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", "4", "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_directionalshading = {CVAR_SAVE, "r_shadow_bouncegrid_directionalshading", "0", "use diffuse shading rather than ambient, 3D texture becomes 4x as many pixels to hold the additional data"};
325 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"};
326 cvar_t r_shadow_bouncegrid_hitmodels = {CVAR_SAVE, "r_shadow_bouncegrid_hitmodels", "0", "enables hitting character model geometry (SLOW)"};
327 cvar_t r_shadow_bouncegrid_intensity = {CVAR_SAVE, "r_shadow_bouncegrid_intensity", "4", "overall brightness of bouncegrid texture"};
328 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)"};
329 cvar_t r_shadow_bouncegrid_maxbounce = {CVAR_SAVE, "r_shadow_bouncegrid_maxbounce", "3", "maximum number of bounces for a particle (minimum is 1)"};
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 qboolean r_shadow_bouncegriddirectional;
358 static double r_shadow_bouncegridtime;
359 static int r_shadow_bouncegridresolution[3];
360 static int r_shadow_bouncegridnumpixels;
361 static unsigned char *r_shadow_bouncegridpixels;
362 static float *r_shadow_bouncegridhighpixels;
364 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
365 #define ATTENTABLESIZE 256
366 // 1D gradient, 2D circle and 3D sphere attenuation textures
367 #define ATTEN1DSIZE 32
368 #define ATTEN2DSIZE 64
369 #define ATTEN3DSIZE 32
371 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
372 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
373 static float r_shadow_attentable[ATTENTABLESIZE+1];
375 rtlight_t *r_shadow_compilingrtlight;
376 static memexpandablearray_t r_shadow_worldlightsarray;
377 dlight_t *r_shadow_selectedlight;
378 dlight_t r_shadow_bufferlight;
379 vec3_t r_editlights_cursorlocation;
380 qboolean r_editlights_lockcursor;
382 extern int con_vislines;
384 void R_Shadow_UncompileWorldLights(void);
385 void R_Shadow_ClearWorldLights(void);
386 void R_Shadow_SaveWorldLights(void);
387 void R_Shadow_LoadWorldLights(void);
388 void R_Shadow_LoadLightsFile(void);
389 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
390 void R_Shadow_EditLights_Reload_f(void);
391 void R_Shadow_ValidateCvars(void);
392 static void R_Shadow_MakeTextures(void);
394 #define EDLIGHTSPRSIZE 8
395 skinframe_t *r_editlights_sprcursor;
396 skinframe_t *r_editlights_sprlight;
397 skinframe_t *r_editlights_sprnoshadowlight;
398 skinframe_t *r_editlights_sprcubemaplight;
399 skinframe_t *r_editlights_sprcubemapnoshadowlight;
400 skinframe_t *r_editlights_sprselection;
402 void R_Shadow_SetShadowMode(void)
404 r_shadow_shadowmapmaxsize = bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4);
405 r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20;
406 r_shadow_shadowmapfilterquality = r_shadow_shadowmapping_filterquality.integer;
407 r_shadow_shadowmapdepthbits = r_shadow_shadowmapping_depthbits.integer;
408 r_shadow_shadowmapborder = bound(0, r_shadow_shadowmapping_bordersize.integer, 16);
409 r_shadow_shadowmaplod = -1;
410 r_shadow_shadowmapsize = 0;
411 r_shadow_shadowmapsampler = false;
412 r_shadow_shadowmappcf = 0;
413 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
414 if ((r_shadow_shadowmapping.integer || r_shadow_deferred.integer) && vid.support.ext_framebuffer_object)
416 switch(vid.renderpath)
418 case RENDERPATH_GL20:
419 if(r_shadow_shadowmapfilterquality < 0)
421 if(vid.support.amd_texture_texture4 || vid.support.arb_texture_gather)
422 r_shadow_shadowmappcf = 1;
423 else if(strstr(gl_vendor, "NVIDIA") || strstr(gl_renderer, "Radeon HD"))
425 r_shadow_shadowmapsampler = vid.support.arb_shadow;
426 r_shadow_shadowmappcf = 1;
428 else if(strstr(gl_vendor, "ATI"))
429 r_shadow_shadowmappcf = 1;
431 r_shadow_shadowmapsampler = vid.support.arb_shadow;
435 switch (r_shadow_shadowmapfilterquality)
438 r_shadow_shadowmapsampler = vid.support.arb_shadow;
441 r_shadow_shadowmapsampler = vid.support.arb_shadow;
442 r_shadow_shadowmappcf = 1;
445 r_shadow_shadowmappcf = 1;
448 r_shadow_shadowmappcf = 2;
452 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
454 case RENDERPATH_D3D9:
455 case RENDERPATH_D3D10:
456 case RENDERPATH_D3D11:
457 case RENDERPATH_SOFT:
458 r_shadow_shadowmapsampler = false;
459 r_shadow_shadowmappcf = 1;
460 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
462 case RENDERPATH_GL13:
464 case RENDERPATH_GL11:
466 case RENDERPATH_GLES2:
472 qboolean R_Shadow_ShadowMappingEnabled(void)
474 switch (r_shadow_shadowmode)
476 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
483 void R_Shadow_FreeShadowMaps(void)
485 R_Shadow_SetShadowMode();
487 R_Mesh_DestroyFramebufferObject(r_shadow_fbo2d);
491 if (r_shadow_shadowmap2dtexture)
492 R_FreeTexture(r_shadow_shadowmap2dtexture);
493 r_shadow_shadowmap2dtexture = NULL;
495 if (r_shadow_shadowmap2dcolortexture)
496 R_FreeTexture(r_shadow_shadowmap2dcolortexture);
497 r_shadow_shadowmap2dcolortexture = NULL;
499 if (r_shadow_shadowmapvsdcttexture)
500 R_FreeTexture(r_shadow_shadowmapvsdcttexture);
501 r_shadow_shadowmapvsdcttexture = NULL;
504 void r_shadow_start(void)
506 // allocate vertex processing arrays
507 r_shadow_bouncegridpixels = NULL;
508 r_shadow_bouncegridhighpixels = NULL;
509 r_shadow_bouncegridnumpixels = 0;
510 r_shadow_bouncegridtexture = NULL;
511 r_shadow_bouncegriddirectional = false;
512 r_shadow_attenuationgradienttexture = NULL;
513 r_shadow_attenuation2dtexture = NULL;
514 r_shadow_attenuation3dtexture = NULL;
515 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
516 r_shadow_shadowmap2dtexture = NULL;
517 r_shadow_shadowmap2dcolortexture = NULL;
518 r_shadow_shadowmapvsdcttexture = NULL;
519 r_shadow_shadowmapmaxsize = 0;
520 r_shadow_shadowmapsize = 0;
521 r_shadow_shadowmaplod = 0;
522 r_shadow_shadowmapfilterquality = -1;
523 r_shadow_shadowmapdepthbits = 0;
524 r_shadow_shadowmapvsdct = false;
525 r_shadow_shadowmapsampler = false;
526 r_shadow_shadowmappcf = 0;
529 R_Shadow_FreeShadowMaps();
531 r_shadow_texturepool = NULL;
532 r_shadow_filters_texturepool = NULL;
533 R_Shadow_ValidateCvars();
534 R_Shadow_MakeTextures();
535 maxshadowtriangles = 0;
536 shadowelements = NULL;
537 maxshadowvertices = 0;
538 shadowvertex3f = NULL;
546 shadowmarklist = NULL;
551 shadowsideslist = NULL;
552 r_shadow_buffer_numleafpvsbytes = 0;
553 r_shadow_buffer_visitingleafpvs = NULL;
554 r_shadow_buffer_leafpvs = NULL;
555 r_shadow_buffer_leaflist = NULL;
556 r_shadow_buffer_numsurfacepvsbytes = 0;
557 r_shadow_buffer_surfacepvs = NULL;
558 r_shadow_buffer_surfacelist = NULL;
559 r_shadow_buffer_surfacesides = NULL;
560 r_shadow_buffer_numshadowtrispvsbytes = 0;
561 r_shadow_buffer_shadowtrispvs = NULL;
562 r_shadow_buffer_numlighttrispvsbytes = 0;
563 r_shadow_buffer_lighttrispvs = NULL;
565 r_shadow_usingdeferredprepass = false;
566 r_shadow_prepass_width = r_shadow_prepass_height = 0;
569 static void R_Shadow_FreeDeferred(void);
570 void r_shadow_shutdown(void)
573 R_Shadow_UncompileWorldLights();
575 R_Shadow_FreeShadowMaps();
577 r_shadow_usingdeferredprepass = false;
578 if (r_shadow_prepass_width)
579 R_Shadow_FreeDeferred();
580 r_shadow_prepass_width = r_shadow_prepass_height = 0;
583 r_shadow_bouncegridtexture = NULL;
584 r_shadow_bouncegridpixels = NULL;
585 r_shadow_bouncegridhighpixels = NULL;
586 r_shadow_bouncegridnumpixels = 0;
587 r_shadow_bouncegriddirectional = false;
588 r_shadow_attenuationgradienttexture = NULL;
589 r_shadow_attenuation2dtexture = NULL;
590 r_shadow_attenuation3dtexture = NULL;
591 R_FreeTexturePool(&r_shadow_texturepool);
592 R_FreeTexturePool(&r_shadow_filters_texturepool);
593 maxshadowtriangles = 0;
595 Mem_Free(shadowelements);
596 shadowelements = NULL;
598 Mem_Free(shadowvertex3f);
599 shadowvertex3f = NULL;
602 Mem_Free(vertexupdate);
605 Mem_Free(vertexremap);
611 Mem_Free(shadowmark);
614 Mem_Free(shadowmarklist);
615 shadowmarklist = NULL;
620 Mem_Free(shadowsides);
623 Mem_Free(shadowsideslist);
624 shadowsideslist = NULL;
625 r_shadow_buffer_numleafpvsbytes = 0;
626 if (r_shadow_buffer_visitingleafpvs)
627 Mem_Free(r_shadow_buffer_visitingleafpvs);
628 r_shadow_buffer_visitingleafpvs = NULL;
629 if (r_shadow_buffer_leafpvs)
630 Mem_Free(r_shadow_buffer_leafpvs);
631 r_shadow_buffer_leafpvs = NULL;
632 if (r_shadow_buffer_leaflist)
633 Mem_Free(r_shadow_buffer_leaflist);
634 r_shadow_buffer_leaflist = NULL;
635 r_shadow_buffer_numsurfacepvsbytes = 0;
636 if (r_shadow_buffer_surfacepvs)
637 Mem_Free(r_shadow_buffer_surfacepvs);
638 r_shadow_buffer_surfacepvs = NULL;
639 if (r_shadow_buffer_surfacelist)
640 Mem_Free(r_shadow_buffer_surfacelist);
641 r_shadow_buffer_surfacelist = NULL;
642 if (r_shadow_buffer_surfacesides)
643 Mem_Free(r_shadow_buffer_surfacesides);
644 r_shadow_buffer_surfacesides = NULL;
645 r_shadow_buffer_numshadowtrispvsbytes = 0;
646 if (r_shadow_buffer_shadowtrispvs)
647 Mem_Free(r_shadow_buffer_shadowtrispvs);
648 r_shadow_buffer_numlighttrispvsbytes = 0;
649 if (r_shadow_buffer_lighttrispvs)
650 Mem_Free(r_shadow_buffer_lighttrispvs);
653 void r_shadow_newmap(void)
655 if (r_shadow_bouncegridtexture) R_FreeTexture(r_shadow_bouncegridtexture);r_shadow_bouncegridtexture = NULL;
656 if (r_shadow_lightcorona) R_SkinFrame_MarkUsed(r_shadow_lightcorona);
657 if (r_editlights_sprcursor) R_SkinFrame_MarkUsed(r_editlights_sprcursor);
658 if (r_editlights_sprlight) R_SkinFrame_MarkUsed(r_editlights_sprlight);
659 if (r_editlights_sprnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprnoshadowlight);
660 if (r_editlights_sprcubemaplight) R_SkinFrame_MarkUsed(r_editlights_sprcubemaplight);
661 if (r_editlights_sprcubemapnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprcubemapnoshadowlight);
662 if (r_editlights_sprselection) R_SkinFrame_MarkUsed(r_editlights_sprselection);
663 if (strncmp(cl.worldname, r_shadow_mapname, sizeof(r_shadow_mapname)))
664 R_Shadow_EditLights_Reload_f();
667 void R_Shadow_Init(void)
669 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
670 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
671 Cvar_RegisterVariable(&r_shadow_usebihculling);
672 Cvar_RegisterVariable(&r_shadow_usenormalmap);
673 Cvar_RegisterVariable(&r_shadow_debuglight);
674 Cvar_RegisterVariable(&r_shadow_deferred);
675 Cvar_RegisterVariable(&r_shadow_deferred_8bitrange);
676 // Cvar_RegisterVariable(&r_shadow_deferred_fp);
677 Cvar_RegisterVariable(&r_shadow_gloss);
678 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
679 Cvar_RegisterVariable(&r_shadow_glossintensity);
680 Cvar_RegisterVariable(&r_shadow_glossexponent);
681 Cvar_RegisterVariable(&r_shadow_gloss2exponent);
682 Cvar_RegisterVariable(&r_shadow_glossexact);
683 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
684 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
685 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
686 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
687 Cvar_RegisterVariable(&r_shadow_projectdistance);
688 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
689 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
690 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
691 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
692 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
693 Cvar_RegisterVariable(&r_shadow_realtime_world);
694 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
695 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
696 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
697 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
698 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
699 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
700 Cvar_RegisterVariable(&r_shadow_scissor);
701 Cvar_RegisterVariable(&r_shadow_shadowmapping);
702 Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
703 Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
704 Cvar_RegisterVariable(&r_shadow_shadowmapping_depthbits);
705 Cvar_RegisterVariable(&r_shadow_shadowmapping_precision);
706 Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
707 Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
708 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
709 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
710 Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
711 Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
712 Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
713 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonfactor);
714 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonoffset);
715 Cvar_RegisterVariable(&r_shadow_sortsurfaces);
716 Cvar_RegisterVariable(&r_shadow_polygonfactor);
717 Cvar_RegisterVariable(&r_shadow_polygonoffset);
718 Cvar_RegisterVariable(&r_shadow_texture3d);
719 Cvar_RegisterVariable(&r_shadow_bouncegrid);
720 Cvar_RegisterVariable(&r_shadow_bouncegrid_bounceanglediffuse);
721 Cvar_RegisterVariable(&r_shadow_bouncegrid_directionalshading);
722 Cvar_RegisterVariable(&r_shadow_bouncegrid_dlightparticlemultiplier);
723 Cvar_RegisterVariable(&r_shadow_bouncegrid_hitmodels);
724 Cvar_RegisterVariable(&r_shadow_bouncegrid_intensity);
725 Cvar_RegisterVariable(&r_shadow_bouncegrid_lightradiusscale);
726 Cvar_RegisterVariable(&r_shadow_bouncegrid_maxbounce);
727 Cvar_RegisterVariable(&r_shadow_bouncegrid_particlebounceintensity);
728 Cvar_RegisterVariable(&r_shadow_bouncegrid_particleintensity);
729 Cvar_RegisterVariable(&r_shadow_bouncegrid_photons);
730 Cvar_RegisterVariable(&r_shadow_bouncegrid_spacingx);
731 Cvar_RegisterVariable(&r_shadow_bouncegrid_spacingy);
732 Cvar_RegisterVariable(&r_shadow_bouncegrid_spacingz);
733 Cvar_RegisterVariable(&r_shadow_bouncegrid_stablerandom);
734 Cvar_RegisterVariable(&r_shadow_bouncegrid_updateinterval);
735 Cvar_RegisterVariable(&r_shadow_bouncegrid_x);
736 Cvar_RegisterVariable(&r_shadow_bouncegrid_y);
737 Cvar_RegisterVariable(&r_shadow_bouncegrid_z);
738 Cvar_RegisterVariable(&r_coronas);
739 Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
740 Cvar_RegisterVariable(&r_coronas_occlusionquery);
741 Cvar_RegisterVariable(&gl_flashblend);
742 Cvar_RegisterVariable(&gl_ext_separatestencil);
743 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
744 R_Shadow_EditLights_Init();
745 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
746 maxshadowtriangles = 0;
747 shadowelements = NULL;
748 maxshadowvertices = 0;
749 shadowvertex3f = NULL;
757 shadowmarklist = NULL;
762 shadowsideslist = NULL;
763 r_shadow_buffer_numleafpvsbytes = 0;
764 r_shadow_buffer_visitingleafpvs = NULL;
765 r_shadow_buffer_leafpvs = NULL;
766 r_shadow_buffer_leaflist = NULL;
767 r_shadow_buffer_numsurfacepvsbytes = 0;
768 r_shadow_buffer_surfacepvs = NULL;
769 r_shadow_buffer_surfacelist = NULL;
770 r_shadow_buffer_surfacesides = NULL;
771 r_shadow_buffer_shadowtrispvs = NULL;
772 r_shadow_buffer_lighttrispvs = NULL;
773 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap, NULL, NULL);
776 matrix4x4_t matrix_attenuationxyz =
779 {0.5, 0.0, 0.0, 0.5},
780 {0.0, 0.5, 0.0, 0.5},
781 {0.0, 0.0, 0.5, 0.5},
786 matrix4x4_t matrix_attenuationz =
789 {0.0, 0.0, 0.5, 0.5},
790 {0.0, 0.0, 0.0, 0.5},
791 {0.0, 0.0, 0.0, 0.5},
796 void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles, int vertscale, int triscale)
798 numvertices = ((numvertices + 255) & ~255) * vertscale;
799 numtriangles = ((numtriangles + 255) & ~255) * triscale;
800 // make sure shadowelements is big enough for this volume
801 if (maxshadowtriangles < numtriangles)
803 maxshadowtriangles = numtriangles;
805 Mem_Free(shadowelements);
806 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[3]));
808 // make sure shadowvertex3f is big enough for this volume
809 if (maxshadowvertices < numvertices)
811 maxshadowvertices = numvertices;
813 Mem_Free(shadowvertex3f);
814 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[3]));
818 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
820 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
821 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
822 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
823 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
824 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
826 if (r_shadow_buffer_visitingleafpvs)
827 Mem_Free(r_shadow_buffer_visitingleafpvs);
828 if (r_shadow_buffer_leafpvs)
829 Mem_Free(r_shadow_buffer_leafpvs);
830 if (r_shadow_buffer_leaflist)
831 Mem_Free(r_shadow_buffer_leaflist);
832 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
833 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
834 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
835 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
837 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
839 if (r_shadow_buffer_surfacepvs)
840 Mem_Free(r_shadow_buffer_surfacepvs);
841 if (r_shadow_buffer_surfacelist)
842 Mem_Free(r_shadow_buffer_surfacelist);
843 if (r_shadow_buffer_surfacesides)
844 Mem_Free(r_shadow_buffer_surfacesides);
845 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
846 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
847 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
848 r_shadow_buffer_surfacesides = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
850 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
852 if (r_shadow_buffer_shadowtrispvs)
853 Mem_Free(r_shadow_buffer_shadowtrispvs);
854 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
855 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
857 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
859 if (r_shadow_buffer_lighttrispvs)
860 Mem_Free(r_shadow_buffer_lighttrispvs);
861 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
862 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
866 void R_Shadow_PrepareShadowMark(int numtris)
868 // make sure shadowmark is big enough for this volume
869 if (maxshadowmark < numtris)
871 maxshadowmark = numtris;
873 Mem_Free(shadowmark);
875 Mem_Free(shadowmarklist);
876 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
877 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
881 // if shadowmarkcount wrapped we clear the array and adjust accordingly
882 if (shadowmarkcount == 0)
885 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
890 void R_Shadow_PrepareShadowSides(int numtris)
892 if (maxshadowsides < numtris)
894 maxshadowsides = numtris;
896 Mem_Free(shadowsides);
898 Mem_Free(shadowsideslist);
899 shadowsides = (unsigned char *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsides));
900 shadowsideslist = (int *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsideslist));
905 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)
908 int outtriangles = 0, outvertices = 0;
911 float ratio, direction[3], projectvector[3];
913 if (projectdirection)
914 VectorScale(projectdirection, projectdistance, projectvector);
916 VectorClear(projectvector);
918 // create the vertices
919 if (projectdirection)
921 for (i = 0;i < numshadowmarktris;i++)
923 element = inelement3i + shadowmarktris[i] * 3;
924 for (j = 0;j < 3;j++)
926 if (vertexupdate[element[j]] != vertexupdatenum)
928 vertexupdate[element[j]] = vertexupdatenum;
929 vertexremap[element[j]] = outvertices;
930 vertex = invertex3f + element[j] * 3;
931 // project one copy of the vertex according to projectvector
932 VectorCopy(vertex, outvertex3f);
933 VectorAdd(vertex, projectvector, (outvertex3f + 3));
942 for (i = 0;i < numshadowmarktris;i++)
944 element = inelement3i + shadowmarktris[i] * 3;
945 for (j = 0;j < 3;j++)
947 if (vertexupdate[element[j]] != vertexupdatenum)
949 vertexupdate[element[j]] = vertexupdatenum;
950 vertexremap[element[j]] = outvertices;
951 vertex = invertex3f + element[j] * 3;
952 // project one copy of the vertex to the sphere radius of the light
953 // (FIXME: would projecting it to the light box be better?)
954 VectorSubtract(vertex, projectorigin, direction);
955 ratio = projectdistance / VectorLength(direction);
956 VectorCopy(vertex, outvertex3f);
957 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
965 if (r_shadow_frontsidecasting.integer)
967 for (i = 0;i < numshadowmarktris;i++)
969 int remappedelement[3];
971 const int *neighbortriangle;
973 markindex = shadowmarktris[i] * 3;
974 element = inelement3i + markindex;
975 neighbortriangle = inneighbor3i + markindex;
976 // output the front and back triangles
977 outelement3i[0] = vertexremap[element[0]];
978 outelement3i[1] = vertexremap[element[1]];
979 outelement3i[2] = vertexremap[element[2]];
980 outelement3i[3] = vertexremap[element[2]] + 1;
981 outelement3i[4] = vertexremap[element[1]] + 1;
982 outelement3i[5] = vertexremap[element[0]] + 1;
986 // output the sides (facing outward from this triangle)
987 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
989 remappedelement[0] = vertexremap[element[0]];
990 remappedelement[1] = vertexremap[element[1]];
991 outelement3i[0] = remappedelement[1];
992 outelement3i[1] = remappedelement[0];
993 outelement3i[2] = remappedelement[0] + 1;
994 outelement3i[3] = remappedelement[1];
995 outelement3i[4] = remappedelement[0] + 1;
996 outelement3i[5] = remappedelement[1] + 1;
1001 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1003 remappedelement[1] = vertexremap[element[1]];
1004 remappedelement[2] = vertexremap[element[2]];
1005 outelement3i[0] = remappedelement[2];
1006 outelement3i[1] = remappedelement[1];
1007 outelement3i[2] = remappedelement[1] + 1;
1008 outelement3i[3] = remappedelement[2];
1009 outelement3i[4] = remappedelement[1] + 1;
1010 outelement3i[5] = remappedelement[2] + 1;
1015 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1017 remappedelement[0] = vertexremap[element[0]];
1018 remappedelement[2] = vertexremap[element[2]];
1019 outelement3i[0] = remappedelement[0];
1020 outelement3i[1] = remappedelement[2];
1021 outelement3i[2] = remappedelement[2] + 1;
1022 outelement3i[3] = remappedelement[0];
1023 outelement3i[4] = remappedelement[2] + 1;
1024 outelement3i[5] = remappedelement[0] + 1;
1033 for (i = 0;i < numshadowmarktris;i++)
1035 int remappedelement[3];
1037 const int *neighbortriangle;
1039 markindex = shadowmarktris[i] * 3;
1040 element = inelement3i + markindex;
1041 neighbortriangle = inneighbor3i + markindex;
1042 // output the front and back triangles
1043 outelement3i[0] = vertexremap[element[2]];
1044 outelement3i[1] = vertexremap[element[1]];
1045 outelement3i[2] = vertexremap[element[0]];
1046 outelement3i[3] = vertexremap[element[0]] + 1;
1047 outelement3i[4] = vertexremap[element[1]] + 1;
1048 outelement3i[5] = vertexremap[element[2]] + 1;
1052 // output the sides (facing outward from this triangle)
1053 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
1055 remappedelement[0] = vertexremap[element[0]];
1056 remappedelement[1] = vertexremap[element[1]];
1057 outelement3i[0] = remappedelement[0];
1058 outelement3i[1] = remappedelement[1];
1059 outelement3i[2] = remappedelement[1] + 1;
1060 outelement3i[3] = remappedelement[0];
1061 outelement3i[4] = remappedelement[1] + 1;
1062 outelement3i[5] = remappedelement[0] + 1;
1067 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1069 remappedelement[1] = vertexremap[element[1]];
1070 remappedelement[2] = vertexremap[element[2]];
1071 outelement3i[0] = remappedelement[1];
1072 outelement3i[1] = remappedelement[2];
1073 outelement3i[2] = remappedelement[2] + 1;
1074 outelement3i[3] = remappedelement[1];
1075 outelement3i[4] = remappedelement[2] + 1;
1076 outelement3i[5] = remappedelement[1] + 1;
1081 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1083 remappedelement[0] = vertexremap[element[0]];
1084 remappedelement[2] = vertexremap[element[2]];
1085 outelement3i[0] = remappedelement[2];
1086 outelement3i[1] = remappedelement[0];
1087 outelement3i[2] = remappedelement[0] + 1;
1088 outelement3i[3] = remappedelement[2];
1089 outelement3i[4] = remappedelement[0] + 1;
1090 outelement3i[5] = remappedelement[2] + 1;
1098 *outnumvertices = outvertices;
1099 return outtriangles;
1102 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)
1105 int outtriangles = 0, outvertices = 0;
1107 const float *vertex;
1108 float ratio, direction[3], projectvector[3];
1111 if (projectdirection)
1112 VectorScale(projectdirection, projectdistance, projectvector);
1114 VectorClear(projectvector);
1116 for (i = 0;i < numshadowmarktris;i++)
1118 int remappedelement[3];
1120 const int *neighbortriangle;
1122 markindex = shadowmarktris[i] * 3;
1123 neighbortriangle = inneighbor3i + markindex;
1124 side[0] = shadowmark[neighbortriangle[0]] == shadowmarkcount;
1125 side[1] = shadowmark[neighbortriangle[1]] == shadowmarkcount;
1126 side[2] = shadowmark[neighbortriangle[2]] == shadowmarkcount;
1127 if (side[0] + side[1] + side[2] == 0)
1131 element = inelement3i + markindex;
1133 // create the vertices
1134 for (j = 0;j < 3;j++)
1136 if (side[j] + side[j+1] == 0)
1139 if (vertexupdate[k] != vertexupdatenum)
1141 vertexupdate[k] = vertexupdatenum;
1142 vertexremap[k] = outvertices;
1143 vertex = invertex3f + k * 3;
1144 VectorCopy(vertex, outvertex3f);
1145 if (projectdirection)
1147 // project one copy of the vertex according to projectvector
1148 VectorAdd(vertex, projectvector, (outvertex3f + 3));
1152 // project one copy of the vertex to the sphere radius of the light
1153 // (FIXME: would projecting it to the light box be better?)
1154 VectorSubtract(vertex, projectorigin, direction);
1155 ratio = projectdistance / VectorLength(direction);
1156 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1163 // output the sides (facing outward from this triangle)
1166 remappedelement[0] = vertexremap[element[0]];
1167 remappedelement[1] = vertexremap[element[1]];
1168 outelement3i[0] = remappedelement[1];
1169 outelement3i[1] = remappedelement[0];
1170 outelement3i[2] = remappedelement[0] + 1;
1171 outelement3i[3] = remappedelement[1];
1172 outelement3i[4] = remappedelement[0] + 1;
1173 outelement3i[5] = remappedelement[1] + 1;
1180 remappedelement[1] = vertexremap[element[1]];
1181 remappedelement[2] = vertexremap[element[2]];
1182 outelement3i[0] = remappedelement[2];
1183 outelement3i[1] = remappedelement[1];
1184 outelement3i[2] = remappedelement[1] + 1;
1185 outelement3i[3] = remappedelement[2];
1186 outelement3i[4] = remappedelement[1] + 1;
1187 outelement3i[5] = remappedelement[2] + 1;
1194 remappedelement[0] = vertexremap[element[0]];
1195 remappedelement[2] = vertexremap[element[2]];
1196 outelement3i[0] = remappedelement[0];
1197 outelement3i[1] = remappedelement[2];
1198 outelement3i[2] = remappedelement[2] + 1;
1199 outelement3i[3] = remappedelement[0];
1200 outelement3i[4] = remappedelement[2] + 1;
1201 outelement3i[5] = remappedelement[0] + 1;
1208 *outnumvertices = outvertices;
1209 return outtriangles;
1212 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)
1218 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1220 tend = firsttriangle + numtris;
1221 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1223 // surface box entirely inside light box, no box cull
1224 if (projectdirection)
1226 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1228 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
1229 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1230 shadowmarklist[numshadowmark++] = t;
1235 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1236 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
1237 shadowmarklist[numshadowmark++] = t;
1242 // surface box not entirely inside light box, cull each triangle
1243 if (projectdirection)
1245 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1247 v[0] = invertex3f + e[0] * 3;
1248 v[1] = invertex3f + e[1] * 3;
1249 v[2] = invertex3f + e[2] * 3;
1250 TriangleNormal(v[0], v[1], v[2], normal);
1251 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1252 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1253 shadowmarklist[numshadowmark++] = t;
1258 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1260 v[0] = invertex3f + e[0] * 3;
1261 v[1] = invertex3f + e[1] * 3;
1262 v[2] = invertex3f + e[2] * 3;
1263 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1264 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1265 shadowmarklist[numshadowmark++] = t;
1271 qboolean R_Shadow_UseZPass(vec3_t mins, vec3_t maxs)
1276 if (r_shadow_compilingrtlight || !r_shadow_frontsidecasting.integer || !r_shadow_usezpassifpossible.integer)
1278 // check if the shadow volume intersects the near plane
1280 // a ray between the eye and light origin may intersect the caster,
1281 // indicating that the shadow may touch the eye location, however we must
1282 // test the near plane (a polygon), not merely the eye location, so it is
1283 // easiest to enlarge the caster bounding shape slightly for this.
1289 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)
1291 int i, tris, outverts;
1292 if (projectdistance < 0.1)
1294 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
1297 if (!numverts || !nummarktris)
1299 // make sure shadowelements is big enough for this volume
1300 if (maxshadowtriangles < nummarktris*8 || maxshadowvertices < numverts*2)
1301 R_Shadow_ResizeShadowArrays(numverts, nummarktris, 2, 8);
1303 if (maxvertexupdate < numverts)
1305 maxvertexupdate = numverts;
1307 Mem_Free(vertexupdate);
1309 Mem_Free(vertexremap);
1310 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1311 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1312 vertexupdatenum = 0;
1315 if (vertexupdatenum == 0)
1317 vertexupdatenum = 1;
1318 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
1319 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
1322 for (i = 0;i < nummarktris;i++)
1323 shadowmark[marktris[i]] = shadowmarkcount;
1325 if (r_shadow_compilingrtlight)
1327 // if we're compiling an rtlight, capture the mesh
1328 //tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1329 //Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zpass, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1330 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1331 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zfail, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1333 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
1335 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1336 R_Mesh_PrepareVertices_Vertex3f(outverts, shadowvertex3f, NULL);
1337 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1341 // decide which type of shadow to generate and set stencil mode
1342 R_Shadow_RenderMode_StencilShadowVolumes(R_Shadow_UseZPass(trismins, trismaxs));
1343 // generate the sides or a solid volume, depending on type
1344 if (r_shadow_rendermode >= R_SHADOW_RENDERMODE_ZPASS_STENCIL && r_shadow_rendermode <= R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE)
1345 tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1347 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1348 r_refdef.stats.lights_dynamicshadowtriangles += tris;
1349 r_refdef.stats.lights_shadowtriangles += tris;
1350 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
1352 // increment stencil if frontface is infront of depthbuffer
1353 GL_CullFace(r_refdef.view.cullface_front);
1354 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
1355 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1356 // decrement stencil if backface is infront of depthbuffer
1357 GL_CullFace(r_refdef.view.cullface_back);
1358 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
1360 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
1362 // decrement stencil if backface is behind depthbuffer
1363 GL_CullFace(r_refdef.view.cullface_front);
1364 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
1365 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1366 // increment stencil if frontface is behind depthbuffer
1367 GL_CullFace(r_refdef.view.cullface_back);
1368 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
1370 R_Mesh_PrepareVertices_Vertex3f(outverts, shadowvertex3f, NULL);
1371 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1375 int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias)
1377 // p1, p2, p3 are in the cubemap's local coordinate system
1378 // bias = border/(size - border)
1381 float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1382 dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2),
1383 dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3);
1384 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1386 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1387 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1388 | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1389 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1391 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1392 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1393 | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1395 dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1396 dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2),
1397 dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3);
1398 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1400 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1401 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1402 | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1403 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1405 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1406 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1407 | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1409 dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1410 dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2),
1411 dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3);
1412 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1414 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1415 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1416 | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1417 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1419 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1420 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1421 | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1426 int R_Shadow_CalcBBoxSideMask(const vec3_t mins, const vec3_t maxs, const matrix4x4_t *worldtolight, const matrix4x4_t *radiustolight, float bias)
1428 vec3_t center, radius, lightcenter, lightradius, pmin, pmax;
1429 float dp1, dn1, ap1, an1, dp2, dn2, ap2, an2;
1432 VectorSubtract(maxs, mins, radius);
1433 VectorScale(radius, 0.5f, radius);
1434 VectorAdd(mins, radius, center);
1435 Matrix4x4_Transform(worldtolight, center, lightcenter);
1436 Matrix4x4_Transform3x3(radiustolight, radius, lightradius);
1437 VectorSubtract(lightcenter, lightradius, pmin);
1438 VectorAdd(lightcenter, lightradius, pmax);
1440 dp1 = pmax[0] + pmax[1], dn1 = pmax[0] - pmin[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1441 dp2 = pmin[0] + pmin[1], dn2 = pmin[0] - pmax[1], ap2 = fabs(dp2), an2 = fabs(dn2);
1442 if(ap1 > bias*an1 && ap2 > bias*an2)
1444 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1445 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1446 if(an1 > bias*ap1 && an2 > bias*ap2)
1448 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1449 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1451 dp1 = pmax[1] + pmax[2], dn1 = pmax[1] - pmin[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1452 dp2 = pmin[1] + pmin[2], dn2 = pmin[1] - pmax[2], ap2 = fabs(dp2), an2 = fabs(dn2);
1453 if(ap1 > bias*an1 && ap2 > bias*an2)
1455 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1456 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1457 if(an1 > bias*ap1 && an2 > bias*ap2)
1459 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1460 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1462 dp1 = pmax[2] + pmax[0], dn1 = pmax[2] - pmin[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1463 dp2 = pmin[2] + pmin[0], dn2 = pmin[2] - pmax[0], ap2 = fabs(dp2), an2 = fabs(dn2);
1464 if(ap1 > bias*an1 && ap2 > bias*an2)
1466 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1467 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1468 if(an1 > bias*ap1 && an2 > bias*ap2)
1470 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1471 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1476 #define R_Shadow_CalcEntitySideMask(ent, worldtolight, radiustolight, bias) R_Shadow_CalcBBoxSideMask((ent)->mins, (ent)->maxs, worldtolight, radiustolight, bias)
1478 int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
1480 // p is in the cubemap's local coordinate system
1481 // bias = border/(size - border)
1482 float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn);
1483 float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn);
1484 float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn);
1486 if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
1487 if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
1488 if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
1489 if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
1490 if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
1491 if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
1495 int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
1499 int sides = 0x3F, masks[6] = { 3<<4, 3<<4, 3<<0, 3<<0, 3<<2, 3<<2 };
1500 float scale = (size - 2*border)/size, len;
1501 float bias = border / (float)(size - border), dp, dn, ap, an;
1502 // check if cone enclosing side would cross frustum plane
1503 scale = 2 / (scale*scale + 2);
1504 for (i = 0;i < 5;i++)
1506 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) > -0.03125)
1508 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[i].normal, n);
1509 len = scale*VectorLength2(n);
1510 if(n[0]*n[0] > len) sides &= n[0] < 0 ? ~(1<<0) : ~(2 << 0);
1511 if(n[1]*n[1] > len) sides &= n[1] < 0 ? ~(1<<2) : ~(2 << 2);
1512 if(n[2]*n[2] > len) sides &= n[2] < 0 ? ~(1<<4) : ~(2 << 4);
1514 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[4]) >= r_refdef.farclip - r_refdef.nearclip + 0.03125)
1516 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[4].normal, n);
1517 len = scale*VectorLength(n);
1518 if(n[0]*n[0] > len) sides &= n[0] >= 0 ? ~(1<<0) : ~(2 << 0);
1519 if(n[1]*n[1] > len) sides &= n[1] >= 0 ? ~(1<<2) : ~(2 << 2);
1520 if(n[2]*n[2] > len) sides &= n[2] >= 0 ? ~(1<<4) : ~(2 << 4);
1522 // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results
1523 // check if frustum corners/origin cross plane sides
1525 // infinite version, assumes frustum corners merely give direction and extend to infinite distance
1526 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.origin, p);
1527 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1528 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1529 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1530 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1531 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1532 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1533 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1534 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1535 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1536 for (i = 0;i < 4;i++)
1538 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.frustumcorner[i], n);
1539 VectorSubtract(n, p, n);
1540 dp = n[0] + n[1], dn = n[0] - n[1], ap = fabs(dp), an = fabs(dn);
1541 if(ap > 0) masks[0] |= dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2);
1542 if(an > 0) masks[1] |= dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2);
1543 dp = n[1] + n[2], dn = n[1] - n[2], ap = fabs(dp), an = fabs(dn);
1544 if(ap > 0) masks[2] |= dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4);
1545 if(an > 0) masks[3] |= dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4);
1546 dp = n[2] + n[0], dn = n[2] - n[0], ap = fabs(dp), an = fabs(dn);
1547 if(ap > 0) masks[4] |= dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0);
1548 if(an > 0) masks[5] |= dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0);
1551 // finite version, assumes corners are a finite distance from origin dependent on far plane
1552 for (i = 0;i < 5;i++)
1554 Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p);
1555 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1556 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1557 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1558 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1559 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1560 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1561 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1562 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1563 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1566 return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5];
1569 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)
1577 int mask, surfacemask = 0;
1578 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1580 bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
1581 tend = firsttriangle + numtris;
1582 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1584 // surface box entirely inside light box, no box cull
1585 if (projectdirection)
1587 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1589 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1590 TriangleNormal(v[0], v[1], v[2], normal);
1591 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1593 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1594 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1595 surfacemask |= mask;
1598 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;
1599 shadowsides[numshadowsides] = mask;
1600 shadowsideslist[numshadowsides++] = t;
1607 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1609 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1610 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]))
1612 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1613 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1614 surfacemask |= mask;
1617 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;
1618 shadowsides[numshadowsides] = mask;
1619 shadowsideslist[numshadowsides++] = t;
1627 // surface box not entirely inside light box, cull each triangle
1628 if (projectdirection)
1630 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1632 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1633 TriangleNormal(v[0], v[1], v[2], normal);
1634 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1635 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1637 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1638 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1639 surfacemask |= mask;
1642 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;
1643 shadowsides[numshadowsides] = mask;
1644 shadowsideslist[numshadowsides++] = t;
1651 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1653 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1654 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1655 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1657 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1658 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1659 surfacemask |= mask;
1662 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;
1663 shadowsides[numshadowsides] = mask;
1664 shadowsideslist[numshadowsides++] = t;
1673 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)
1675 int i, j, outtriangles = 0;
1676 int *outelement3i[6];
1677 if (!numverts || !numsidetris || !r_shadow_compilingrtlight)
1679 outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5];
1680 // make sure shadowelements is big enough for this mesh
1681 if (maxshadowtriangles < outtriangles)
1682 R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1);
1684 // compute the offset and size of the separate index lists for each cubemap side
1686 for (i = 0;i < 6;i++)
1688 outelement3i[i] = shadowelements + outtriangles * 3;
1689 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles;
1690 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i];
1691 outtriangles += sidetotals[i];
1694 // gather up the (sparse) triangles into separate index lists for each cubemap side
1695 for (i = 0;i < numsidetris;i++)
1697 const int *element = elements + sidetris[i] * 3;
1698 for (j = 0;j < 6;j++)
1700 if (sides[i] & (1 << j))
1702 outelement3i[j][0] = element[0];
1703 outelement3i[j][1] = element[1];
1704 outelement3i[j][2] = element[2];
1705 outelement3i[j] += 3;
1710 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, outtriangles, shadowelements);
1713 static void R_Shadow_MakeTextures_MakeCorona(void)
1717 unsigned char pixels[32][32][4];
1718 for (y = 0;y < 32;y++)
1720 dy = (y - 15.5f) * (1.0f / 16.0f);
1721 for (x = 0;x < 32;x++)
1723 dx = (x - 15.5f) * (1.0f / 16.0f);
1724 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1725 a = bound(0, a, 255);
1726 pixels[y][x][0] = a;
1727 pixels[y][x][1] = a;
1728 pixels[y][x][2] = a;
1729 pixels[y][x][3] = 255;
1732 r_shadow_lightcorona = R_SkinFrame_LoadInternalBGRA("lightcorona", TEXF_FORCELINEAR, &pixels[0][0][0], 32, 32);
1735 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1737 float dist = sqrt(x*x+y*y+z*z);
1738 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1739 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1740 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1743 static void R_Shadow_MakeTextures(void)
1746 float intensity, dist;
1748 R_Shadow_FreeShadowMaps();
1749 R_FreeTexturePool(&r_shadow_texturepool);
1750 r_shadow_texturepool = R_AllocTexturePool();
1751 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1752 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1753 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1754 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1755 for (x = 0;x <= ATTENTABLESIZE;x++)
1757 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1758 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1759 r_shadow_attentable[x] = bound(0, intensity, 1);
1761 // 1D gradient texture
1762 for (x = 0;x < ATTEN1DSIZE;x++)
1763 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1764 r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1765 // 2D circle texture
1766 for (y = 0;y < ATTEN2DSIZE;y++)
1767 for (x = 0;x < ATTEN2DSIZE;x++)
1768 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);
1769 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1770 // 3D sphere texture
1771 if (r_shadow_texture3d.integer && vid.support.ext_texture_3d)
1773 for (z = 0;z < ATTEN3DSIZE;z++)
1774 for (y = 0;y < ATTEN3DSIZE;y++)
1775 for (x = 0;x < ATTEN3DSIZE;x++)
1776 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));
1777 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);
1780 r_shadow_attenuation3dtexture = NULL;
1783 R_Shadow_MakeTextures_MakeCorona();
1785 // Editor light sprites
1786 r_editlights_sprcursor = R_SkinFrame_LoadInternal8bit("gfx/editlights/cursor", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1803 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1804 r_editlights_sprlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/light", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1821 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1822 r_editlights_sprnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/noshadow", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1839 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1840 r_editlights_sprcubemaplight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemaplight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1857 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1858 r_editlights_sprcubemapnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemapnoshadowlight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1875 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1876 r_editlights_sprselection = R_SkinFrame_LoadInternal8bit("gfx/editlights/selection", TEXF_ALPHA | TEXF_CLAMP, (unsigned char *)
1893 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1896 void R_Shadow_ValidateCvars(void)
1898 if (r_shadow_texture3d.integer && !vid.support.ext_texture_3d)
1899 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1900 if (gl_ext_separatestencil.integer && !vid.support.ati_separate_stencil)
1901 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
1902 if (gl_ext_stenciltwoside.integer && !vid.support.ext_stencil_two_side)
1903 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1906 void R_Shadow_RenderMode_Begin(void)
1912 R_Shadow_ValidateCvars();
1914 if (!r_shadow_attenuation2dtexture
1915 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1916 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1917 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1918 R_Shadow_MakeTextures();
1921 R_Mesh_ResetTextureState();
1922 GL_BlendFunc(GL_ONE, GL_ZERO);
1923 GL_DepthRange(0, 1);
1924 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1926 GL_DepthMask(false);
1927 GL_Color(0, 0, 0, 1);
1928 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1930 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1932 if (gl_ext_separatestencil.integer && vid.support.ati_separate_stencil)
1934 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
1935 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
1937 else if (gl_ext_stenciltwoside.integer && vid.support.ext_stencil_two_side)
1939 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
1940 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
1944 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
1945 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
1948 switch(vid.renderpath)
1950 case RENDERPATH_GL20:
1951 case RENDERPATH_D3D9:
1952 case RENDERPATH_D3D10:
1953 case RENDERPATH_D3D11:
1954 case RENDERPATH_SOFT:
1955 case RENDERPATH_GLES2:
1956 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1958 case RENDERPATH_GL13:
1959 case RENDERPATH_GL11:
1960 if (r_textureunits.integer >= 2 && vid.texunits >= 2 && r_shadow_texture3d.integer && r_shadow_attenuation3dtexture)
1961 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN;
1962 else if (r_textureunits.integer >= 3 && vid.texunits >= 3)
1963 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN;
1964 else if (r_textureunits.integer >= 2 && vid.texunits >= 2)
1965 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN;
1967 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1973 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
1974 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
1975 r_shadow_drawbuffer = drawbuffer;
1976 r_shadow_readbuffer = readbuffer;
1978 r_shadow_cullface_front = r_refdef.view.cullface_front;
1979 r_shadow_cullface_back = r_refdef.view.cullface_back;
1982 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
1984 rsurface.rtlight = rtlight;
1987 void R_Shadow_RenderMode_Reset(void)
1989 R_Mesh_ResetRenderTargets();
1990 R_SetViewport(&r_refdef.view.viewport);
1991 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
1992 R_Mesh_ResetTextureState();
1993 GL_DepthRange(0, 1);
1995 GL_DepthMask(false);
1996 GL_DepthFunc(GL_LEQUAL);
1997 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1998 r_refdef.view.cullface_front = r_shadow_cullface_front;
1999 r_refdef.view.cullface_back = r_shadow_cullface_back;
2000 GL_CullFace(r_refdef.view.cullface_back);
2001 GL_Color(1, 1, 1, 1);
2002 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
2003 GL_BlendFunc(GL_ONE, GL_ZERO);
2004 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
2005 r_shadow_usingshadowmap2d = false;
2006 r_shadow_usingshadowmaportho = false;
2007 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
2010 void R_Shadow_ClearStencil(void)
2012 GL_Clear(GL_STENCIL_BUFFER_BIT, NULL, 1.0f, 128);
2013 r_refdef.stats.lights_clears++;
2016 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
2018 r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
2019 if (r_shadow_rendermode == mode)
2021 R_Shadow_RenderMode_Reset();
2022 GL_DepthFunc(GL_LESS);
2023 GL_ColorMask(0, 0, 0, 0);
2024 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2025 GL_CullFace(GL_NONE);
2026 R_SetupShader_DepthOrShadow();
2027 r_shadow_rendermode = mode;
2032 case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
2033 case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
2034 R_SetStencilSeparate(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, GL_ALWAYS, 128, 255);
2036 case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
2037 case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
2038 R_SetStencilSeparate(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, GL_ALWAYS, 128, 255);
2043 static void R_Shadow_MakeVSDCT(void)
2045 // maps to a 2x3 texture rectangle with normalized coordinates
2050 // stores abs(dir.xy), offset.xy/2.5
2051 unsigned char data[4*6] =
2053 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
2054 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
2055 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
2056 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
2057 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
2058 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
2060 r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
2063 static void R_Shadow_MakeShadowMap(int side, int size)
2065 switch (r_shadow_shadowmode)
2067 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2068 if (r_shadow_shadowmap2dtexture) return;
2069 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);
2070 r_shadow_shadowmap2dcolortexture = NULL;
2071 switch(vid.renderpath)
2074 case RENDERPATH_D3D9:
2075 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);
2076 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
2080 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2dtexture, NULL, NULL, NULL, NULL);
2088 // render depth into the fbo, do not render color at all
2089 // validate the fbo now
2093 qglDrawBuffer(GL_NONE);CHECKGLERROR
2094 qglReadBuffer(GL_NONE);CHECKGLERROR
2095 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2096 if (status != GL_FRAMEBUFFER_COMPLETE_EXT && (r_shadow_shadowmapping.integer || r_shadow_deferred.integer))
2098 Con_Printf("R_Shadow_MakeShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2099 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2100 Cvar_SetValueQuick(&r_shadow_deferred, 0);
2105 void R_Shadow_RenderMode_ShadowMap(int side, int clear, int size)
2107 float nearclip, farclip, bias;
2108 r_viewport_t viewport;
2111 float clearcolor[4];
2112 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
2114 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
2115 r_shadow_shadowmap_parameters[1] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
2116 r_shadow_shadowmap_parameters[3] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
2117 r_shadow_shadowmapside = side;
2118 r_shadow_shadowmapsize = size;
2120 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2121 r_shadow_shadowmap_parameters[2] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2122 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
2123 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D) goto init_done;
2125 // complex unrolled cube approach (more flexible)
2126 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2127 R_Shadow_MakeVSDCT();
2128 if (!r_shadow_shadowmap2dtexture)
2129 R_Shadow_MakeShadowMap(side, r_shadow_shadowmapmaxsize);
2130 if (r_shadow_shadowmap2dtexture) fbo = r_shadow_fbo2d;
2131 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
2132 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
2133 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
2135 R_Mesh_ResetTextureState();
2136 R_Mesh_ResetRenderTargets();
2137 R_Shadow_RenderMode_Reset();
2140 R_Mesh_SetRenderTargets(fbo, r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
2141 R_SetupShader_DepthOrShadow();
2144 R_SetupShader_ShowDepth();
2145 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
2150 R_SetViewport(&viewport);
2151 flipped = (side & 1) ^ (side >> 2);
2152 r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
2153 r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
2154 switch(vid.renderpath)
2156 case RENDERPATH_GL11:
2157 case RENDERPATH_GL13:
2158 case RENDERPATH_GL20:
2159 case RENDERPATH_SOFT:
2160 case RENDERPATH_GLES2:
2161 GL_CullFace(r_refdef.view.cullface_back);
2162 // OpenGL lets us scissor larger than the viewport, so go ahead and clear all views at once
2163 if ((clear & ((2 << side) - 1)) == (1 << side)) // only clear if the side is the first in the mask
2165 // get tightest scissor rectangle that encloses all viewports in the clear mask
2166 int x1 = clear & 0x15 ? 0 : size;
2167 int x2 = clear & 0x2A ? 2 * size : size;
2168 int y1 = clear & 0x03 ? 0 : (clear & 0xC ? size : 2 * size);
2169 int y2 = clear & 0x30 ? 3 * size : (clear & 0xC ? 2 * size : size);
2170 GL_Scissor(x1, y1, x2 - x1, y2 - y1);
2171 GL_Clear(GL_DEPTH_BUFFER_BIT, NULL, 1.0f, 0);
2173 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2175 case RENDERPATH_D3D9:
2176 case RENDERPATH_D3D10:
2177 case RENDERPATH_D3D11:
2178 Vector4Set(clearcolor, 1,1,1,1);
2179 // completely different meaning than in OpenGL path
2180 r_shadow_shadowmap_parameters[1] = 0;
2181 r_shadow_shadowmap_parameters[3] = -bias;
2182 // we invert the cull mode because we flip the projection matrix
2183 // NOTE: this actually does nothing because the DrawShadowMap code sets it to doublesided...
2184 GL_CullFace(r_refdef.view.cullface_front);
2185 // D3D considers it an error to use a scissor larger than the viewport... clear just this view
2186 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2187 if (r_shadow_shadowmapsampler)
2189 GL_ColorMask(0,0,0,0);
2191 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
2195 GL_ColorMask(1,1,1,1);
2197 GL_Clear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
2203 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
2205 R_Mesh_ResetTextureState();
2206 R_Mesh_ResetRenderTargets();
2209 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2210 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2211 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2212 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2214 R_Shadow_RenderMode_Reset();
2215 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2217 GL_DepthFunc(GL_EQUAL);
2218 // do global setup needed for the chosen lighting mode
2219 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2220 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2221 r_shadow_usingshadowmap2d = shadowmapping;
2222 r_shadow_rendermode = r_shadow_lightingrendermode;
2223 // only draw light where this geometry was already rendered AND the
2224 // stencil is 128 (values other than this mean shadow)
2226 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2228 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
2231 static const unsigned short bboxelements[36] =
2241 static const float bboxpoints[8][3] =
2253 void R_Shadow_RenderMode_DrawDeferredLight(qboolean stenciltest, qboolean shadowmapping)
2256 float vertex3f[8*3];
2257 const matrix4x4_t *matrix = &rsurface.rtlight->matrix_lighttoworld;
2258 // do global setup needed for the chosen lighting mode
2259 R_Shadow_RenderMode_Reset();
2260 r_shadow_rendermode = r_shadow_lightingrendermode;
2261 R_EntityMatrix(&identitymatrix);
2262 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2263 // only draw light where this geometry was already rendered AND the
2264 // stencil is 128 (values other than this mean shadow)
2265 R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2266 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
2268 r_shadow_usingshadowmap2d = shadowmapping;
2270 // render the lighting
2271 R_SetupShader_DeferredLight(rsurface.rtlight);
2272 for (i = 0;i < 8;i++)
2273 Matrix4x4_Transform(matrix, bboxpoints[i], vertex3f + i*3);
2274 GL_ColorMask(1,1,1,1);
2275 GL_DepthMask(false);
2276 GL_DepthRange(0, 1);
2277 GL_PolygonOffset(0, 0);
2279 GL_DepthFunc(GL_GREATER);
2280 GL_CullFace(r_refdef.view.cullface_back);
2281 R_Mesh_PrepareVertices_Vertex3f(8, vertex3f, NULL);
2282 R_Mesh_Draw(0, 8, 0, 12, NULL, NULL, 0, bboxelements, NULL, 0);
2285 static void R_Shadow_UpdateBounceGridTexture(void)
2287 #define MAXBOUNCEGRIDPARTICLESPERLIGHT 1048576
2289 int flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
2291 int hitsupercontentsmask;
2300 //trace_t cliptrace2;
2301 //trace_t cliptrace3;
2302 unsigned char *pixel;
2303 unsigned char *pixels;
2306 unsigned int lightindex;
2308 unsigned int range1;
2309 unsigned int range2;
2310 unsigned int seed = (unsigned int)(realtime * 1000.0f);
2312 vec3_t baseshotcolor;
2325 vec_t lightintensity;
2326 vec_t photonscaling;
2327 vec_t photonresidual;
2329 float texlerp[2][3];
2330 float splatcolor[16];
2331 float pixelweight[8];
2337 qboolean isstatic = r_shadow_bouncegrid_updateinterval.value > 1.0f;
2338 qboolean directionalshading = r_shadow_bouncegrid_directionalshading.integer != 0;
2340 if (!r_shadow_bouncegrid.integer || !vid.support.ext_texture_3d)
2342 if (r_shadow_bouncegridtexture)
2344 R_FreeTexture(r_shadow_bouncegridtexture);
2345 r_shadow_bouncegridtexture = NULL;
2347 if (r_shadow_bouncegridpixels)
2348 Mem_Free(r_shadow_bouncegridpixels);
2349 r_shadow_bouncegridpixels = NULL;
2350 if (r_shadow_bouncegridhighpixels)
2351 Mem_Free(r_shadow_bouncegridhighpixels);
2352 r_shadow_bouncegridhighpixels = NULL;
2353 r_shadow_bouncegridnumpixels = 0;
2354 r_shadow_bouncegriddirectional = false;
2357 if (r_refdef.scene.worldmodel && isstatic)
2359 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));
2360 VectorMA(r_refdef.scene.worldmodel->normalmins, -2.0f, spacing, mins);
2361 VectorMA(r_refdef.scene.worldmodel->normalmaxs, 2.0f, spacing, maxs);
2362 VectorSubtract(maxs, mins, size);
2363 resolution[0] = (int)floor(size[0] / spacing[0] + 0.5f);
2364 resolution[1] = (int)floor(size[1] / spacing[1] + 0.5f);
2365 resolution[2] = (int)floor(size[2] / spacing[2] + 0.5f);
2366 resolution[0] = min(resolution[0], bound(4, r_shadow_bouncegrid_x.integer, (int)vid.maxtexturesize_3d));
2367 resolution[1] = min(resolution[1], bound(4, r_shadow_bouncegrid_y.integer, (int)vid.maxtexturesize_3d));
2368 resolution[2] = min(resolution[2], bound(4, r_shadow_bouncegrid_z.integer, (int)vid.maxtexturesize_3d));
2369 spacing[0] = size[0] / resolution[0];
2370 spacing[1] = size[1] / resolution[1];
2371 spacing[2] = size[2] / resolution[2];
2372 ispacing[0] = 1.0f / spacing[0];
2373 ispacing[1] = 1.0f / spacing[1];
2374 ispacing[2] = 1.0f / spacing[2];
2378 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));
2379 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));
2380 VectorMultiply(resolution, spacing, size);
2381 ispacing[0] = 1.0f / spacing[0];
2382 ispacing[1] = 1.0f / spacing[1];
2383 ispacing[2] = 1.0f / spacing[2];
2384 mins[0] = floor(r_refdef.view.origin[0] * ispacing[0] + 0.5f) * spacing[0] - 0.5f * size[0];
2385 mins[1] = floor(r_refdef.view.origin[1] * ispacing[1] + 0.5f) * spacing[1] - 0.5f * size[1];
2386 mins[2] = floor(r_refdef.view.origin[2] * ispacing[2] + 0.5f) * spacing[2] - 0.5f * size[2];
2387 VectorAdd(mins, size, maxs);
2389 r_shadow_bouncegridintensity = r_shadow_bouncegrid_intensity.value;
2390 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])
2392 // we're going to update the bouncegrid, update the matrix...
2393 memset(m, 0, sizeof(m));
2394 m[0] = 1.0f / size[0];
2395 m[3] = -mins[0] * m[0];
2396 m[5] = 1.0f / size[1];
2397 m[7] = -mins[1] * m[5];
2398 m[10] = 1.0f / size[2];
2399 m[11] = -mins[2] * m[10];
2401 if (directionalshading)
2406 Matrix4x4_FromArrayFloatD3D(&r_shadow_bouncegridmatrix, m);
2407 numpixels = resolution[0]*resolution[1]*resolution[2];
2408 if (directionalshading)
2410 r_shadow_bouncegriddirectional = directionalshading;
2411 // reallocate pixels for this update if needed...
2412 if (r_shadow_bouncegridnumpixels != numpixels || !r_shadow_bouncegridpixels || !r_shadow_bouncegridhighpixels)
2414 if (r_shadow_bouncegridtexture)
2416 R_FreeTexture(r_shadow_bouncegridtexture);
2417 r_shadow_bouncegridtexture = NULL;
2419 r_shadow_bouncegridpixels = (unsigned char *)Mem_Realloc(r_main_mempool, r_shadow_bouncegridpixels, numpixels * sizeof(unsigned char[4]));
2420 r_shadow_bouncegridhighpixels = (float *)Mem_Realloc(r_main_mempool, r_shadow_bouncegridhighpixels, numpixels * sizeof(float[4]));
2422 r_shadow_bouncegridnumpixels = numpixels;
2423 pixels = r_shadow_bouncegridpixels;
2424 highpixels = r_shadow_bouncegridhighpixels;
2425 if (directionalshading)
2426 memset(pixels, 128, numpixels * sizeof(unsigned char[4]));
2428 memset(pixels, 0, numpixels * sizeof(unsigned char[4]));
2429 memset(highpixels, 0, numpixels * sizeof(float[4]));
2430 // figure out what we want to interact with
2431 if (r_shadow_bouncegrid_hitmodels.integer)
2432 hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_LIQUIDSMASK;
2434 hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_LIQUIDSMASK;
2435 maxbounce = bound(1, r_shadow_bouncegrid_maxbounce.integer, 16);
2436 // clear variables that produce warnings otherwise
2437 memset(splatcolor, 0, sizeof(splatcolor));
2438 // iterate world rtlights
2439 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
2440 range1 = isstatic ? 0 : r_refdef.scene.numlights;
2441 range2 = range + range1;
2443 for (lightindex = 0;lightindex < range2;lightindex++)
2447 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2448 if (!light || !(light->flags & flag))
2450 rtlight = &light->rtlight;
2451 // when static, we skip styled lights because they tend to change...
2452 if (rtlight->style > 0)
2454 VectorScale(rtlight->color, (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) * (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1), lightcolor);
2458 if (lightindex < range)
2460 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2461 rtlight = &light->rtlight;
2464 rtlight = r_refdef.scene.lights[lightindex - range];
2465 // draw only visible lights (major speedup)
2468 VectorScale(rtlight->currentcolor, rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale, lightcolor);
2470 if (!VectorLength2(lightcolor))
2472 // shoot particles from this light
2473 // use a calculation for the number of particles that will not
2474 // vary with lightstyle, otherwise we get randomized particle
2475 // distribution, the seeded random is only consistent for a
2476 // consistent number of particles on this light...
2477 radius = rtlight->radius * bound(0.0001f, r_shadow_bouncegrid_lightradiusscale.value, 1024.0f);
2478 s = rtlight->radius;
2479 lightintensity = VectorLength(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2480 if (lightindex >= range)
2481 lightintensity *= r_shadow_bouncegrid_dlightparticlemultiplier.value;
2482 photoncount += max(0.0f, lightintensity * s * s);
2484 photonscaling = bound(1, r_shadow_bouncegrid_photons.value, 1048576) / max(1, photoncount);
2485 photonresidual = 0.0f;
2486 for (lightindex = 0;lightindex < range2;lightindex++)
2490 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2491 if (!light || !(light->flags & flag))
2493 rtlight = &light->rtlight;
2494 // when static, we skip styled lights because they tend to change...
2495 if (rtlight->style > 0)
2497 VectorScale(rtlight->color, (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) * (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1), lightcolor);
2501 if (lightindex < range)
2503 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2504 rtlight = &light->rtlight;
2507 rtlight = r_refdef.scene.lights[lightindex - range];
2508 // draw only visible lights (major speedup)
2511 VectorScale(rtlight->currentcolor, rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale, lightcolor);
2513 if (!VectorLength2(lightcolor))
2515 // shoot particles from this light
2516 // use a calculation for the number of particles that will not
2517 // vary with lightstyle, otherwise we get randomized particle
2518 // distribution, the seeded random is only consistent for a
2519 // consistent number of particles on this light...
2520 radius = rtlight->radius * bound(0.0001f, r_shadow_bouncegrid_lightradiusscale.value, 1024.0f);
2521 s = rtlight->radius;
2522 lightintensity = VectorLength(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2523 if (lightindex >= range)
2524 lightintensity *= r_shadow_bouncegrid_dlightparticlemultiplier.value;
2525 photonresidual += lightintensity * s * s * photonscaling;
2526 shootparticles = (int)bound(0, photonresidual, MAXBOUNCEGRIDPARTICLESPERLIGHT);
2527 if (!shootparticles)
2529 photonresidual -= shootparticles;
2530 s = r_shadow_bouncegrid_particleintensity.value / shootparticles;
2531 VectorScale(lightcolor, s, baseshotcolor);
2532 if (VectorLength2(baseshotcolor) == 0.0f)
2534 r_refdef.stats.bouncegrid_lights++;
2535 r_refdef.stats.bouncegrid_particles += shootparticles;
2536 for (shotparticles = 0;shotparticles < shootparticles;shotparticles++)
2538 if (r_shadow_bouncegrid_stablerandom.integer > 0)
2539 seed = lightindex * 11937 + shotparticles;
2540 VectorCopy(baseshotcolor, shotcolor);
2541 VectorCopy(rtlight->shadoworigin, clipstart);
2542 if (r_shadow_bouncegrid_stablerandom.integer < 0)
2543 VectorRandom(clipend);
2545 VectorCheeseRandom(clipend);
2546 VectorMA(clipstart, radius, clipend, clipend);
2547 for (bouncecount = 0;;bouncecount++)
2549 r_refdef.stats.bouncegrid_traces++;
2550 //r_refdef.scene.worldmodel->TraceLineAgainstSurfaces(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace, clipstart, clipend, hitsupercontentsmask);
2551 //r_refdef.scene.worldmodel->TraceLine(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace2, clipstart, clipend, hitsupercontentsmask);
2552 cliptrace = CL_TraceLine(clipstart, clipend, r_shadow_bouncegrid_hitmodels.integer ? MOVE_HITMODEL : MOVE_NOMONSTERS, NULL, hitsupercontentsmask, true, false, NULL, true, true);
2553 //Collision_ClipLineToWorld(&cliptrace, cl.worldmodel, clipstart, clipend, hitsupercontentsmask);
2554 if (cliptrace.fraction >= 1.0f)
2556 r_refdef.stats.bouncegrid_hits++;
2557 if (bouncecount > 0)
2559 r_refdef.stats.bouncegrid_splats++;
2560 // figure out which texture pixel this is in
2561 texlerp[1][0] = ((cliptrace.endpos[0] - mins[0]) * ispacing[0]);
2562 texlerp[1][1] = ((cliptrace.endpos[1] - mins[1]) * ispacing[1]);
2563 texlerp[1][2] = ((cliptrace.endpos[2] - mins[2]) * ispacing[2]);
2564 tex[0] = (int)floor(texlerp[1][0]);
2565 tex[1] = (int)floor(texlerp[1][1]);
2566 tex[2] = (int)floor(texlerp[1][2]);
2567 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)
2569 // it is within bounds... do the real work now
2570 // calculate first order spherical harmonics values (average, slopeX, slopeY, slopeZ)
2571 if (directionalshading)
2573 VectorSubtract(clipstart, cliptrace.endpos, clipdiff);
2574 VectorNormalize(clipdiff);
2575 splatcolor[ 0] = shotcolor[0] * clipdiff[2];
2576 splatcolor[ 1] = shotcolor[0] * clipdiff[1];
2577 splatcolor[ 2] = shotcolor[0] * clipdiff[0];
2578 splatcolor[ 3] = shotcolor[0];
2579 splatcolor[ 4] = shotcolor[1] * clipdiff[2];
2580 splatcolor[ 5] = shotcolor[1] * clipdiff[1];
2581 splatcolor[ 6] = shotcolor[1] * clipdiff[0];
2582 splatcolor[ 7] = shotcolor[1];
2583 splatcolor[ 8] = shotcolor[2] * clipdiff[2];
2584 splatcolor[ 9] = shotcolor[2] * clipdiff[1];
2585 splatcolor[10] = shotcolor[2] * clipdiff[0];
2586 splatcolor[11] = shotcolor[2];
2587 w = VectorLength(shotcolor);
2588 splatcolor[12] = clipdiff[2] * w;
2589 splatcolor[13] = clipdiff[1] * w;
2590 splatcolor[14] = clipdiff[0] * w;
2591 splatcolor[15] = 1.0f;
2595 splatcolor[ 0] = shotcolor[2];
2596 splatcolor[ 1] = shotcolor[1];
2597 splatcolor[ 2] = shotcolor[0];
2598 splatcolor[ 3] = 1.0f;
2600 // calculate the lerp factors
2601 texlerp[1][0] -= tex[0];
2602 texlerp[1][1] -= tex[1];
2603 texlerp[1][2] -= tex[2];
2604 texlerp[0][0] = 1.0f - texlerp[1][0];
2605 texlerp[0][1] = 1.0f - texlerp[1][1];
2606 texlerp[0][2] = 1.0f - texlerp[1][2];
2607 // calculate individual pixel indexes and weights
2608 pixelindex[0] = (((tex[2] )*resolution[1]+tex[1] )*resolution[0]+tex[0] );pixelweight[0] = (texlerp[0][0]*texlerp[0][1]*texlerp[0][2]);
2609 pixelindex[1] = (((tex[2] )*resolution[1]+tex[1] )*resolution[0]+tex[0]+1);pixelweight[1] = (texlerp[1][0]*texlerp[0][1]*texlerp[0][2]);
2610 pixelindex[2] = (((tex[2] )*resolution[1]+tex[1]+1)*resolution[0]+tex[0] );pixelweight[2] = (texlerp[0][0]*texlerp[1][1]*texlerp[0][2]);
2611 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]);
2612 pixelindex[4] = (((tex[2]+1)*resolution[1]+tex[1] )*resolution[0]+tex[0] );pixelweight[4] = (texlerp[0][0]*texlerp[0][1]*texlerp[1][2]);
2613 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]);
2614 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]);
2615 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]);
2616 // update the 8 pixels...
2617 for (corner = 0;corner < 8;corner++)
2619 // calculate address for first set of coefficients
2620 w = pixelweight[corner];
2621 pixel = pixels + 4 * pixelindex[corner];
2622 highpixel = highpixels + 4 * pixelindex[corner];
2623 // add to the high precision pixel color
2624 highpixel[0] += (splatcolor[ 0]*w);
2625 highpixel[1] += (splatcolor[ 1]*w);
2626 highpixel[2] += (splatcolor[ 2]*w);
2627 highpixel[3] += (splatcolor[ 3]*w);
2628 // flag the low precision pixel as needing to be updated
2630 if (directionalshading)
2632 // advance to second set of coefficients
2634 highpixel += numpixels;
2635 // add to the high precision pixel color
2636 highpixel[0] += (splatcolor[ 4]*w);
2637 highpixel[1] += (splatcolor[ 5]*w);
2638 highpixel[2] += (splatcolor[ 6]*w);
2639 highpixel[3] += (splatcolor[ 7]*w);
2640 // flag the low precision pixel as needing to be updated
2642 // advance to third set of coefficients
2644 highpixel += numpixels;
2645 // add to the high precision pixel color
2646 highpixel[0] += (splatcolor[ 8]*w);
2647 highpixel[1] += (splatcolor[ 9]*w);
2648 highpixel[2] += (splatcolor[10]*w);
2649 highpixel[3] += (splatcolor[11]*w);
2650 // flag the low precision pixel as needing to be updated
2652 // advance to fourth set of coefficients
2654 highpixel += numpixels;
2655 // add to the high precision pixel color
2656 highpixel[0] += (splatcolor[12]*w);
2657 highpixel[1] += (splatcolor[13]*w);
2658 highpixel[2] += (splatcolor[14]*w);
2659 highpixel[3] += (splatcolor[15]*w);
2660 // flag the low precision pixel as needing to be updated
2666 if (bouncecount >= maxbounce)
2668 // scale down shot color by bounce intensity and texture color (or 50% if no texture reported)
2669 // also clamp the resulting color to never add energy, even if the user requests extreme values
2670 if (cliptrace.hittexture && cliptrace.hittexture->currentskinframe)
2671 VectorCopy(cliptrace.hittexture->currentskinframe->avgcolor, surfcolor);
2673 VectorSet(surfcolor, 0.5f, 0.5f, 0.5f);
2674 VectorScale(surfcolor, r_shadow_bouncegrid_particlebounceintensity.value, surfcolor);
2675 surfcolor[0] = min(surfcolor[0], 1.0f);
2676 surfcolor[1] = min(surfcolor[1], 1.0f);
2677 surfcolor[2] = min(surfcolor[2], 1.0f);
2678 VectorMultiply(shotcolor, surfcolor, shotcolor);
2679 if (VectorLength2(baseshotcolor) == 0.0f)
2681 r_refdef.stats.bouncegrid_bounces++;
2682 if (r_shadow_bouncegrid_bounceanglediffuse.integer)
2684 // random direction, primarily along plane normal
2685 s = VectorDistance(cliptrace.endpos, clipend);
2686 if (r_shadow_bouncegrid_stablerandom.integer < 0)
2687 VectorRandom(clipend);
2689 VectorCheeseRandom(clipend);
2690 VectorMA(cliptrace.plane.normal, 0.95f, clipend, clipend);
2691 VectorNormalize(clipend);
2692 VectorScale(clipend, s, clipend);
2696 // reflect the remaining portion of the line across plane normal
2697 VectorSubtract(clipend, cliptrace.endpos, clipdiff);
2698 VectorReflect(clipdiff, 1.0, cliptrace.plane.normal, clipend);
2700 // calculate the new line start and end
2701 VectorCopy(cliptrace.endpos, clipstart);
2702 VectorAdd(clipstart, clipend, clipend);
2706 // generate pixels array from highpixels array
2707 // skip first and last columns, rows, and layers as these are blank
2708 // the pixel[3] value was written above, so we can use it to detect only pixels that need to be calculated
2709 for (d = 0;d < 4;d++)
2711 for (z = 1;z < resolution[2]-1;z++)
2713 for (y = 1;y < resolution[1]-1;y++)
2715 for (x = 1, pixelindex[0] = ((d*resolution[2]+z)*resolution[1]+y)*resolution[0]+x, pixel = pixels + 4*pixelindex[0], highpixel = highpixels + 4*pixelindex[0];x < resolution[0]-1;x++, pixel += 4, highpixel += 4)
2717 // only convert pixels that were hit by photons
2718 if (pixel[3] == 255)
2720 // normalize the bentnormal...
2721 if (directionalshading)
2724 VectorNormalize(highpixel);
2725 c[0] = (int)(highpixel[0]*128.0f+128.0f);
2726 c[1] = (int)(highpixel[1]*128.0f+128.0f);
2727 c[2] = (int)(highpixel[2]*128.0f+128.0f);
2728 c[3] = (int)(highpixel[3]*128.0f+128.0f);
2732 c[0] = (int)(highpixel[0]*256.0f);
2733 c[1] = (int)(highpixel[1]*256.0f);
2734 c[2] = (int)(highpixel[2]*256.0f);
2735 c[3] = (int)(highpixel[3]*256.0f);
2737 pixel[0] = (unsigned char)bound(0, c[0], 255);
2738 pixel[1] = (unsigned char)bound(0, c[1], 255);
2739 pixel[2] = (unsigned char)bound(0, c[2], 255);
2740 pixel[3] = (unsigned char)bound(0, c[3], 255);
2745 if (!directionalshading)
2748 if (r_shadow_bouncegridtexture && r_shadow_bouncegridresolution[0] == resolution[0] && r_shadow_bouncegridresolution[1] == resolution[1] && r_shadow_bouncegridresolution[2] == resolution[2])
2749 R_UpdateTexture(r_shadow_bouncegridtexture, pixels, 0, 0, 0, resolution[0], resolution[1], resolution[2]*(directionalshading ? 4 : 1));
2752 VectorCopy(resolution, r_shadow_bouncegridresolution);
2753 if (r_shadow_bouncegridtexture)
2754 R_FreeTexture(r_shadow_bouncegridtexture);
2755 r_shadow_bouncegridtexture = R_LoadTexture3D(r_shadow_texturepool, "bouncegrid", resolution[0], resolution[1], resolution[2]*(directionalshading ? 4 : 1), pixels, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, 0, NULL);
2757 r_shadow_bouncegridtime = realtime;
2760 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
2762 R_Shadow_RenderMode_Reset();
2763 GL_BlendFunc(GL_ONE, GL_ONE);
2764 GL_DepthRange(0, 1);
2765 GL_DepthTest(r_showshadowvolumes.integer < 2);
2766 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
2767 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2768 GL_CullFace(GL_NONE);
2769 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
2772 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
2774 R_Shadow_RenderMode_Reset();
2775 GL_BlendFunc(GL_ONE, GL_ONE);
2776 GL_DepthRange(0, 1);
2777 GL_DepthTest(r_showlighting.integer < 2);
2778 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2780 GL_DepthFunc(GL_EQUAL);
2781 R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2782 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2785 void R_Shadow_RenderMode_End(void)
2787 R_Shadow_RenderMode_Reset();
2788 R_Shadow_RenderMode_ActiveLight(NULL);
2790 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2791 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2794 int bboxedges[12][2] =
2813 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2815 if (!r_shadow_scissor.integer)
2817 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2818 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2819 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2820 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2823 if(R_ScissorForBBox(mins, maxs, r_shadow_lightscissor))
2824 return true; // invisible
2825 if(r_shadow_lightscissor[0] != r_refdef.view.viewport.x
2826 || r_shadow_lightscissor[1] != r_refdef.view.viewport.y
2827 || r_shadow_lightscissor[2] != r_refdef.view.viewport.width
2828 || r_shadow_lightscissor[3] != r_refdef.view.viewport.height)
2829 r_refdef.stats.lights_scissored++;
2833 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, const float *diffusecolor, const float *ambientcolor)
2836 const float *vertex3f;
2837 const float *normal3f;
2839 float dist, dot, distintensity, shadeintensity, v[3], n[3];
2840 switch (r_shadow_rendermode)
2842 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2843 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2844 if (VectorLength2(diffusecolor) > 0)
2846 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)
2848 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2849 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2850 if ((dot = DotProduct(n, v)) < 0)
2852 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2853 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
2856 VectorCopy(ambientcolor, color4f);
2857 if (r_refdef.fogenabled)
2860 f = RSurf_FogVertex(vertex3f);
2861 VectorScale(color4f, f, color4f);
2868 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
2870 VectorCopy(ambientcolor, color4f);
2871 if (r_refdef.fogenabled)
2874 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2875 f = RSurf_FogVertex(vertex3f);
2876 VectorScale(color4f + 4*i, f, color4f);
2882 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2883 if (VectorLength2(diffusecolor) > 0)
2885 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)
2887 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2888 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2890 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2891 if ((dot = DotProduct(n, v)) < 0)
2893 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2894 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2895 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2896 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2900 color4f[0] = ambientcolor[0] * distintensity;
2901 color4f[1] = ambientcolor[1] * distintensity;
2902 color4f[2] = ambientcolor[2] * distintensity;
2904 if (r_refdef.fogenabled)
2907 f = RSurf_FogVertex(vertex3f);
2908 VectorScale(color4f, f, color4f);
2912 VectorClear(color4f);
2918 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
2920 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2921 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2923 color4f[0] = ambientcolor[0] * distintensity;
2924 color4f[1] = ambientcolor[1] * distintensity;
2925 color4f[2] = ambientcolor[2] * distintensity;
2926 if (r_refdef.fogenabled)
2929 f = RSurf_FogVertex(vertex3f);
2930 VectorScale(color4f, f, color4f);
2934 VectorClear(color4f);
2939 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2940 if (VectorLength2(diffusecolor) > 0)
2942 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)
2944 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2945 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2947 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2948 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2949 if ((dot = DotProduct(n, v)) < 0)
2951 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2952 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2953 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2954 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2958 color4f[0] = ambientcolor[0] * distintensity;
2959 color4f[1] = ambientcolor[1] * distintensity;
2960 color4f[2] = ambientcolor[2] * distintensity;
2962 if (r_refdef.fogenabled)
2965 f = RSurf_FogVertex(vertex3f);
2966 VectorScale(color4f, f, color4f);
2970 VectorClear(color4f);
2976 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
2978 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2979 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2981 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2982 color4f[0] = ambientcolor[0] * distintensity;
2983 color4f[1] = ambientcolor[1] * distintensity;
2984 color4f[2] = ambientcolor[2] * distintensity;
2985 if (r_refdef.fogenabled)
2988 f = RSurf_FogVertex(vertex3f);
2989 VectorScale(color4f, f, color4f);
2993 VectorClear(color4f);
3003 static void R_Shadow_RenderLighting_VisibleLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
3005 // used to display how many times a surface is lit for level design purposes
3006 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
3007 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
3011 static void R_Shadow_RenderLighting_Light_GLSL(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale, float specularscale)
3013 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
3014 R_SetupShader_Surface(lightcolor, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT, texturenumsurfaces, texturesurfacelist, NULL);
3015 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
3016 GL_DepthFunc(GL_EQUAL);
3018 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
3019 GL_DepthFunc(GL_LEQUAL);
3022 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
3029 int newnumtriangles;
3033 int maxtriangles = 4096;
3034 static int newelements[4096*3];
3035 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, diffusecolor2, ambientcolor2);
3036 for (renders = 0;renders < 4;renders++)
3041 newnumtriangles = 0;
3043 // due to low fillrate on the cards this vertex lighting path is
3044 // designed for, we manually cull all triangles that do not
3045 // contain a lit vertex
3046 // this builds batches of triangles from multiple surfaces and
3047 // renders them at once
3048 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
3050 if (VectorLength2(rsurface.passcolor4f + e[0] * 4) + VectorLength2(rsurface.passcolor4f + e[1] * 4) + VectorLength2(rsurface.passcolor4f + e[2] * 4) >= 0.01)
3052 if (newnumtriangles)
3054 newfirstvertex = min(newfirstvertex, e[0]);
3055 newlastvertex = max(newlastvertex, e[0]);
3059 newfirstvertex = e[0];
3060 newlastvertex = e[0];
3062 newfirstvertex = min(newfirstvertex, e[1]);
3063 newlastvertex = max(newlastvertex, e[1]);
3064 newfirstvertex = min(newfirstvertex, e[2]);
3065 newlastvertex = max(newlastvertex, e[2]);
3071 if (newnumtriangles >= maxtriangles)
3073 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
3074 newnumtriangles = 0;
3080 if (newnumtriangles >= 1)
3082 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
3085 // if we couldn't find any lit triangles, exit early
3088 // now reduce the intensity for the next overbright pass
3089 // we have to clamp to 0 here incase the drivers have improper
3090 // handling of negative colors
3091 // (some old drivers even have improper handling of >1 color)
3093 for (i = 0, c = rsurface.passcolor4f + 4 * firstvertex;i < numvertices;i++, c += 4)
3095 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
3097 c[0] = max(0, c[0] - 1);
3098 c[1] = max(0, c[1] - 1);
3099 c[2] = max(0, c[2] - 1);
3111 static void R_Shadow_RenderLighting_Light_Vertex(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale)
3113 // OpenGL 1.1 path (anything)
3114 float ambientcolorbase[3], diffusecolorbase[3];
3115 float ambientcolorpants[3], diffusecolorpants[3];
3116 float ambientcolorshirt[3], diffusecolorshirt[3];
3117 const float *surfacecolor = rsurface.texture->dlightcolor;
3118 const float *surfacepants = rsurface.colormap_pantscolor;
3119 const float *surfaceshirt = rsurface.colormap_shirtcolor;
3120 rtexture_t *basetexture = rsurface.texture->basetexture;
3121 rtexture_t *pantstexture = rsurface.texture->pantstexture;
3122 rtexture_t *shirttexture = rsurface.texture->shirttexture;
3123 qboolean dopants = pantstexture && VectorLength2(surfacepants) >= (1.0f / 1048576.0f);
3124 qboolean doshirt = shirttexture && VectorLength2(surfaceshirt) >= (1.0f / 1048576.0f);
3125 ambientscale *= 2 * r_refdef.view.colorscale;
3126 diffusescale *= 2 * r_refdef.view.colorscale;
3127 ambientcolorbase[0] = lightcolor[0] * ambientscale * surfacecolor[0];ambientcolorbase[1] = lightcolor[1] * ambientscale * surfacecolor[1];ambientcolorbase[2] = lightcolor[2] * ambientscale * surfacecolor[2];
3128 diffusecolorbase[0] = lightcolor[0] * diffusescale * surfacecolor[0];diffusecolorbase[1] = lightcolor[1] * diffusescale * surfacecolor[1];diffusecolorbase[2] = lightcolor[2] * diffusescale * surfacecolor[2];
3129 ambientcolorpants[0] = ambientcolorbase[0] * surfacepants[0];ambientcolorpants[1] = ambientcolorbase[1] * surfacepants[1];ambientcolorpants[2] = ambientcolorbase[2] * surfacepants[2];
3130 diffusecolorpants[0] = diffusecolorbase[0] * surfacepants[0];diffusecolorpants[1] = diffusecolorbase[1] * surfacepants[1];diffusecolorpants[2] = diffusecolorbase[2] * surfacepants[2];
3131 ambientcolorshirt[0] = ambientcolorbase[0] * surfaceshirt[0];ambientcolorshirt[1] = ambientcolorbase[1] * surfaceshirt[1];ambientcolorshirt[2] = ambientcolorbase[2] * surfaceshirt[2];
3132 diffusecolorshirt[0] = diffusecolorbase[0] * surfaceshirt[0];diffusecolorshirt[1] = diffusecolorbase[1] * surfaceshirt[1];diffusecolorshirt[2] = diffusecolorbase[2] * surfaceshirt[2];
3133 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | (diffusescale > 0 ? BATCHNEED_ARRAY_NORMAL : 0) | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
3134 rsurface.passcolor4f = (float *)R_FrameData_Alloc((rsurface.batchfirstvertex + rsurface.batchnumvertices) * sizeof(float[4]));
3135 R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3136 R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.passcolor4f, 0, 0);
3137 R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
3138 R_Mesh_TexBind(0, basetexture);
3139 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
3140 R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
3141 switch(r_shadow_rendermode)
3143 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
3144 R_Mesh_TexBind(1, r_shadow_attenuation3dtexture);
3145 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
3146 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
3147 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3149 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
3150 R_Mesh_TexBind(2, r_shadow_attenuation2dtexture);
3151 R_Mesh_TexMatrix(2, &rsurface.entitytoattenuationz);
3152 R_Mesh_TexCombine(2, GL_MODULATE, GL_MODULATE, 1, 1);
3153 R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3155 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
3156 R_Mesh_TexBind(1, r_shadow_attenuation2dtexture);
3157 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
3158 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
3159 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3161 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3166 //R_Mesh_TexBind(0, basetexture);
3167 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorbase, ambientcolorbase);
3170 R_Mesh_TexBind(0, pantstexture);
3171 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorpants, ambientcolorpants);
3175 R_Mesh_TexBind(0, shirttexture);
3176 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorshirt, ambientcolorshirt);
3180 extern cvar_t gl_lightmaps;
3181 void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
3183 float ambientscale, diffusescale, specularscale;
3185 float lightcolor[3];
3186 VectorCopy(rsurface.rtlight->currentcolor, lightcolor);
3187 ambientscale = rsurface.rtlight->ambientscale;
3188 diffusescale = rsurface.rtlight->diffusescale;
3189 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
3190 if (!r_shadow_usenormalmap.integer)
3192 ambientscale += 1.0f * diffusescale;
3196 if ((ambientscale + diffusescale) * VectorLength2(lightcolor) + specularscale * VectorLength2(lightcolor) < (1.0f / 1048576.0f))
3198 negated = (lightcolor[0] + lightcolor[1] + lightcolor[2] < 0) && vid.support.ext_blend_subtract;
3201 VectorNegate(lightcolor, lightcolor);
3202 switch(vid.renderpath)
3204 case RENDERPATH_GL11:
3205 case RENDERPATH_GL13:
3206 case RENDERPATH_GL20:
3207 case RENDERPATH_GLES2:
3208 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
3210 case RENDERPATH_D3D9:
3212 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_SUBTRACT);
3215 case RENDERPATH_D3D10:
3216 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3218 case RENDERPATH_D3D11:
3219 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3221 case RENDERPATH_SOFT:
3222 DPSOFTRAST_BlendSubtract(true);
3226 RSurf_SetupDepthAndCulling();
3227 switch (r_shadow_rendermode)
3229 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
3230 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
3231 R_Shadow_RenderLighting_VisibleLighting(texturenumsurfaces, texturesurfacelist);
3233 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
3234 R_Shadow_RenderLighting_Light_GLSL(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale, specularscale);
3236 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
3237 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
3238 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
3239 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3240 R_Shadow_RenderLighting_Light_Vertex(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale);
3243 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
3248 switch(vid.renderpath)
3250 case RENDERPATH_GL11:
3251 case RENDERPATH_GL13:
3252 case RENDERPATH_GL20:
3253 case RENDERPATH_GLES2:
3254 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
3256 case RENDERPATH_D3D9:
3258 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_ADD);
3261 case RENDERPATH_D3D10:
3262 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3264 case RENDERPATH_D3D11:
3265 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3267 case RENDERPATH_SOFT:
3268 DPSOFTRAST_BlendSubtract(false);
3274 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)
3276 matrix4x4_t tempmatrix = *matrix;
3277 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
3279 // if this light has been compiled before, free the associated data
3280 R_RTLight_Uncompile(rtlight);
3282 // clear it completely to avoid any lingering data
3283 memset(rtlight, 0, sizeof(*rtlight));
3285 // copy the properties
3286 rtlight->matrix_lighttoworld = tempmatrix;
3287 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
3288 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
3289 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
3290 VectorCopy(color, rtlight->color);
3291 rtlight->cubemapname[0] = 0;
3292 if (cubemapname && cubemapname[0])
3293 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
3294 rtlight->shadow = shadow;
3295 rtlight->corona = corona;
3296 rtlight->style = style;
3297 rtlight->isstatic = isstatic;
3298 rtlight->coronasizescale = coronasizescale;
3299 rtlight->ambientscale = ambientscale;
3300 rtlight->diffusescale = diffusescale;
3301 rtlight->specularscale = specularscale;
3302 rtlight->flags = flags;
3304 // compute derived data
3305 //rtlight->cullradius = rtlight->radius;
3306 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
3307 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3308 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3309 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3310 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3311 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3312 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3315 // compiles rtlight geometry
3316 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
3317 void R_RTLight_Compile(rtlight_t *rtlight)
3320 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
3321 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
3322 entity_render_t *ent = r_refdef.scene.worldentity;
3323 dp_model_t *model = r_refdef.scene.worldmodel;
3324 unsigned char *data;
3327 // compile the light
3328 rtlight->compiled = true;
3329 rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
3330 rtlight->static_numleafs = 0;
3331 rtlight->static_numleafpvsbytes = 0;
3332 rtlight->static_leaflist = NULL;
3333 rtlight->static_leafpvs = NULL;
3334 rtlight->static_numsurfaces = 0;
3335 rtlight->static_surfacelist = NULL;
3336 rtlight->static_shadowmap_receivers = 0x3F;
3337 rtlight->static_shadowmap_casters = 0x3F;
3338 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3339 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3340 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3341 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3342 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3343 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3345 if (model && model->GetLightInfo)
3347 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
3348 r_shadow_compilingrtlight = rtlight;
3349 R_FrameData_SetMark();
3350 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);
3351 R_FrameData_ReturnToMark();
3352 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
3353 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
3354 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3355 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
3356 rtlight->static_numsurfaces = numsurfaces;
3357 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
3358 rtlight->static_numleafs = numleafs;
3359 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
3360 rtlight->static_numleafpvsbytes = numleafpvsbytes;
3361 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
3362 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
3363 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
3364 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
3365 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3366 if (rtlight->static_numsurfaces)
3367 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3368 if (rtlight->static_numleafs)
3369 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3370 if (rtlight->static_numleafpvsbytes)
3371 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3372 if (rtlight->static_numshadowtrispvsbytes)
3373 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3374 if (rtlight->static_numlighttrispvsbytes)
3375 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3376 R_FrameData_SetMark();
3377 switch (rtlight->shadowmode)
3379 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
3380 if (model->CompileShadowMap && rtlight->shadow)
3381 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3384 if (model->CompileShadowVolume && rtlight->shadow)
3385 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3388 R_FrameData_ReturnToMark();
3389 // now we're done compiling the rtlight
3390 r_shadow_compilingrtlight = NULL;
3394 // use smallest available cullradius - box radius or light radius
3395 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3396 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3398 shadowzpasstris = 0;
3399 if (rtlight->static_meshchain_shadow_zpass)
3400 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
3401 shadowzpasstris += mesh->numtriangles;
3403 shadowzfailtris = 0;
3404 if (rtlight->static_meshchain_shadow_zfail)
3405 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
3406 shadowzfailtris += mesh->numtriangles;
3409 if (rtlight->static_numlighttrispvsbytes)
3410 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3411 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3415 if (rtlight->static_numlighttrispvsbytes)
3416 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3417 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3420 if (developer_extra.integer)
3421 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);
3424 void R_RTLight_Uncompile(rtlight_t *rtlight)
3426 if (rtlight->compiled)
3428 if (rtlight->static_meshchain_shadow_zpass)
3429 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
3430 rtlight->static_meshchain_shadow_zpass = NULL;
3431 if (rtlight->static_meshchain_shadow_zfail)
3432 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
3433 rtlight->static_meshchain_shadow_zfail = NULL;
3434 if (rtlight->static_meshchain_shadow_shadowmap)
3435 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
3436 rtlight->static_meshchain_shadow_shadowmap = NULL;
3437 // these allocations are grouped
3438 if (rtlight->static_surfacelist)
3439 Mem_Free(rtlight->static_surfacelist);
3440 rtlight->static_numleafs = 0;
3441 rtlight->static_numleafpvsbytes = 0;
3442 rtlight->static_leaflist = NULL;
3443 rtlight->static_leafpvs = NULL;
3444 rtlight->static_numsurfaces = 0;
3445 rtlight->static_surfacelist = NULL;
3446 rtlight->static_numshadowtrispvsbytes = 0;
3447 rtlight->static_shadowtrispvs = NULL;
3448 rtlight->static_numlighttrispvsbytes = 0;
3449 rtlight->static_lighttrispvs = NULL;
3450 rtlight->compiled = false;
3454 void R_Shadow_UncompileWorldLights(void)
3458 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3459 for (lightindex = 0;lightindex < range;lightindex++)
3461 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3464 R_RTLight_Uncompile(&light->rtlight);
3468 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3472 // reset the count of frustum planes
3473 // see rtlight->cached_frustumplanes definition for how much this array
3475 rtlight->cached_numfrustumplanes = 0;
3477 // haven't implemented a culling path for ortho rendering
3478 if (!r_refdef.view.useperspective)
3480 // check if the light is on screen and copy the 4 planes if it is
3481 for (i = 0;i < 4;i++)
3482 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3485 for (i = 0;i < 4;i++)
3486 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3491 // generate a deformed frustum that includes the light origin, this is
3492 // used to cull shadow casting surfaces that can not possibly cast a
3493 // shadow onto the visible light-receiving surfaces, which can be a
3496 // if the light origin is onscreen the result will be 4 planes exactly
3497 // if the light origin is offscreen on only one axis the result will
3498 // be exactly 5 planes (split-side case)
3499 // if the light origin is offscreen on two axes the result will be
3500 // exactly 4 planes (stretched corner case)
3501 for (i = 0;i < 4;i++)
3503 // quickly reject standard frustum planes that put the light
3504 // origin outside the frustum
3505 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3508 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3510 // if all the standard frustum planes were accepted, the light is onscreen
3511 // otherwise we need to generate some more planes below...
3512 if (rtlight->cached_numfrustumplanes < 4)
3514 // at least one of the stock frustum planes failed, so we need to
3515 // create one or two custom planes to enclose the light origin
3516 for (i = 0;i < 4;i++)
3518 // create a plane using the view origin and light origin, and a
3519 // single point from the frustum corner set
3520 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3521 VectorNormalize(plane.normal);
3522 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3523 // see if this plane is backwards and flip it if so
3524 for (j = 0;j < 4;j++)
3525 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3529 VectorNegate(plane.normal, plane.normal);
3531 // flipped plane, test again to see if it is now valid
3532 for (j = 0;j < 4;j++)
3533 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3535 // if the plane is still not valid, then it is dividing the
3536 // frustum and has to be rejected
3540 // we have created a valid plane, compute extra info
3541 PlaneClassify(&plane);
3543 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3545 // if we've found 5 frustum planes then we have constructed a
3546 // proper split-side case and do not need to keep searching for
3547 // planes to enclose the light origin
3548 if (rtlight->cached_numfrustumplanes == 5)
3556 for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
3558 plane = rtlight->cached_frustumplanes[i];
3559 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));
3564 // now add the light-space box planes if the light box is rotated, as any
3565 // caster outside the oriented light box is irrelevant (even if it passed
3566 // the worldspace light box, which is axial)
3567 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3569 for (i = 0;i < 6;i++)
3573 v[i >> 1] = (i & 1) ? -1 : 1;
3574 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3575 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3576 plane.dist = VectorNormalizeLength(plane.normal);
3577 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3578 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3584 // add the world-space reduced box planes
3585 for (i = 0;i < 6;i++)
3587 VectorClear(plane.normal);
3588 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3589 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
3590 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3599 // reduce all plane distances to tightly fit the rtlight cull box, which
3601 VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3602 VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3603 VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3604 VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3605 VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3606 VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3607 VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3608 VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3609 oldnum = rtlight->cached_numfrustumplanes;
3610 rtlight->cached_numfrustumplanes = 0;
3611 for (j = 0;j < oldnum;j++)
3613 // find the nearest point on the box to this plane
3614 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
3615 for (i = 1;i < 8;i++)
3617 dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
3618 if (bestdist > dist)
3621 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);
3622 // if the nearest point is near or behind the plane, we want this
3623 // plane, otherwise the plane is useless as it won't cull anything
3624 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
3626 PlaneClassify(&rtlight->cached_frustumplanes[j]);
3627 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
3634 void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
3638 RSurf_ActiveWorldEntity();
3640 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3643 GL_CullFace(GL_NONE);
3644 mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3645 for (;mesh;mesh = mesh->next)
3647 if (!mesh->sidetotals[r_shadow_shadowmapside])
3649 r_refdef.stats.lights_shadowtriangles += mesh->sidetotals[r_shadow_shadowmapside];
3650 if (mesh->vertex3fbuffer)
3651 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vertex3fbuffer);
3653 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer);
3654 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);
3658 else if (r_refdef.scene.worldentity->model)
3659 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);
3661 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3664 void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3666 qboolean zpass = false;
3669 int surfacelistindex;
3670 msurface_t *surface;
3672 // if triangle neighbors are disabled, shadowvolumes are disabled
3673 if (r_refdef.scene.worldmodel->brush.shadowmesh ? !r_refdef.scene.worldmodel->brush.shadowmesh->neighbor3i : !r_refdef.scene.worldmodel->surfmesh.data_neighbor3i)
3676 RSurf_ActiveWorldEntity();
3678 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3681 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
3683 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
3684 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
3686 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
3687 for (;mesh;mesh = mesh->next)
3689 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
3690 if (mesh->vertex3fbuffer)
3691 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vertex3fbuffer);
3693 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer);
3694 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
3696 // increment stencil if frontface is infront of depthbuffer
3697 GL_CullFace(r_refdef.view.cullface_back);
3698 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
3699 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);
3700 // decrement stencil if backface is infront of depthbuffer
3701 GL_CullFace(r_refdef.view.cullface_front);
3702 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
3704 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
3706 // decrement stencil if backface is behind depthbuffer
3707 GL_CullFace(r_refdef.view.cullface_front);
3708 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
3709 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);
3710 // increment stencil if frontface is behind depthbuffer
3711 GL_CullFace(r_refdef.view.cullface_back);
3712 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
3714 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);
3718 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh)
3720 // use the shadow trispvs calculated earlier by GetLightInfo to cull world triangles on this dynamic light
3721 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
3722 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
3724 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
3725 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
3726 if (CHECKPVSBIT(trispvs, t))
3727 shadowmarklist[numshadowmark++] = t;
3729 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);
3731 else if (numsurfaces)
3733 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);
3736 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3739 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3741 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3742 vec_t relativeshadowradius;
3743 RSurf_ActiveModelEntity(ent, false, false, false);
3744 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3745 // we need to re-init the shader for each entity because the matrix changed
3746 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3747 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3748 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3749 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3750 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3751 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3752 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3753 switch (r_shadow_rendermode)
3755 case R_SHADOW_RENDERMODE_SHADOWMAP2D:
3756 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
3759 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3762 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3765 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3767 // set up properties for rendering light onto this entity
3768 RSurf_ActiveModelEntity(ent, true, true, false);
3769 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3770 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3771 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3772 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3775 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
3777 if (!r_refdef.scene.worldmodel->DrawLight)
3780 // set up properties for rendering light onto this entity
3781 RSurf_ActiveWorldEntity();
3782 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3783 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3784 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3785 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3787 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
3789 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3792 void R_Shadow_DrawEntityLight(entity_render_t *ent)
3794 dp_model_t *model = ent->model;
3795 if (!model->DrawLight)
3798 R_Shadow_SetupEntityLight(ent);
3800 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3802 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3805 void R_Shadow_PrepareLight(rtlight_t *rtlight)
3809 int numleafs, numsurfaces;
3810 int *leaflist, *surfacelist;
3811 unsigned char *leafpvs;
3812 unsigned char *shadowtrispvs;
3813 unsigned char *lighttrispvs;
3814 //unsigned char *surfacesides;
3815 int numlightentities;
3816 int numlightentities_noselfshadow;
3817 int numshadowentities;
3818 int numshadowentities_noselfshadow;
3819 static entity_render_t *lightentities[MAX_EDICTS];
3820 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3821 static entity_render_t *shadowentities[MAX_EDICTS];
3822 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3825 rtlight->draw = false;
3827 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3828 // skip lights that are basically invisible (color 0 0 0)
3829 nolight = VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f);
3831 // loading is done before visibility checks because loading should happen
3832 // all at once at the start of a level, not when it stalls gameplay.
3833 // (especially important to benchmarks)
3835 if (rtlight->isstatic && !nolight && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
3837 if (rtlight->compiled)
3838 R_RTLight_Uncompile(rtlight);
3839 R_RTLight_Compile(rtlight);
3843 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
3845 // look up the light style value at this time
3846 f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3847 VectorScale(rtlight->color, f, rtlight->currentcolor);
3849 if (rtlight->selected)
3851 f = 2 + sin(realtime * M_PI * 4.0);
3852 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3856 // if lightstyle is currently off, don't draw the light
3857 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3860 // skip processing on corona-only lights
3864 // if the light box is offscreen, skip it
3865 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3868 VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
3869 VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
3871 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3873 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3875 // compiled light, world available and can receive realtime lighting
3876 // retrieve leaf information
3877 numleafs = rtlight->static_numleafs;
3878 leaflist = rtlight->static_leaflist;
3879 leafpvs = rtlight->static_leafpvs;
3880 numsurfaces = rtlight->static_numsurfaces;
3881 surfacelist = rtlight->static_surfacelist;
3882 //surfacesides = NULL;
3883 shadowtrispvs = rtlight->static_shadowtrispvs;
3884 lighttrispvs = rtlight->static_lighttrispvs;
3886 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3888 // dynamic light, world available and can receive realtime lighting
3889 // calculate lit surfaces and leafs
3890 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);
3891 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3892 leaflist = r_shadow_buffer_leaflist;
3893 leafpvs = r_shadow_buffer_leafpvs;
3894 surfacelist = r_shadow_buffer_surfacelist;
3895 //surfacesides = r_shadow_buffer_surfacesides;
3896 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3897 lighttrispvs = r_shadow_buffer_lighttrispvs;
3898 // if the reduced leaf bounds are offscreen, skip it
3899 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3910 //surfacesides = NULL;
3911 shadowtrispvs = NULL;
3912 lighttrispvs = NULL;
3914 // check if light is illuminating any visible leafs
3917 for (i = 0;i < numleafs;i++)
3918 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3924 // make a list of lit entities and shadow casting entities
3925 numlightentities = 0;
3926 numlightentities_noselfshadow = 0;
3927 numshadowentities = 0;
3928 numshadowentities_noselfshadow = 0;
3930 // add dynamic entities that are lit by the light
3931 for (i = 0;i < r_refdef.scene.numentities;i++)
3934 entity_render_t *ent = r_refdef.scene.entities[i];
3936 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3938 // skip the object entirely if it is not within the valid
3939 // shadow-casting region (which includes the lit region)
3940 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
3942 if (!(model = ent->model))
3944 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
3946 // this entity wants to receive light, is visible, and is
3947 // inside the light box
3948 // TODO: check if the surfaces in the model can receive light
3949 // so now check if it's in a leaf seen by the light
3950 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))
3952 if (ent->flags & RENDER_NOSELFSHADOW)
3953 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
3955 lightentities[numlightentities++] = ent;
3956 // since it is lit, it probably also casts a shadow...
3957 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3958 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3959 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3961 // note: exterior models without the RENDER_NOSELFSHADOW
3962 // flag still create a RENDER_NOSELFSHADOW shadow but
3963 // are lit normally, this means that they are
3964 // self-shadowing but do not shadow other
3965 // RENDER_NOSELFSHADOW entities such as the gun
3966 // (very weird, but keeps the player shadow off the gun)
3967 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3968 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3970 shadowentities[numshadowentities++] = ent;
3973 else if (ent->flags & RENDER_SHADOW)
3975 // this entity is not receiving light, but may still need to
3977 // TODO: check if the surfaces in the model can cast shadow
3978 // now check if it is in a leaf seen by the light
3979 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))
3981 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3982 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3983 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3985 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3986 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3988 shadowentities[numshadowentities++] = ent;
3993 // return if there's nothing at all to light
3994 if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
3997 // count this light in the r_speeds
3998 r_refdef.stats.lights++;
4000 // flag it as worth drawing later
4001 rtlight->draw = true;
4003 // cache all the animated entities that cast a shadow but are not visible
4004 for (i = 0;i < numshadowentities;i++)
4005 if (!shadowentities[i]->animcache_vertex3f)
4006 R_AnimCache_GetEntity(shadowentities[i], false, false);
4007 for (i = 0;i < numshadowentities_noselfshadow;i++)
4008 if (!shadowentities_noselfshadow[i]->animcache_vertex3f)
4009 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
4011 // allocate some temporary memory for rendering this light later in the frame
4012 // reusable buffers need to be copied, static data can be used as-is
4013 rtlight->cached_numlightentities = numlightentities;
4014 rtlight->cached_numlightentities_noselfshadow = numlightentities_noselfshadow;
4015 rtlight->cached_numshadowentities = numshadowentities;
4016 rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
4017 rtlight->cached_numsurfaces = numsurfaces;
4018 rtlight->cached_lightentities = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
4019 rtlight->cached_lightentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
4020 rtlight->cached_shadowentities = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
4021 rtlight->cached_shadowentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
4022 if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
4024 int numshadowtrispvsbytes = (((r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles) + 7) >> 3);
4025 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
4026 rtlight->cached_shadowtrispvs = (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
4027 rtlight->cached_lighttrispvs = (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
4028 rtlight->cached_surfacelist = (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
4032 // compiled light data
4033 rtlight->cached_shadowtrispvs = shadowtrispvs;
4034 rtlight->cached_lighttrispvs = lighttrispvs;
4035 rtlight->cached_surfacelist = surfacelist;
4039 void R_Shadow_DrawLight(rtlight_t *rtlight)
4043 unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
4044 int numlightentities;
4045 int numlightentities_noselfshadow;
4046 int numshadowentities;
4047 int numshadowentities_noselfshadow;
4048 entity_render_t **lightentities;
4049 entity_render_t **lightentities_noselfshadow;
4050 entity_render_t **shadowentities;
4051 entity_render_t **shadowentities_noselfshadow;
4053 static unsigned char entitysides[MAX_EDICTS];
4054 static unsigned char entitysides_noselfshadow[MAX_EDICTS];
4055 vec3_t nearestpoint;
4057 qboolean castshadows;
4060 // check if we cached this light this frame (meaning it is worth drawing)
4064 numlightentities = rtlight->cached_numlightentities;
4065 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
4066 numshadowentities = rtlight->cached_numshadowentities;
4067 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
4068 numsurfaces = rtlight->cached_numsurfaces;
4069 lightentities = rtlight->cached_lightentities;
4070 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
4071 shadowentities = rtlight->cached_shadowentities;
4072 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
4073 shadowtrispvs = rtlight->cached_shadowtrispvs;
4074 lighttrispvs = rtlight->cached_lighttrispvs;
4075 surfacelist = rtlight->cached_surfacelist;
4077 // set up a scissor rectangle for this light
4078 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4081 // don't let sound skip if going slow
4082 if (r_refdef.scene.extraupdate)
4085 // make this the active rtlight for rendering purposes
4086 R_Shadow_RenderMode_ActiveLight(rtlight);
4088 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
4090 // optionally draw visible shape of the shadow volumes
4091 // for performance analysis by level designers
4092 R_Shadow_RenderMode_VisibleShadowVolumes();
4094 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
4095 for (i = 0;i < numshadowentities;i++)
4096 R_Shadow_DrawEntityShadow(shadowentities[i]);
4097 for (i = 0;i < numshadowentities_noselfshadow;i++)
4098 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
4099 R_Shadow_RenderMode_VisibleLighting(false, false);
4102 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
4104 // optionally draw the illuminated areas
4105 // for performance analysis by level designers
4106 R_Shadow_RenderMode_VisibleLighting(false, false);
4108 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4109 for (i = 0;i < numlightentities;i++)
4110 R_Shadow_DrawEntityLight(lightentities[i]);
4111 for (i = 0;i < numlightentities_noselfshadow;i++)
4112 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4115 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
4117 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
4118 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
4119 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
4120 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
4122 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance/rtlight->radius));
4123 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
4124 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
4126 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
4132 int receivermask = 0;
4133 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
4134 Matrix4x4_Abs(&radiustolight);
4136 r_shadow_shadowmaplod = 0;
4137 for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
4138 if ((r_shadow_shadowmapmaxsize >> i) > lodlinear)
4139 r_shadow_shadowmaplod = i;
4141 size = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
4143 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
4145 surfacesides = NULL;
4148 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
4150 castermask = rtlight->static_shadowmap_casters;
4151 receivermask = rtlight->static_shadowmap_receivers;
4155 surfacesides = r_shadow_buffer_surfacesides;
4156 for(i = 0;i < numsurfaces;i++)
4158 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
4159 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4160 castermask |= surfacesides[i];
4161 receivermask |= surfacesides[i];
4165 if (receivermask < 0x3F)
4167 for (i = 0;i < numlightentities;i++)
4168 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4169 if (receivermask < 0x3F)
4170 for(i = 0; i < numlightentities_noselfshadow;i++)
4171 receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4174 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
4178 for (i = 0;i < numshadowentities;i++)
4179 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
4180 for (i = 0;i < numshadowentities_noselfshadow;i++)
4181 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
4184 //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
4186 // render shadow casters into 6 sided depth texture
4187 for (side = 0;side < 6;side++) if (receivermask & (1 << side))
4189 R_Shadow_RenderMode_ShadowMap(side, receivermask, size);
4190 if (! (castermask & (1 << side))) continue;
4192 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
4193 for (i = 0;i < numshadowentities;i++) if (entitysides[i] & (1 << side))
4194 R_Shadow_DrawEntityShadow(shadowentities[i]);
4197 if (numlightentities_noselfshadow)
4199 // render lighting using the depth texture as shadowmap
4200 // draw lighting in the unmasked areas
4201 R_Shadow_RenderMode_Lighting(false, false, true);
4202 for (i = 0;i < numlightentities_noselfshadow;i++)
4203 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4206 // render shadow casters into 6 sided depth texture
4207 if (numshadowentities_noselfshadow)
4209 for (side = 0;side < 6;side++) if ((receivermask & castermask) & (1 << side))
4211 R_Shadow_RenderMode_ShadowMap(side, 0, size);
4212 for (i = 0;i < numshadowentities_noselfshadow;i++) if (entitysides_noselfshadow[i] & (1 << side))
4213 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
4217 // render lighting using the depth texture as shadowmap
4218 // draw lighting in the unmasked areas
4219 R_Shadow_RenderMode_Lighting(false, false, true);
4220 // draw lighting in the unmasked areas
4222 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4223 for (i = 0;i < numlightentities;i++)
4224 R_Shadow_DrawEntityLight(lightentities[i]);
4226 else if (castshadows && vid.stencil)
4228 // draw stencil shadow volumes to mask off pixels that are in shadow
4229 // so that they won't receive lighting
4230 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
4231 R_Shadow_ClearStencil();
4234 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
4235 for (i = 0;i < numshadowentities;i++)
4236 R_Shadow_DrawEntityShadow(shadowentities[i]);
4238 // draw lighting in the unmasked areas
4239 R_Shadow_RenderMode_Lighting(true, false, false);
4240 for (i = 0;i < numlightentities_noselfshadow;i++)
4241 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4243 for (i = 0;i < numshadowentities_noselfshadow;i++)
4244 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
4246 // draw lighting in the unmasked areas
4247 R_Shadow_RenderMode_Lighting(true, false, false);
4249 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4250 for (i = 0;i < numlightentities;i++)
4251 R_Shadow_DrawEntityLight(lightentities[i]);
4255 // draw lighting in the unmasked areas
4256 R_Shadow_RenderMode_Lighting(false, false, false);
4258 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4259 for (i = 0;i < numlightentities;i++)
4260 R_Shadow_DrawEntityLight(lightentities[i]);
4261 for (i = 0;i < numlightentities_noselfshadow;i++)
4262 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4265 if (r_shadow_usingdeferredprepass)
4267 // when rendering deferred lighting, we simply rasterize the box
4268 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
4269 R_Shadow_RenderMode_DrawDeferredLight(false, true);
4270 else if (castshadows && vid.stencil)
4271 R_Shadow_RenderMode_DrawDeferredLight(true, false);
4273 R_Shadow_RenderMode_DrawDeferredLight(false, false);
4277 static void R_Shadow_FreeDeferred(void)
4279 R_Mesh_DestroyFramebufferObject(r_shadow_prepassgeometryfbo);
4280 r_shadow_prepassgeometryfbo = 0;
4282 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusespecularfbo);
4283 r_shadow_prepasslightingdiffusespecularfbo = 0;
4285 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusefbo);
4286 r_shadow_prepasslightingdiffusefbo = 0;
4288 if (r_shadow_prepassgeometrydepthtexture)
4289 R_FreeTexture(r_shadow_prepassgeometrydepthtexture);
4290 r_shadow_prepassgeometrydepthtexture = NULL;
4292 if (r_shadow_prepassgeometrydepthcolortexture)
4293 R_FreeTexture(r_shadow_prepassgeometrydepthcolortexture);
4294 r_shadow_prepassgeometrydepthcolortexture = NULL;
4296 if (r_shadow_prepassgeometrynormalmaptexture)
4297 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
4298 r_shadow_prepassgeometrynormalmaptexture = NULL;
4300 if (r_shadow_prepasslightingdiffusetexture)
4301 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
4302 r_shadow_prepasslightingdiffusetexture = NULL;
4304 if (r_shadow_prepasslightingspeculartexture)
4305 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
4306 r_shadow_prepasslightingspeculartexture = NULL;
4309 void R_Shadow_DrawPrepass(void)
4317 entity_render_t *ent;
4318 float clearcolor[4];
4320 R_Mesh_ResetTextureState();
4322 GL_ColorMask(1,1,1,1);
4323 GL_BlendFunc(GL_ONE, GL_ZERO);
4326 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, r_shadow_prepassgeometrydepthcolortexture, NULL, NULL);
4327 Vector4Set(clearcolor, 0.5f,0.5f,0.5f,1.0f);
4328 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4329 if (r_timereport_active)
4330 R_TimeReport("prepasscleargeom");
4332 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
4333 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
4334 if (r_timereport_active)
4335 R_TimeReport("prepassworld");
4337 for (i = 0;i < r_refdef.scene.numentities;i++)
4339 if (!r_refdef.viewcache.entityvisible[i])
4341 ent = r_refdef.scene.entities[i];
4342 if (ent->model && ent->model->DrawPrepass != NULL)
4343 ent->model->DrawPrepass(ent);
4346 if (r_timereport_active)
4347 R_TimeReport("prepassmodels");
4349 GL_DepthMask(false);
4350 GL_ColorMask(1,1,1,1);
4353 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4354 Vector4Set(clearcolor, 0, 0, 0, 0);
4355 GL_Clear(GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
4356 if (r_timereport_active)
4357 R_TimeReport("prepassclearlit");
4359 R_Shadow_RenderMode_Begin();
4361 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4362 if (r_shadow_debuglight.integer >= 0)
4364 lightindex = r_shadow_debuglight.integer;
4365 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4366 if (light && (light->flags & flag) && light->rtlight.draw)
4367 R_Shadow_DrawLight(&light->rtlight);
4371 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4372 for (lightindex = 0;lightindex < range;lightindex++)
4374 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4375 if (light && (light->flags & flag) && light->rtlight.draw)
4376 R_Shadow_DrawLight(&light->rtlight);
4379 if (r_refdef.scene.rtdlight)
4380 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4381 if (r_refdef.scene.lights[lnum]->draw)
4382 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4384 R_Mesh_ResetRenderTargets();
4386 R_Shadow_RenderMode_End();
4388 if (r_timereport_active)
4389 R_TimeReport("prepasslights");
4392 void R_Shadow_DrawLightSprites(void);
4393 void R_Shadow_PrepareLights(void)
4403 if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4) ||
4404 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
4405 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20) ||
4406 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
4407 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
4408 r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
4409 R_Shadow_FreeShadowMaps();
4411 r_shadow_usingshadowmaportho = false;
4413 switch (vid.renderpath)
4415 case RENDERPATH_GL20:
4416 case RENDERPATH_D3D9:
4417 case RENDERPATH_D3D10:
4418 case RENDERPATH_D3D11:
4419 case RENDERPATH_SOFT:
4420 case RENDERPATH_GLES2:
4421 if (!r_shadow_deferred.integer || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_STENCIL || !vid.support.ext_framebuffer_object || vid.maxdrawbuffers < 2)
4423 r_shadow_usingdeferredprepass = false;
4424 if (r_shadow_prepass_width)
4425 R_Shadow_FreeDeferred();
4426 r_shadow_prepass_width = r_shadow_prepass_height = 0;
4430 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
4432 R_Shadow_FreeDeferred();
4434 r_shadow_usingdeferredprepass = true;
4435 r_shadow_prepass_width = vid.width;
4436 r_shadow_prepass_height = vid.height;
4437 r_shadow_prepassgeometrydepthtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "prepassgeometrydepthmap", vid.width, vid.height, 24, false);
4438 switch (vid.renderpath)
4440 case RENDERPATH_D3D9:
4441 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);
4446 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);
4447 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);
4448 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);
4450 // set up the geometry pass fbo (depth + normalmap)
4451 r_shadow_prepassgeometryfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4452 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, r_shadow_prepassgeometrydepthcolortexture, NULL, NULL);
4453 // render depth into one texture and normalmap into the other
4454 if (qglDrawBuffersARB)
4456 qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);CHECKGLERROR
4457 qglReadBuffer(GL_NONE);CHECKGLERROR
4458 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4459 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4461 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4462 Cvar_SetValueQuick(&r_shadow_deferred, 0);
4463 r_shadow_usingdeferredprepass = false;
4467 // set up the lighting pass fbo (diffuse + specular)
4468 r_shadow_prepasslightingdiffusespecularfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4469 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4470 // render diffuse into one texture and specular into another,
4471 // with depth and normalmap bound as textures,
4472 // with depth bound as attachment as well
4473 if (qglDrawBuffersARB)
4475 qglDrawBuffersARB(2, r_shadow_prepasslightingdrawbuffers);CHECKGLERROR
4476 qglReadBuffer(GL_NONE);CHECKGLERROR
4477 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4478 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4480 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4481 Cvar_SetValueQuick(&r_shadow_deferred, 0);
4482 r_shadow_usingdeferredprepass = false;
4486 // set up the lighting pass fbo (diffuse)
4487 r_shadow_prepasslightingdiffusefbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
4488 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
4489 // render diffuse into one texture,
4490 // with depth and normalmap bound as textures,
4491 // with depth bound as attachment as well
4492 if (qglDrawBuffersARB)
4494 qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);CHECKGLERROR
4495 qglReadBuffer(GL_NONE);CHECKGLERROR
4496 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4497 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4499 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4500 Cvar_SetValueQuick(&r_shadow_deferred, 0);
4501 r_shadow_usingdeferredprepass = false;
4506 case RENDERPATH_GL13:
4507 case RENDERPATH_GL11:
4508 r_shadow_usingdeferredprepass = false;
4512 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);
4514 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4515 if (r_shadow_debuglight.integer >= 0)
4517 lightindex = r_shadow_debuglight.integer;
4518 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4519 if (light && (light->flags & flag))
4520 R_Shadow_PrepareLight(&light->rtlight);
4524 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4525 for (lightindex = 0;lightindex < range;lightindex++)
4527 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4528 if (light && (light->flags & flag))
4529 R_Shadow_PrepareLight(&light->rtlight);
4532 if (r_refdef.scene.rtdlight)
4534 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4535 R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
4537 else if(gl_flashblend.integer)
4539 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4541 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
4542 f = (rtlight->style >= 0 ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4543 VectorScale(rtlight->color, f, rtlight->currentcolor);
4547 if (r_editlights.integer)
4548 R_Shadow_DrawLightSprites();
4550 R_Shadow_UpdateBounceGridTexture();
4553 void R_Shadow_DrawLights(void)
4561 R_Shadow_RenderMode_Begin();
4563 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4564 if (r_shadow_debuglight.integer >= 0)
4566 lightindex = r_shadow_debuglight.integer;
4567 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4568 if (light && (light->flags & flag))
4569 R_Shadow_DrawLight(&light->rtlight);
4573 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4574 for (lightindex = 0;lightindex < range;lightindex++)
4576 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4577 if (light && (light->flags & flag))
4578 R_Shadow_DrawLight(&light->rtlight);
4581 if (r_refdef.scene.rtdlight)
4582 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4583 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4585 R_Shadow_RenderMode_End();
4588 extern const float r_screenvertex3f[12];
4589 extern void R_SetupView(qboolean allowwaterclippingplane);
4590 extern void R_ResetViewRendering3D(void);
4591 extern void R_ResetViewRendering2D(void);
4592 extern cvar_t r_shadows;
4593 extern cvar_t r_shadows_darken;
4594 extern cvar_t r_shadows_drawafterrtlighting;
4595 extern cvar_t r_shadows_castfrombmodels;
4596 extern cvar_t r_shadows_throwdistance;
4597 extern cvar_t r_shadows_throwdirection;
4598 extern cvar_t r_shadows_focus;
4599 extern cvar_t r_shadows_shadowmapscale;
4601 void R_Shadow_PrepareModelShadows(void)
4604 float scale, size, radius, dot1, dot2;
4605 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
4606 entity_render_t *ent;
4608 if (!r_refdef.scene.numentities)
4611 switch (r_shadow_shadowmode)
4613 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4614 if (r_shadows.integer >= 2)
4617 case R_SHADOW_SHADOWMODE_STENCIL:
4618 for (i = 0;i < r_refdef.scene.numentities;i++)
4620 ent = r_refdef.scene.entities[i];
4621 if (!ent->animcache_vertex3f && ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4622 R_AnimCache_GetEntity(ent, false, false);
4629 size = 2*r_shadow_shadowmapmaxsize;
4630 scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
4631 radius = 0.5f * size / scale;
4633 Math_atov(r_shadows_throwdirection.string, shadowdir);
4634 VectorNormalize(shadowdir);
4635 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4636 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4637 if (fabs(dot1) <= fabs(dot2))
4638 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4640 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4641 VectorNormalize(shadowforward);
4642 CrossProduct(shadowdir, shadowforward, shadowright);
4643 Math_atov(r_shadows_focus.string, shadowfocus);
4644 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4645 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4646 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4647 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4648 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4650 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4652 shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4653 shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4654 shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4655 shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4656 shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4657 shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4659 for (i = 0;i < r_refdef.scene.numentities;i++)
4661 ent = r_refdef.scene.entities[i];
4662 if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
4664 // cast shadows from anything of the map (submodels are optional)
4665 if (!ent->animcache_vertex3f && ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4666 R_AnimCache_GetEntity(ent, false, false);
4670 void R_DrawModelShadowMaps(void)
4673 float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
4674 entity_render_t *ent;
4675 vec3_t relativelightorigin;
4676 vec3_t relativelightdirection, relativeforward, relativeright;
4677 vec3_t relativeshadowmins, relativeshadowmaxs;
4678 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
4680 matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
4681 r_viewport_t viewport;
4683 float clearcolor[4];
4685 if (!r_refdef.scene.numentities)
4688 switch (r_shadow_shadowmode)
4690 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4696 R_ResetViewRendering3D();
4697 R_Shadow_RenderMode_Begin();
4698 R_Shadow_RenderMode_ActiveLight(NULL);
4700 switch (r_shadow_shadowmode)
4702 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4703 if (!r_shadow_shadowmap2dtexture)
4704 R_Shadow_MakeShadowMap(0, r_shadow_shadowmapmaxsize);
4705 fbo = r_shadow_fbo2d;
4706 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
4707 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
4708 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
4714 size = 2*r_shadow_shadowmapmaxsize;
4715 scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
4716 radius = 0.5f / scale;
4717 nearclip = -r_shadows_throwdistance.value;
4718 farclip = r_shadows_throwdistance.value;
4719 bias = r_shadow_shadowmapping_bias.value * r_shadow_shadowmapping_nearclip.value / (2 * r_shadows_throwdistance.value) * (1024.0f / size);
4721 r_shadow_shadowmap_parameters[0] = size;
4722 r_shadow_shadowmap_parameters[1] = size;
4723 r_shadow_shadowmap_parameters[2] = 1.0;
4724 r_shadow_shadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
4726 Math_atov(r_shadows_throwdirection.string, shadowdir);
4727 VectorNormalize(shadowdir);
4728 Math_atov(r_shadows_focus.string, shadowfocus);
4729 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4730 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4731 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4732 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4733 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4734 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4735 if (fabs(dot1) <= fabs(dot2))
4736 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4738 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4739 VectorNormalize(shadowforward);
4740 VectorM(scale, shadowforward, &m[0]);
4741 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4743 m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
4744 CrossProduct(shadowdir, shadowforward, shadowright);
4745 VectorM(scale, shadowright, &m[4]);
4746 m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
4747 VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
4748 m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
4749 Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
4750 Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
4751 R_Viewport_InitOrtho(&viewport, &cameramatrix, 0, 0, size, size, 0, 0, 1, 1, 0, -1, NULL);
4753 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4755 R_Mesh_SetRenderTargets(fbo, r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
4756 R_SetupShader_DepthOrShadow();
4757 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
4760 R_SetViewport(&viewport);
4761 GL_Scissor(viewport.x, viewport.y, min(viewport.width + r_shadow_shadowmapborder, 2*r_shadow_shadowmapmaxsize), viewport.height + r_shadow_shadowmapborder);
4762 Vector4Set(clearcolor, 1,1,1,1);
4763 // in D3D9 we have to render to a color texture shadowmap
4764 // in GL we render directly to a depth texture only
4765 if (r_shadow_shadowmap2dtexture)
4766 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4768 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4769 // render into a slightly restricted region so that the borders of the
4770 // shadowmap area fade away, rather than streaking across everything
4771 // outside the usable area
4772 GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
4776 R_Mesh_ResetRenderTargets();
4777 R_SetupShader_ShowDepth();
4778 GL_ColorMask(1,1,1,1);
4779 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4782 for (i = 0;i < r_refdef.scene.numentities;i++)
4784 ent = r_refdef.scene.entities[i];
4786 // cast shadows from anything of the map (submodels are optional)
4787 if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4789 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4790 Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
4791 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4792 Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
4793 Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
4794 relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4795 relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4796 relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4797 relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4798 relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4799 relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4800 RSurf_ActiveModelEntity(ent, false, false, false);
4801 ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
4802 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4809 unsigned char *rawpixels = Z_Malloc(viewport.width*viewport.height*4);
4811 qglReadPixels(viewport.x, viewport.y, viewport.width, viewport.height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, rawpixels);
4813 Image_WriteTGABGRA("r_shadows_2.tga", viewport.width, viewport.height, rawpixels);
4814 Cvar_SetValueQuick(&r_test, 0);
4819 R_Shadow_RenderMode_End();
4821 Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
4822 Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
4823 Matrix4x4_CreateScale3(&scalematrix, size, -size, 1);
4824 Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
4825 Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
4826 Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
4828 switch (vid.renderpath)
4830 case RENDERPATH_GL11:
4831 case RENDERPATH_GL13:
4832 case RENDERPATH_GL20:
4833 case RENDERPATH_SOFT:
4834 case RENDERPATH_GLES2:
4836 case RENDERPATH_D3D9:
4837 case RENDERPATH_D3D10:
4838 case RENDERPATH_D3D11:
4839 #ifdef OPENGL_ORIENTATION
4840 r_shadow_shadowmapmatrix.m[0][0] *= -1.0f;
4841 r_shadow_shadowmapmatrix.m[0][1] *= -1.0f;
4842 r_shadow_shadowmapmatrix.m[0][2] *= -1.0f;
4843 r_shadow_shadowmapmatrix.m[0][3] *= -1.0f;
4845 r_shadow_shadowmapmatrix.m[0][0] *= -1.0f;
4846 r_shadow_shadowmapmatrix.m[1][0] *= -1.0f;
4847 r_shadow_shadowmapmatrix.m[2][0] *= -1.0f;
4848 r_shadow_shadowmapmatrix.m[3][0] *= -1.0f;
4853 r_shadow_usingshadowmaportho = true;
4854 switch (r_shadow_shadowmode)
4856 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4857 r_shadow_usingshadowmap2d = true;
4864 void R_DrawModelShadows(void)
4867 float relativethrowdistance;
4868 entity_render_t *ent;
4869 vec3_t relativelightorigin;
4870 vec3_t relativelightdirection;
4871 vec3_t relativeshadowmins, relativeshadowmaxs;
4872 vec3_t tmp, shadowdir;
4874 if (!r_refdef.scene.numentities || !vid.stencil || (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL && r_shadows.integer != 1))
4877 R_ResetViewRendering3D();
4878 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4879 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4880 R_Shadow_RenderMode_Begin();
4881 R_Shadow_RenderMode_ActiveLight(NULL);
4882 r_shadow_lightscissor[0] = r_refdef.view.x;
4883 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
4884 r_shadow_lightscissor[2] = r_refdef.view.width;
4885 r_shadow_lightscissor[3] = r_refdef.view.height;
4886 R_Shadow_RenderMode_StencilShadowVolumes(false);
4889 if (r_shadows.integer == 2)
4891 Math_atov(r_shadows_throwdirection.string, shadowdir);
4892 VectorNormalize(shadowdir);
4895 R_Shadow_ClearStencil();
4897 for (i = 0;i < r_refdef.scene.numentities;i++)
4899 ent = r_refdef.scene.entities[i];
4901 // cast shadows from anything of the map (submodels are optional)
4902 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4904 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4905 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
4906 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
4907 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
4908 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4911 if(ent->entitynumber != 0)
4913 if(ent->entitynumber >= MAX_EDICTS) // csqc entity
4915 // FIXME handle this
4916 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4920 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
4921 int entnum, entnum2, recursion;
4922 entnum = entnum2 = ent->entitynumber;
4923 for(recursion = 32; recursion > 0; --recursion)
4925 entnum2 = cl.entities[entnum].state_current.tagentity;
4926 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
4931 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
4933 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
4934 // transform into modelspace of OUR entity
4935 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
4936 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
4939 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4943 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4946 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
4947 RSurf_ActiveModelEntity(ent, false, false, false);
4948 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4949 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4953 // not really the right mode, but this will disable any silly stencil features
4954 R_Shadow_RenderMode_End();
4956 // set up ortho view for rendering this pass
4957 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4958 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4959 //GL_ScissorTest(true);
4960 //R_EntityMatrix(&identitymatrix);
4961 //R_Mesh_ResetTextureState();
4962 R_ResetViewRendering2D();
4964 // set up a darkening blend on shadowed areas
4965 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4966 //GL_DepthRange(0, 1);
4967 //GL_DepthTest(false);
4968 //GL_DepthMask(false);
4969 //GL_PolygonOffset(0, 0);CHECKGLERROR
4970 GL_Color(0, 0, 0, r_shadows_darken.value);
4971 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4972 //GL_DepthFunc(GL_ALWAYS);
4973 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_NOTEQUAL, 128, 255);
4975 // apply the blend to the shadowed areas
4976 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, NULL);
4977 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
4978 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4980 // restore the viewport
4981 R_SetViewport(&r_refdef.view.viewport);
4983 // restore other state to normal
4984 //R_Shadow_RenderMode_End();
4987 void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4990 vec3_t centerorigin;
4992 // if it's too close, skip it
4993 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
4995 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4998 if (usequery && r_numqueries + 2 <= r_maxqueries)
5000 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
5001 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
5002 // 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
5003 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
5005 switch(vid.renderpath)
5007 case RENDERPATH_GL20:
5008 case RENDERPATH_GL13:
5009 case RENDERPATH_GL11:
5010 case RENDERPATH_GLES2:
5012 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use GL_DepthFunc instead
5013 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
5014 GL_DepthFunc(GL_ALWAYS);
5015 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5016 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL);
5017 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5018 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
5019 GL_DepthFunc(GL_LEQUAL);
5020 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
5021 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5022 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL);
5023 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5024 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
5027 case RENDERPATH_D3D9:
5028 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5030 case RENDERPATH_D3D10:
5031 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5033 case RENDERPATH_D3D11:
5034 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5036 case RENDERPATH_SOFT:
5037 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5041 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
5044 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
5046 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
5049 GLint allpixels = 0, visiblepixels = 0;
5050 // now we have to check the query result
5051 if (rtlight->corona_queryindex_visiblepixels)
5053 switch(vid.renderpath)
5055 case RENDERPATH_GL20:
5056 case RENDERPATH_GL13:
5057 case RENDERPATH_GL11:
5058 case RENDERPATH_GLES2:
5060 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
5061 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
5064 case RENDERPATH_D3D9:
5065 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5067 case RENDERPATH_D3D10:
5068 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5070 case RENDERPATH_D3D11:
5071 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5073 case RENDERPATH_SOFT:
5074 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5077 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
5078 if (visiblepixels < 1 || allpixels < 1)
5080 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
5081 cscale *= rtlight->corona_visibility;
5085 // FIXME: these traces should scan all render entities instead of cl.world
5086 if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false, true).fraction < 1)
5089 VectorScale(rtlight->currentcolor, cscale, color);
5090 if (VectorLength(color) > (1.0f / 256.0f))
5093 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
5096 VectorNegate(color, color);
5097 switch(vid.renderpath)
5099 case RENDERPATH_GL11:
5100 case RENDERPATH_GL13:
5101 case RENDERPATH_GL20:
5102 case RENDERPATH_GLES2:
5103 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
5105 case RENDERPATH_D3D9:
5107 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_SUBTRACT);
5110 case RENDERPATH_D3D10:
5111 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5113 case RENDERPATH_D3D11:
5114 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5116 case RENDERPATH_SOFT:
5117 DPSOFTRAST_BlendSubtract(true);
5121 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5122 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);
5123 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5126 switch(vid.renderpath)
5128 case RENDERPATH_GL11:
5129 case RENDERPATH_GL13:
5130 case RENDERPATH_GL20:
5131 case RENDERPATH_GLES2:
5132 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
5134 case RENDERPATH_D3D9:
5136 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_ADD);
5139 case RENDERPATH_D3D10:
5140 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5142 case RENDERPATH_D3D11:
5143 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5145 case RENDERPATH_SOFT:
5146 DPSOFTRAST_BlendSubtract(false);
5153 void R_Shadow_DrawCoronas(void)
5156 qboolean usequery = false;
5161 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
5163 if (r_waterstate.renderingscene)
5165 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
5166 R_EntityMatrix(&identitymatrix);
5168 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5170 // check occlusion of coronas
5171 // use GL_ARB_occlusion_query if available
5172 // otherwise use raytraces
5174 switch (vid.renderpath)
5176 case RENDERPATH_GL11:
5177 case RENDERPATH_GL13:
5178 case RENDERPATH_GL20:
5179 case RENDERPATH_GLES2:
5180 usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
5183 GL_ColorMask(0,0,0,0);
5184 if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
5185 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
5188 r_maxqueries = (range + r_refdef.scene.numlights) * 4;
5189 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
5191 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
5194 RSurf_ActiveWorldEntity();
5195 GL_BlendFunc(GL_ONE, GL_ZERO);
5196 GL_CullFace(GL_NONE);
5197 GL_DepthMask(false);
5198 GL_DepthRange(0, 1);
5199 GL_PolygonOffset(0, 0);
5201 R_Mesh_ResetTextureState();
5202 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
5205 case RENDERPATH_D3D9:
5207 //Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5209 case RENDERPATH_D3D10:
5210 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5212 case RENDERPATH_D3D11:
5213 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5215 case RENDERPATH_SOFT:
5217 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5220 for (lightindex = 0;lightindex < range;lightindex++)
5222 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5225 rtlight = &light->rtlight;
5226 rtlight->corona_visibility = 0;
5227 rtlight->corona_queryindex_visiblepixels = 0;
5228 rtlight->corona_queryindex_allpixels = 0;
5229 if (!(rtlight->flags & flag))
5231 if (rtlight->corona <= 0)
5233 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
5235 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
5237 for (i = 0;i < r_refdef.scene.numlights;i++)
5239 rtlight = r_refdef.scene.lights[i];
5240 rtlight->corona_visibility = 0;
5241 rtlight->corona_queryindex_visiblepixels = 0;
5242 rtlight->corona_queryindex_allpixels = 0;
5243 if (!(rtlight->flags & flag))
5245 if (rtlight->corona <= 0)
5247 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
5250 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5252 // now draw the coronas using the query data for intensity info
5253 for (lightindex = 0;lightindex < range;lightindex++)
5255 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5258 rtlight = &light->rtlight;
5259 if (rtlight->corona_visibility <= 0)
5261 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
5263 for (i = 0;i < r_refdef.scene.numlights;i++)
5265 rtlight = r_refdef.scene.lights[i];
5266 if (rtlight->corona_visibility <= 0)
5268 if (gl_flashblend.integer)
5269 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
5271 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
5277 dlight_t *R_Shadow_NewWorldLight(void)
5279 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
5282 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)
5285 // validate parameters
5286 if (style < 0 || style >= MAX_LIGHTSTYLES)
5288 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
5294 // copy to light properties
5295 VectorCopy(origin, light->origin);
5296 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
5297 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
5298 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
5300 light->color[0] = max(color[0], 0);
5301 light->color[1] = max(color[1], 0);
5302 light->color[2] = max(color[2], 0);
5304 light->color[0] = color[0];
5305 light->color[1] = color[1];
5306 light->color[2] = color[2];
5307 light->radius = max(radius, 0);
5308 light->style = style;
5309 light->shadow = shadowenable;
5310 light->corona = corona;
5311 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
5312 light->coronasizescale = coronasizescale;
5313 light->ambientscale = ambientscale;
5314 light->diffusescale = diffusescale;
5315 light->specularscale = specularscale;
5316 light->flags = flags;
5318 // update renderable light data
5319 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
5320 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);
5323 void R_Shadow_FreeWorldLight(dlight_t *light)
5325 if (r_shadow_selectedlight == light)
5326 r_shadow_selectedlight = NULL;
5327 R_RTLight_Uncompile(&light->rtlight);
5328 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
5331 void R_Shadow_ClearWorldLights(void)
5335 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5336 for (lightindex = 0;lightindex < range;lightindex++)
5338 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5340 R_Shadow_FreeWorldLight(light);
5342 r_shadow_selectedlight = NULL;
5345 void R_Shadow_SelectLight(dlight_t *light)
5347 if (r_shadow_selectedlight)
5348 r_shadow_selectedlight->selected = false;
5349 r_shadow_selectedlight = light;
5350 if (r_shadow_selectedlight)
5351 r_shadow_selectedlight->selected = true;
5354 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
5356 // this is never batched (there can be only one)
5358 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
5359 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
5360 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5363 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
5368 skinframe_t *skinframe;
5371 // this is never batched (due to the ent parameter changing every time)
5372 // so numsurfaces == 1 and surfacelist[0] == lightnumber
5373 const dlight_t *light = (dlight_t *)ent;
5376 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
5379 VectorScale(light->color, intensity, spritecolor);
5380 if (VectorLength(spritecolor) < 0.1732f)
5381 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
5382 if (VectorLength(spritecolor) > 1.0f)
5383 VectorNormalize(spritecolor);
5385 // draw light sprite
5386 if (light->cubemapname[0] && !light->shadow)
5387 skinframe = r_editlights_sprcubemapnoshadowlight;
5388 else if (light->cubemapname[0])
5389 skinframe = r_editlights_sprcubemaplight;
5390 else if (!light->shadow)
5391 skinframe = r_editlights_sprnoshadowlight;
5393 skinframe = r_editlights_sprlight;
5395 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);
5396 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5398 // draw selection sprite if light is selected
5399 if (light->selected)
5401 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
5402 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5403 // VorteX todo: add normalmode/realtime mode light overlay sprites?
5407 void R_Shadow_DrawLightSprites(void)
5411 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5412 for (lightindex = 0;lightindex < range;lightindex++)
5414 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5416 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
5418 if (!r_editlights_lockcursor)
5419 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
5422 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
5427 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
5428 if (lightindex >= range)
5430 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5433 rtlight = &light->rtlight;
5434 //if (!(rtlight->flags & flag))
5436 VectorCopy(rtlight->shadoworigin, origin);
5437 *radius = rtlight->radius;
5438 VectorCopy(rtlight->color, color);
5442 void R_Shadow_SelectLightInView(void)
5444 float bestrating, rating, temp[3];
5448 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5452 if (r_editlights_lockcursor)
5454 for (lightindex = 0;lightindex < range;lightindex++)
5456 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5459 VectorSubtract(light->origin, r_refdef.view.origin, temp);
5460 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
5463 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
5464 if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false, true).fraction == 1.0f)
5466 bestrating = rating;
5471 R_Shadow_SelectLight(best);
5474 void R_Shadow_LoadWorldLights(void)
5476 int n, a, style, shadow, flags;
5477 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
5478 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
5479 if (cl.worldmodel == NULL)
5481 Con_Print("No map loaded.\n");
5484 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
5485 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5495 for (;COM_Parse(t, true) && strcmp(
5496 if (COM_Parse(t, true))
5498 if (com_token[0] == '!')
5501 origin[0] = atof(com_token+1);
5504 origin[0] = atof(com_token);
5509 while (*s && *s != '\n' && *s != '\r')
5515 // check for modifier flags
5522 #if _MSC_VER >= 1400
5523 #define sscanf sscanf_s
5525 cubemapname[sizeof(cubemapname)-1] = 0;
5526 #if MAX_QPATH != 128
5527 #error update this code if MAX_QPATH changes
5529 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
5530 #if _MSC_VER >= 1400
5531 , sizeof(cubemapname)
5533 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
5536 flags = LIGHTFLAG_REALTIMEMODE;
5544 coronasizescale = 0.25f;
5546 VectorClear(angles);
5549 if (a < 9 || !strcmp(cubemapname, "\"\""))
5551 // remove quotes on cubemapname
5552 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
5555 namelen = strlen(cubemapname) - 2;
5556 memmove(cubemapname, cubemapname + 1, namelen);
5557 cubemapname[namelen] = '\0';
5561 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);
5564 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5572 Con_Printf("invalid rtlights file \"%s\"\n", name);
5573 Mem_Free(lightsstring);
5577 void R_Shadow_SaveWorldLights(void)
5581 size_t bufchars, bufmaxchars;
5583 char name[MAX_QPATH];
5584 char line[MAX_INPUTLINE];
5585 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
5586 // I hate lines which are 3 times my screen size :( --blub
5589 if (cl.worldmodel == NULL)
5591 Con_Print("No map loaded.\n");
5594 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
5595 bufchars = bufmaxchars = 0;
5597 for (lightindex = 0;lightindex < range;lightindex++)
5599 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5602 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
5603 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);
5604 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
5605 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]);
5607 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);
5608 if (bufchars + strlen(line) > bufmaxchars)
5610 bufmaxchars = bufchars + strlen(line) + 2048;
5612 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
5616 memcpy(buf, oldbuf, bufchars);
5622 memcpy(buf + bufchars, line, strlen(line));
5623 bufchars += strlen(line);
5627 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
5632 void R_Shadow_LoadLightsFile(void)
5635 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
5636 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
5637 if (cl.worldmodel == NULL)
5639 Con_Print("No map loaded.\n");
5642 dpsnprintf(name, sizeof(name), "%s.lights", cl.worldnamenoextension);
5643 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5651 while (*s && *s != '\n' && *s != '\r')
5657 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);
5661 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);
5664 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
5665 radius = bound(15, radius, 4096);
5666 VectorScale(color, (2.0f / (8388608.0f)), color);
5667 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5675 Con_Printf("invalid lights file \"%s\"\n", name);
5676 Mem_Free(lightsstring);
5680 // tyrlite/hmap2 light types in the delay field
5681 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
5683 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
5695 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
5696 char key[256], value[MAX_INPUTLINE];
5698 if (cl.worldmodel == NULL)
5700 Con_Print("No map loaded.\n");
5703 // try to load a .ent file first
5704 dpsnprintf(key, sizeof(key), "%s.ent", cl.worldnamenoextension);
5705 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
5706 // and if that is not found, fall back to the bsp file entity string
5708 data = cl.worldmodel->brush.entities;
5711 for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
5713 type = LIGHTTYPE_MINUSX;
5714 origin[0] = origin[1] = origin[2] = 0;
5715 originhack[0] = originhack[1] = originhack[2] = 0;
5716 angles[0] = angles[1] = angles[2] = 0;
5717 color[0] = color[1] = color[2] = 1;
5718 light[0] = light[1] = light[2] = 1;light[3] = 300;
5719 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
5729 if (!COM_ParseToken_Simple(&data, false, false))
5731 if (com_token[0] == '}')
5732 break; // end of entity
5733 if (com_token[0] == '_')
5734 strlcpy(key, com_token + 1, sizeof(key));
5736 strlcpy(key, com_token, sizeof(key));
5737 while (key[strlen(key)-1] == ' ') // remove trailing spaces
5738 key[strlen(key)-1] = 0;
5739 if (!COM_ParseToken_Simple(&data, false, false))
5741 strlcpy(value, com_token, sizeof(value));
5743 // now that we have the key pair worked out...
5744 if (!strcmp("light", key))
5746 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5750 light[0] = vec[0] * (1.0f / 256.0f);
5751 light[1] = vec[0] * (1.0f / 256.0f);
5752 light[2] = vec[0] * (1.0f / 256.0f);
5758 light[0] = vec[0] * (1.0f / 255.0f);
5759 light[1] = vec[1] * (1.0f / 255.0f);
5760 light[2] = vec[2] * (1.0f / 255.0f);
5764 else if (!strcmp("delay", key))
5766 else if (!strcmp("origin", key))
5767 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5768 else if (!strcmp("angle", key))
5769 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5770 else if (!strcmp("angles", key))
5771 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5772 else if (!strcmp("color", key))
5773 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5774 else if (!strcmp("wait", key))
5775 fadescale = atof(value);
5776 else if (!strcmp("classname", key))
5778 if (!strncmp(value, "light", 5))
5781 if (!strcmp(value, "light_fluoro"))
5786 overridecolor[0] = 1;
5787 overridecolor[1] = 1;
5788 overridecolor[2] = 1;
5790 if (!strcmp(value, "light_fluorospark"))
5795 overridecolor[0] = 1;
5796 overridecolor[1] = 1;
5797 overridecolor[2] = 1;
5799 if (!strcmp(value, "light_globe"))
5804 overridecolor[0] = 1;
5805 overridecolor[1] = 0.8;
5806 overridecolor[2] = 0.4;
5808 if (!strcmp(value, "light_flame_large_yellow"))
5813 overridecolor[0] = 1;
5814 overridecolor[1] = 0.5;
5815 overridecolor[2] = 0.1;
5817 if (!strcmp(value, "light_flame_small_yellow"))
5822 overridecolor[0] = 1;
5823 overridecolor[1] = 0.5;
5824 overridecolor[2] = 0.1;
5826 if (!strcmp(value, "light_torch_small_white"))
5831 overridecolor[0] = 1;
5832 overridecolor[1] = 0.5;
5833 overridecolor[2] = 0.1;
5835 if (!strcmp(value, "light_torch_small_walltorch"))
5840 overridecolor[0] = 1;
5841 overridecolor[1] = 0.5;
5842 overridecolor[2] = 0.1;
5846 else if (!strcmp("style", key))
5847 style = atoi(value);
5848 else if (!strcmp("skin", key))
5849 skin = (int)atof(value);
5850 else if (!strcmp("pflags", key))
5851 pflags = (int)atof(value);
5852 //else if (!strcmp("effects", key))
5853 // effects = (int)atof(value);
5854 else if (cl.worldmodel->type == mod_brushq3)
5856 if (!strcmp("scale", key))
5857 lightscale = atof(value);
5858 if (!strcmp("fade", key))
5859 fadescale = atof(value);
5864 if (lightscale <= 0)
5868 if (color[0] == color[1] && color[0] == color[2])
5870 color[0] *= overridecolor[0];
5871 color[1] *= overridecolor[1];
5872 color[2] *= overridecolor[2];
5874 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5875 color[0] = color[0] * light[0];
5876 color[1] = color[1] * light[1];
5877 color[2] = color[2] * light[2];
5880 case LIGHTTYPE_MINUSX:
5882 case LIGHTTYPE_RECIPX:
5884 VectorScale(color, (1.0f / 16.0f), color);
5886 case LIGHTTYPE_RECIPXX:
5888 VectorScale(color, (1.0f / 16.0f), color);
5891 case LIGHTTYPE_NONE:
5895 case LIGHTTYPE_MINUSXX:
5898 VectorAdd(origin, originhack, origin);
5900 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);
5903 Mem_Free(entfiledata);
5907 void R_Shadow_SetCursorLocationForView(void)
5910 vec3_t dest, endpos;
5912 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5913 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false, true);
5914 if (trace.fraction < 1)
5916 dist = trace.fraction * r_editlights_cursordistance.value;
5917 push = r_editlights_cursorpushback.value;
5921 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5922 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5926 VectorClear( endpos );
5928 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5929 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5930 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5933 void R_Shadow_UpdateWorldLightSelection(void)
5935 if (r_editlights.integer)
5937 R_Shadow_SetCursorLocationForView();
5938 R_Shadow_SelectLightInView();
5941 R_Shadow_SelectLight(NULL);
5944 void R_Shadow_EditLights_Clear_f(void)
5946 R_Shadow_ClearWorldLights();
5949 void R_Shadow_EditLights_Reload_f(void)
5953 strlcpy(r_shadow_mapname, cl.worldname, sizeof(r_shadow_mapname));
5954 R_Shadow_ClearWorldLights();
5955 R_Shadow_LoadWorldLights();
5956 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5958 R_Shadow_LoadLightsFile();
5959 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5960 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5964 void R_Shadow_EditLights_Save_f(void)
5968 R_Shadow_SaveWorldLights();
5971 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
5973 R_Shadow_ClearWorldLights();
5974 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5977 void R_Shadow_EditLights_ImportLightsFile_f(void)
5979 R_Shadow_ClearWorldLights();
5980 R_Shadow_LoadLightsFile();
5983 void R_Shadow_EditLights_Spawn_f(void)
5986 if (!r_editlights.integer)
5988 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5991 if (Cmd_Argc() != 1)
5993 Con_Print("r_editlights_spawn does not take parameters\n");
5996 color[0] = color[1] = color[2] = 1;
5997 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
6000 void R_Shadow_EditLights_Edit_f(void)
6002 vec3_t origin, angles, color;
6003 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
6004 int style, shadows, flags, normalmode, realtimemode;
6005 char cubemapname[MAX_INPUTLINE];
6006 if (!r_editlights.integer)
6008 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6011 if (!r_shadow_selectedlight)
6013 Con_Print("No selected light.\n");
6016 VectorCopy(r_shadow_selectedlight->origin, origin);
6017 VectorCopy(r_shadow_selectedlight->angles, angles);
6018 VectorCopy(r_shadow_selectedlight->color, color);
6019 radius = r_shadow_selectedlight->radius;
6020 style = r_shadow_selectedlight->style;
6021 if (r_shadow_selectedlight->cubemapname)
6022 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
6025 shadows = r_shadow_selectedlight->shadow;
6026 corona = r_shadow_selectedlight->corona;
6027 coronasizescale = r_shadow_selectedlight->coronasizescale;
6028 ambientscale = r_shadow_selectedlight->ambientscale;
6029 diffusescale = r_shadow_selectedlight->diffusescale;
6030 specularscale = r_shadow_selectedlight->specularscale;
6031 flags = r_shadow_selectedlight->flags;
6032 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
6033 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
6034 if (!strcmp(Cmd_Argv(1), "origin"))
6036 if (Cmd_Argc() != 5)
6038 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6041 origin[0] = atof(Cmd_Argv(2));
6042 origin[1] = atof(Cmd_Argv(3));
6043 origin[2] = atof(Cmd_Argv(4));
6045 else if (!strcmp(Cmd_Argv(1), "originx"))
6047 if (Cmd_Argc() != 3)
6049 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6052 origin[0] = atof(Cmd_Argv(2));
6054 else if (!strcmp(Cmd_Argv(1), "originy"))
6056 if (Cmd_Argc() != 3)
6058 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6061 origin[1] = atof(Cmd_Argv(2));
6063 else if (!strcmp(Cmd_Argv(1), "originz"))
6065 if (Cmd_Argc() != 3)
6067 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6070 origin[2] = atof(Cmd_Argv(2));
6072 else if (!strcmp(Cmd_Argv(1), "move"))
6074 if (Cmd_Argc() != 5)
6076 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6079 origin[0] += atof(Cmd_Argv(2));
6080 origin[1] += atof(Cmd_Argv(3));
6081 origin[2] += atof(Cmd_Argv(4));
6083 else if (!strcmp(Cmd_Argv(1), "movex"))
6085 if (Cmd_Argc() != 3)
6087 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6090 origin[0] += atof(Cmd_Argv(2));
6092 else if (!strcmp(Cmd_Argv(1), "movey"))
6094 if (Cmd_Argc() != 3)
6096 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6099 origin[1] += atof(Cmd_Argv(2));
6101 else if (!strcmp(Cmd_Argv(1), "movez"))
6103 if (Cmd_Argc() != 3)
6105 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6108 origin[2] += atof(Cmd_Argv(2));
6110 else if (!strcmp(Cmd_Argv(1), "angles"))
6112 if (Cmd_Argc() != 5)
6114 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6117 angles[0] = atof(Cmd_Argv(2));
6118 angles[1] = atof(Cmd_Argv(3));
6119 angles[2] = atof(Cmd_Argv(4));
6121 else if (!strcmp(Cmd_Argv(1), "anglesx"))
6123 if (Cmd_Argc() != 3)
6125 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6128 angles[0] = atof(Cmd_Argv(2));
6130 else if (!strcmp(Cmd_Argv(1), "anglesy"))
6132 if (Cmd_Argc() != 3)
6134 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6137 angles[1] = atof(Cmd_Argv(2));
6139 else if (!strcmp(Cmd_Argv(1), "anglesz"))
6141 if (Cmd_Argc() != 3)
6143 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6146 angles[2] = atof(Cmd_Argv(2));
6148 else if (!strcmp(Cmd_Argv(1), "color"))
6150 if (Cmd_Argc() != 5)
6152 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
6155 color[0] = atof(Cmd_Argv(2));
6156 color[1] = atof(Cmd_Argv(3));
6157 color[2] = atof(Cmd_Argv(4));
6159 else if (!strcmp(Cmd_Argv(1), "radius"))
6161 if (Cmd_Argc() != 3)
6163 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6166 radius = atof(Cmd_Argv(2));
6168 else if (!strcmp(Cmd_Argv(1), "colorscale"))
6170 if (Cmd_Argc() == 3)
6172 double scale = atof(Cmd_Argv(2));
6179 if (Cmd_Argc() != 5)
6181 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
6184 color[0] *= atof(Cmd_Argv(2));
6185 color[1] *= atof(Cmd_Argv(3));
6186 color[2] *= atof(Cmd_Argv(4));
6189 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
6191 if (Cmd_Argc() != 3)
6193 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6196 radius *= atof(Cmd_Argv(2));
6198 else if (!strcmp(Cmd_Argv(1), "style"))
6200 if (Cmd_Argc() != 3)
6202 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6205 style = atoi(Cmd_Argv(2));
6207 else if (!strcmp(Cmd_Argv(1), "cubemap"))
6211 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6214 if (Cmd_Argc() == 3)
6215 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
6219 else if (!strcmp(Cmd_Argv(1), "shadows"))
6221 if (Cmd_Argc() != 3)
6223 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6226 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
6228 else if (!strcmp(Cmd_Argv(1), "corona"))
6230 if (Cmd_Argc() != 3)
6232 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6235 corona = atof(Cmd_Argv(2));
6237 else if (!strcmp(Cmd_Argv(1), "coronasize"))
6239 if (Cmd_Argc() != 3)
6241 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6244 coronasizescale = atof(Cmd_Argv(2));
6246 else if (!strcmp(Cmd_Argv(1), "ambient"))
6248 if (Cmd_Argc() != 3)
6250 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6253 ambientscale = atof(Cmd_Argv(2));
6255 else if (!strcmp(Cmd_Argv(1), "diffuse"))
6257 if (Cmd_Argc() != 3)
6259 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6262 diffusescale = atof(Cmd_Argv(2));
6264 else if (!strcmp(Cmd_Argv(1), "specular"))
6266 if (Cmd_Argc() != 3)
6268 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6271 specularscale = atof(Cmd_Argv(2));
6273 else if (!strcmp(Cmd_Argv(1), "normalmode"))
6275 if (Cmd_Argc() != 3)
6277 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6280 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
6282 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
6284 if (Cmd_Argc() != 3)
6286 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6289 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
6293 Con_Print("usage: r_editlights_edit [property] [value]\n");
6294 Con_Print("Selected light's properties:\n");
6295 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
6296 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
6297 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
6298 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
6299 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
6300 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
6301 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
6302 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
6303 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
6304 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
6305 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
6306 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
6307 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
6308 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
6311 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
6312 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
6315 void R_Shadow_EditLights_EditAll_f(void)
6318 dlight_t *light, *oldselected;
6321 if (!r_editlights.integer)
6323 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
6327 oldselected = r_shadow_selectedlight;
6328 // EditLights doesn't seem to have a "remove" command or something so:
6329 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6330 for (lightindex = 0;lightindex < range;lightindex++)
6332 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6335 R_Shadow_SelectLight(light);
6336 R_Shadow_EditLights_Edit_f();
6338 // return to old selected (to not mess editing once selection is locked)
6339 R_Shadow_SelectLight(oldselected);
6342 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
6344 int lightnumber, lightcount;
6345 size_t lightindex, range;
6349 if (!r_editlights.integer)
6351 x = vid_conwidth.value - 240;
6353 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
6356 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6357 for (lightindex = 0;lightindex < range;lightindex++)
6359 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6362 if (light == r_shadow_selectedlight)
6363 lightnumber = lightindex;
6366 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;
6367 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;
6369 if (r_shadow_selectedlight == NULL)
6371 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;
6372 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;
6373 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;
6374 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;
6375 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;
6376 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;
6377 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;
6378 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;
6379 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;
6380 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;
6381 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;
6382 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;
6383 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;
6384 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;
6385 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;
6388 void R_Shadow_EditLights_ToggleShadow_f(void)
6390 if (!r_editlights.integer)
6392 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6395 if (!r_shadow_selectedlight)
6397 Con_Print("No selected light.\n");
6400 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);
6403 void R_Shadow_EditLights_ToggleCorona_f(void)
6405 if (!r_editlights.integer)
6407 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6410 if (!r_shadow_selectedlight)
6412 Con_Print("No selected light.\n");
6415 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);
6418 void R_Shadow_EditLights_Remove_f(void)
6420 if (!r_editlights.integer)
6422 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
6425 if (!r_shadow_selectedlight)
6427 Con_Print("No selected light.\n");
6430 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
6431 r_shadow_selectedlight = NULL;
6434 void R_Shadow_EditLights_Help_f(void)
6437 "Documentation on r_editlights system:\n"
6439 "r_editlights : enable/disable editing mode\n"
6440 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
6441 "r_editlights_cursorpushback : push back cursor this far from surface\n"
6442 "r_editlights_cursorpushoff : push cursor off surface this far\n"
6443 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
6444 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
6446 "r_editlights_help : this help\n"
6447 "r_editlights_clear : remove all lights\n"
6448 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
6449 "r_editlights_lock : lock selection to current light, if already locked - unlock\n"
6450 "r_editlights_save : save to .rtlights file\n"
6451 "r_editlights_spawn : create a light with default settings\n"
6452 "r_editlights_edit command : edit selected light - more documentation below\n"
6453 "r_editlights_remove : remove selected light\n"
6454 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
6455 "r_editlights_importlightentitiesfrommap : reload light entities\n"
6456 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
6458 "origin x y z : set light location\n"
6459 "originx x: set x component of light location\n"
6460 "originy y: set y component of light location\n"
6461 "originz z: set z component of light location\n"
6462 "move x y z : adjust light location\n"
6463 "movex x: adjust x component of light location\n"
6464 "movey y: adjust y component of light location\n"
6465 "movez z: adjust z component of light location\n"
6466 "angles x y z : set light angles\n"
6467 "anglesx x: set x component of light angles\n"
6468 "anglesy y: set y component of light angles\n"
6469 "anglesz z: set z component of light angles\n"
6470 "color r g b : set color of light (can be brighter than 1 1 1)\n"
6471 "radius radius : set radius (size) of light\n"
6472 "colorscale grey : multiply color of light (1 does nothing)\n"
6473 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
6474 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
6475 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
6476 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
6477 "cubemap basename : set filter cubemap of light (not yet supported)\n"
6478 "shadows 1/0 : turn on/off shadows\n"
6479 "corona n : set corona intensity\n"
6480 "coronasize n : set corona size (0-1)\n"
6481 "ambient n : set ambient intensity (0-1)\n"
6482 "diffuse n : set diffuse intensity (0-1)\n"
6483 "specular n : set specular intensity (0-1)\n"
6484 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
6485 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
6486 "<nothing> : print light properties to console\n"
6490 void R_Shadow_EditLights_CopyInfo_f(void)
6492 if (!r_editlights.integer)
6494 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
6497 if (!r_shadow_selectedlight)
6499 Con_Print("No selected light.\n");
6502 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
6503 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
6504 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
6505 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
6506 if (r_shadow_selectedlight->cubemapname)
6507 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
6509 r_shadow_bufferlight.cubemapname[0] = 0;
6510 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
6511 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
6512 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
6513 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
6514 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
6515 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
6516 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
6519 void R_Shadow_EditLights_PasteInfo_f(void)
6521 if (!r_editlights.integer)
6523 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
6526 if (!r_shadow_selectedlight)
6528 Con_Print("No selected light.\n");
6531 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);
6534 void R_Shadow_EditLights_Lock_f(void)
6536 if (!r_editlights.integer)
6538 Con_Print("Cannot lock on light when not in editing mode. Set r_editlights to 1.\n");
6541 if (r_editlights_lockcursor)
6543 r_editlights_lockcursor = false;
6546 if (!r_shadow_selectedlight)
6548 Con_Print("No selected light to lock on.\n");
6551 r_editlights_lockcursor = true;
6554 void R_Shadow_EditLights_Init(void)
6556 Cvar_RegisterVariable(&r_editlights);
6557 Cvar_RegisterVariable(&r_editlights_cursordistance);
6558 Cvar_RegisterVariable(&r_editlights_cursorpushback);
6559 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
6560 Cvar_RegisterVariable(&r_editlights_cursorgrid);
6561 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
6562 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
6563 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
6564 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)");
6565 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
6566 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
6567 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
6568 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)");
6569 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
6570 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
6571 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
6572 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
6573 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
6574 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
6575 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)");
6576 Cmd_AddCommand("r_editlights_lock", R_Shadow_EditLights_Lock_f, "lock selection to current light, if already locked - unlock");
6582 =============================================================================
6586 =============================================================================
6589 void R_CompleteLightPoint(vec3_t ambient, vec3_t diffuse, vec3_t lightdir, const vec3_t p, const int flags)
6591 int i, numlights, flag;
6594 float relativepoint[3];
6603 if (r_fullbright.integer)
6605 VectorSet(ambient, 1, 1, 1);
6606 VectorClear(diffuse);
6607 VectorClear(lightdir);
6611 if (flags & LP_LIGHTMAP)
6613 VectorSet(ambient, r_refdef.scene.ambient, r_refdef.scene.ambient, r_refdef.scene.ambient);
6614 VectorClear(diffuse);
6615 VectorClear(lightdir);
6616 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
6617 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambient, diffuse, lightdir);
6621 memset(sample, 0, sizeof(sample));
6622 VectorSet(sample, r_refdef.scene.ambient, r_refdef.scene.ambient, r_refdef.scene.ambient);
6624 if ((flags & LP_LIGHTMAP) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
6627 VectorClear(tempambient);
6629 VectorClear(relativepoint);
6630 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, tempambient, color, relativepoint);
6631 VectorScale(tempambient, r_refdef.lightmapintensity, tempambient);
6632 VectorScale(color, r_refdef.lightmapintensity, color);
6633 VectorAdd(sample, tempambient, sample);
6634 VectorMA(sample , 0.5f , color, sample );
6635 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
6636 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
6637 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
6638 // calculate a weighted average light direction as well
6639 intensity = VectorLength(color);
6640 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
6643 if (flags & LP_RTWORLD)
6645 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
6646 numlights = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
6647 for (i = 0; i < numlights; i++)
6649 dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
6652 light = &dlight->rtlight;
6653 if (!(light->flags & flag))
6656 lightradius2 = light->radius * light->radius;
6657 VectorSubtract(light->shadoworigin, p, relativepoint);
6658 dist2 = VectorLength2(relativepoint);
6659 if (dist2 >= lightradius2)
6661 dist = sqrt(dist2) / light->radius;
6662 intensity = min(1.0f, (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) * r_shadow_lightintensityscale.value;
6663 if (intensity <= 0.0f)
6665 if (light->shadow && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false, true).fraction < 1)
6667 // scale down intensity to add to both ambient and diffuse
6668 //intensity *= 0.5f;
6669 VectorNormalize(relativepoint);
6670 VectorScale(light->currentcolor, intensity, color);
6671 VectorMA(sample , 0.5f , color, sample );
6672 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
6673 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
6674 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
6675 // calculate a weighted average light direction as well
6676 intensity *= VectorLength(color);
6677 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
6681 if (flags & LP_DYNLIGHT)
6684 for (i = 0;i < r_refdef.scene.numlights;i++)
6686 light = r_refdef.scene.lights[i];
6688 lightradius2 = light->radius * light->radius;
6689 VectorSubtract(light->shadoworigin, p, relativepoint);
6690 dist2 = VectorLength2(relativepoint);
6691 if (dist2 >= lightradius2)
6693 dist = sqrt(dist2) / light->radius;
6694 intensity = (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist) * r_shadow_lightintensityscale.value;
6695 if (intensity <= 0.0f)
6697 if (light->shadow && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false, true).fraction < 1)
6699 // scale down intensity to add to both ambient and diffuse
6700 //intensity *= 0.5f;
6701 VectorNormalize(relativepoint);
6702 VectorScale(light->currentcolor, intensity, color);
6703 VectorMA(sample , 0.5f , color, sample );
6704 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
6705 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
6706 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
6707 // calculate a weighted average light direction as well
6708 intensity *= VectorLength(color);
6709 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
6713 // calculate the direction we'll use to reduce the sample to a directional light source
6714 VectorCopy(sample + 12, dir);
6715 //VectorSet(dir, sample[3] + sample[4] + sample[5], sample[6] + sample[7] + sample[8], sample[9] + sample[10] + sample[11]);
6716 VectorNormalize(dir);
6717 // extract the diffuse color along the chosen direction and scale it
6718 diffuse[0] = (dir[0]*sample[3] + dir[1]*sample[6] + dir[2]*sample[ 9] + sample[ 0]);
6719 diffuse[1] = (dir[0]*sample[4] + dir[1]*sample[7] + dir[2]*sample[10] + sample[ 1]);
6720 diffuse[2] = (dir[0]*sample[5] + dir[1]*sample[8] + dir[2]*sample[11] + sample[ 2]);
6721 // subtract some of diffuse from ambient
6722 VectorMA(sample, -0.333f, diffuse, ambient);
6723 // store the normalized lightdir
6724 VectorCopy(dir, lightdir);