3 Terminology: Stencil Shadow Volume (sometimes called Stencil Shadows)
4 An extrusion of the lit faces, beginning at the original geometry and ending
5 further from the light source than the original geometry (presumably at least
6 as far as the light's radius, if the light has a radius at all), capped at
7 both front and back to avoid any problems (extrusion from dark faces also
8 works but has a different set of problems)
10 This is normally rendered using Carmack's Reverse technique, in which
11 backfaces behind zbuffer (zfail) increment the stencil, and frontfaces behind
12 zbuffer (zfail) decrement the stencil, the result is a stencil value of zero
13 where shadows did not intersect the visible geometry, suitable as a stencil
14 mask for rendering lighting everywhere but shadow.
16 In our case to hopefully avoid the Creative Labs patent, we draw the backfaces
17 as decrement and the frontfaces as increment, and we redefine the DepthFunc to
18 GL_LESS (the patent uses GL_GEQUAL) which causes zfail when behind surfaces
19 and zpass when infront (the patent draws where zpass with a GL_GEQUAL test),
20 additionally we clear stencil to 128 to avoid the need for the unclamped
21 incr/decr extension (not related to patent).
24 This algorithm may be covered by Creative's patent (US Patent #6384822),
25 however that patent is quite specific about increment on backfaces and
26 decrement on frontfaces where zpass with GL_GEQUAL depth test, which is
27 opposite this implementation and partially opposite Carmack's Reverse paper
28 (which uses GL_LESS, but increments on backfaces and decrements on frontfaces).
32 Terminology: Stencil Light Volume (sometimes called Light Volumes)
33 Similar to a Stencil Shadow Volume, but inverted; rather than containing the
34 areas in shadow it contains the areas in light, this can only be built
35 quickly for certain limited cases (such as portal visibility from a point),
36 but is quite useful for some effects (sunlight coming from sky polygons is
37 one possible example, translucent occluders is another example).
41 Terminology: Optimized Stencil Shadow Volume
42 A Stencil Shadow Volume that has been processed sufficiently to ensure it has
43 no duplicate coverage of areas (no need to shadow an area twice), often this
44 greatly improves performance but is an operation too costly to use on moving
45 lights (however completely optimal Stencil Light Volumes can be constructed
50 Terminology: Per Pixel Lighting (sometimes abbreviated PPL)
51 Per pixel evaluation of lighting equations, at a bare minimum this involves
52 DOT3 shading of diffuse lighting (per pixel dotproduct of negated incidence
53 vector and surface normal, using a texture of the surface bumps, called a
54 NormalMap) if supported by hardware; in our case there is support for cards
55 which are incapable of DOT3, the quality is quite poor however. Additionally
56 it is desirable to have specular evaluation per pixel, per vertex
57 normalization of specular halfangle vectors causes noticable distortion but
58 is unavoidable on hardware without GL_ARB_fragment_program or
59 GL_ARB_fragment_shader.
63 Terminology: Normalization CubeMap
64 A cubemap containing normalized dot3-encoded (vectors of length 1 or less
65 encoded as RGB colors) for any possible direction, this technique allows per
66 pixel calculation of incidence vector for per pixel lighting purposes, which
67 would not otherwise be possible per pixel without GL_ARB_fragment_program or
68 GL_ARB_fragment_shader.
72 Terminology: 2D+1D Attenuation Texturing
73 A very crude approximation of light attenuation with distance which results
74 in cylindrical light shapes which fade vertically as a streak (some games
75 such as Doom3 allow this to be rotated to be less noticable in specific
76 cases), the technique is simply modulating lighting by two 2D textures (which
77 can be the same) on different axes of projection (XY and Z, typically), this
78 is the second best technique available without 3D Attenuation Texturing,
79 GL_ARB_fragment_program or GL_ARB_fragment_shader technology.
83 Terminology: 2D+1D Inverse Attenuation Texturing
84 A clever method described in papers on the Abducted engine, this has a squared
85 distance texture (bright on the outside, black in the middle), which is used
86 twice using GL_ADD blending, the result of this is used in an inverse modulate
87 (GL_ONE_MINUS_DST_ALPHA, GL_ZERO) to implement the equation
88 lighting*=(1-((X*X+Y*Y)+(Z*Z))) which is spherical (unlike 2D+1D attenuation
93 Terminology: 3D Attenuation Texturing
94 A slightly crude approximation of light attenuation with distance, its flaws
95 are limited radius and resolution (performance tradeoffs).
99 Terminology: 3D Attenuation-Normalization Texturing
100 A 3D Attenuation Texture merged with a Normalization CubeMap, by making the
101 vectors shorter the lighting becomes darker, a very effective optimization of
102 diffuse lighting if 3D Attenuation Textures are already used.
106 Terminology: Light Cubemap Filtering
107 A technique for modeling non-uniform light distribution according to
108 direction, for example a lantern may use a cubemap to describe the light
109 emission pattern of the cage around the lantern (as well as soot buildup
110 discoloring the light in certain areas), often also used for softened grate
111 shadows and light shining through a stained glass window (done crudely by
112 texturing the lighting with a cubemap), another good example would be a disco
113 light. This technique is used heavily in many games (Doom3 does not support
118 Terminology: Light Projection Filtering
119 A technique for modeling shadowing of light passing through translucent
120 surfaces, allowing stained glass windows and other effects to be done more
121 elegantly than possible with Light Cubemap Filtering by applying an occluder
122 texture to the lighting combined with a stencil light volume to limit the lit
123 area, this technique is used by Doom3 for spotlights and flashlights, among
124 other things, this can also be used more generally to render light passing
125 through multiple translucent occluders in a scene (using a light volume to
126 describe the area beyond the occluder, and thus mask off rendering of all
131 Terminology: Doom3 Lighting
132 A combination of Stencil Shadow Volume, Per Pixel Lighting, Normalization
133 CubeMap, 2D+1D Attenuation Texturing, and Light Projection Filtering, as
134 demonstrated by the game Doom3.
137 #include "quakedef.h"
138 #include "r_shadow.h"
139 #include "cl_collision.h"
142 #include "dpsoftrast.h"
146 extern LPDIRECT3DDEVICE9 vid_d3d9dev;
149 extern void R_Shadow_EditLights_Init(void);
151 typedef enum r_shadow_rendermode_e
153 R_SHADOW_RENDERMODE_NONE,
154 R_SHADOW_RENDERMODE_ZPASS_STENCIL,
155 R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL,
156 R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE,
157 R_SHADOW_RENDERMODE_ZFAIL_STENCIL,
158 R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL,
159 R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE,
160 R_SHADOW_RENDERMODE_LIGHT_VERTEX,
161 R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN,
162 R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN,
163 R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN,
164 R_SHADOW_RENDERMODE_LIGHT_GLSL,
165 R_SHADOW_RENDERMODE_VISIBLEVOLUMES,
166 R_SHADOW_RENDERMODE_VISIBLELIGHTING,
167 R_SHADOW_RENDERMODE_SHADOWMAP2D
169 r_shadow_rendermode_t;
171 typedef enum r_shadow_shadowmode_e
173 R_SHADOW_SHADOWMODE_STENCIL,
174 R_SHADOW_SHADOWMODE_SHADOWMAP2D
176 r_shadow_shadowmode_t;
178 r_shadow_rendermode_t r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
179 r_shadow_rendermode_t r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_NONE;
180 r_shadow_rendermode_t r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_NONE;
181 r_shadow_rendermode_t r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_NONE;
182 qboolean r_shadow_usingshadowmap2d;
183 qboolean r_shadow_usingshadowmaportho;
184 int r_shadow_shadowmapside;
185 float r_shadow_shadowmap_texturescale[2];
186 float r_shadow_shadowmap_parameters[4];
188 int r_shadow_drawbuffer;
189 int r_shadow_readbuffer;
191 int r_shadow_cullface_front, r_shadow_cullface_back;
192 GLuint r_shadow_fbo2d;
193 r_shadow_shadowmode_t r_shadow_shadowmode;
194 int r_shadow_shadowmapfilterquality;
195 int r_shadow_shadowmapdepthbits;
196 int r_shadow_shadowmapmaxsize;
197 qboolean r_shadow_shadowmapvsdct;
198 qboolean r_shadow_shadowmapsampler;
199 int r_shadow_shadowmappcf;
200 int r_shadow_shadowmapborder;
201 matrix4x4_t r_shadow_shadowmapmatrix;
202 int r_shadow_lightscissor[4];
203 qboolean r_shadow_usingdeferredprepass;
205 int maxshadowtriangles;
208 int maxshadowvertices;
209 float *shadowvertex3f;
219 unsigned char *shadowsides;
220 int *shadowsideslist;
227 int r_shadow_buffer_numleafpvsbytes;
228 unsigned char *r_shadow_buffer_visitingleafpvs;
229 unsigned char *r_shadow_buffer_leafpvs;
230 int *r_shadow_buffer_leaflist;
232 int r_shadow_buffer_numsurfacepvsbytes;
233 unsigned char *r_shadow_buffer_surfacepvs;
234 int *r_shadow_buffer_surfacelist;
235 unsigned char *r_shadow_buffer_surfacesides;
237 int r_shadow_buffer_numshadowtrispvsbytes;
238 unsigned char *r_shadow_buffer_shadowtrispvs;
239 int r_shadow_buffer_numlighttrispvsbytes;
240 unsigned char *r_shadow_buffer_lighttrispvs;
242 rtexturepool_t *r_shadow_texturepool;
243 rtexture_t *r_shadow_attenuationgradienttexture;
244 rtexture_t *r_shadow_attenuation2dtexture;
245 rtexture_t *r_shadow_attenuation3dtexture;
246 skinframe_t *r_shadow_lightcorona;
247 rtexture_t *r_shadow_shadowmap2dtexture;
248 rtexture_t *r_shadow_shadowmap2dcolortexture;
249 rtexture_t *r_shadow_shadowmapvsdcttexture;
250 int r_shadow_shadowmapsize; // changes for each light based on distance
251 int r_shadow_shadowmaplod; // changes for each light based on distance
253 GLuint r_shadow_prepassgeometryfbo;
254 GLuint r_shadow_prepasslightingdiffusespecularfbo;
255 GLuint r_shadow_prepasslightingdiffusefbo;
256 int r_shadow_prepass_width;
257 int r_shadow_prepass_height;
258 rtexture_t *r_shadow_prepassgeometrydepthtexture;
259 rtexture_t *r_shadow_prepassgeometrydepthcolortexture;
260 rtexture_t *r_shadow_prepassgeometrynormalmaptexture;
261 rtexture_t *r_shadow_prepasslightingdiffusetexture;
262 rtexture_t *r_shadow_prepasslightingspeculartexture;
264 // lights are reloaded when this changes
265 char r_shadow_mapname[MAX_QPATH];
267 // used only for light filters (cubemaps)
268 rtexturepool_t *r_shadow_filters_texturepool;
270 static const GLenum r_shadow_prepasslightingdrawbuffers[2] = {GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT};
272 cvar_t r_shadow_bumpscale_basetexture = {0, "r_shadow_bumpscale_basetexture", "0", "generate fake bumpmaps from diffuse textures at this bumpyness, try 4 to match tenebrae, higher values increase depth, requires r_restart to take effect"};
273 cvar_t r_shadow_bumpscale_bumpmap = {0, "r_shadow_bumpscale_bumpmap", "4", "what magnitude to interpret _bump.tga textures as, higher values increase depth, requires r_restart to take effect"};
274 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
275 cvar_t r_shadow_deferred = {CVAR_SAVE, "r_shadow_deferred", "0", "uses image-based lighting instead of geometry-based lighting, the method used renders a depth image and a normalmap image, renders lights into separate diffuse and specular images, and then combines this into the normal rendering, requires r_shadow_shadowmapping"};
276 cvar_t r_shadow_deferred_8bitrange = {CVAR_SAVE, "r_shadow_deferred_8bitrange", "2", "dynamic range of image-based lighting when using 32bit color (does not apply to fp)"};
277 //cvar_t r_shadow_deferred_fp = {CVAR_SAVE, "r_shadow_deferred_fp", "0", "use 16bit (1) or 32bit (2) floating point for accumulation of image-based lighting"};
278 cvar_t r_shadow_usebihculling = {0, "r_shadow_usebihculling", "1", "use BIH (Bounding Interval Hierarchy) for culling lit surfaces instead of BSP (Binary Space Partitioning)"};
279 cvar_t r_shadow_usenormalmap = {CVAR_SAVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"};
280 cvar_t r_shadow_gloss = {CVAR_SAVE, "r_shadow_gloss", "1", "0 disables gloss (specularity) rendering, 1 uses gloss if textures are found, 2 forces a flat metallic specular effect on everything without textures (similar to tenebrae)"};
281 cvar_t r_shadow_gloss2intensity = {0, "r_shadow_gloss2intensity", "0.125", "how bright the forced flat gloss should look if r_shadow_gloss is 2"};
282 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
283 cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
284 cvar_t r_shadow_gloss2exponent = {0, "r_shadow_gloss2exponent", "32", "same as r_shadow_glossexponent but for forced gloss (gloss 2) surfaces"};
285 cvar_t r_shadow_glossexact = {0, "r_shadow_glossexact", "0", "use exact reflection math for gloss (slightly slower, but should look a tad better)"};
286 cvar_t r_shadow_lightattenuationdividebias = {0, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"};
287 cvar_t r_shadow_lightattenuationlinearscale = {0, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"};
288 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
289 cvar_t r_shadow_lightradiusscale = {0, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
290 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "0", "how far to cast shadows"};
291 cvar_t r_shadow_frontsidecasting = {0, "r_shadow_frontsidecasting", "1", "whether to cast shadows from illuminated triangles (front side of model) or unlit triangles (back side of model)"};
292 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
293 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
294 cvar_t r_shadow_realtime_dlight_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
295 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
296 cvar_t r_shadow_realtime_world = {CVAR_SAVE, "r_shadow_realtime_world", "0", "enables rendering of full world lighting (whether loaded from the map, or a .rtlights file, or a .ent file, or a .lights file produced by hlight)"};
297 cvar_t r_shadow_realtime_world_lightmaps = {CVAR_SAVE, "r_shadow_realtime_world_lightmaps", "0", "brightness to render lightmaps when using full world lighting, try 0.5 for a tenebrae-like appearance"};
298 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
299 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
300 cvar_t r_shadow_realtime_world_compileshadow = {0, "r_shadow_realtime_world_compileshadow", "1", "enables compilation of shadows from world lights for higher performance rendering"};
301 cvar_t r_shadow_realtime_world_compilesvbsp = {0, "r_shadow_realtime_world_compilesvbsp", "1", "enables svbsp optimization during compilation (slower than compileportalculling but more exact)"};
302 cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "1", "enables portal-based culling optimization during compilation (overrides compilesvbsp)"};
303 cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1", "use scissor optimization of light rendering (restricts rendering to the portion of the screen affected by the light)"};
304 cvar_t r_shadow_shadowmapping = {CVAR_SAVE, "r_shadow_shadowmapping", "1", "enables use of shadowmapping (depth texture sampling) instead of stencil shadow volumes, requires gl_fbo 1"};
305 cvar_t r_shadow_shadowmapping_filterquality = {CVAR_SAVE, "r_shadow_shadowmapping_filterquality", "-1", "shadowmap filter modes: -1 = auto-select, 0 = no filtering, 1 = bilinear, 2 = bilinear 2x2 blur (fast), 3 = 3x3 blur (moderate), 4 = 4x4 blur (slow)"};
306 cvar_t r_shadow_shadowmapping_depthbits = {CVAR_SAVE, "r_shadow_shadowmapping_depthbits", "24", "requested minimum shadowmap texture depth bits"};
307 cvar_t r_shadow_shadowmapping_vsdct = {CVAR_SAVE, "r_shadow_shadowmapping_vsdct", "1", "enables use of virtual shadow depth cube texture"};
308 cvar_t r_shadow_shadowmapping_minsize = {CVAR_SAVE, "r_shadow_shadowmapping_minsize", "32", "shadowmap size limit"};
309 cvar_t r_shadow_shadowmapping_maxsize = {CVAR_SAVE, "r_shadow_shadowmapping_maxsize", "512", "shadowmap size limit"};
310 cvar_t r_shadow_shadowmapping_precision = {CVAR_SAVE, "r_shadow_shadowmapping_precision", "1", "makes shadowmaps have a maximum resolution of this number of pixels per light source radius unit such that, for example, at precision 0.5 a light with radius 200 will have a maximum resolution of 100 pixels"};
311 //cvar_t r_shadow_shadowmapping_lod_bias = {CVAR_SAVE, "r_shadow_shadowmapping_lod_bias", "16", "shadowmap size bias"};
312 //cvar_t r_shadow_shadowmapping_lod_scale = {CVAR_SAVE, "r_shadow_shadowmapping_lod_scale", "128", "shadowmap size scaling parameter"};
313 cvar_t r_shadow_shadowmapping_bordersize = {CVAR_SAVE, "r_shadow_shadowmapping_bordersize", "4", "shadowmap size bias for filtering"};
314 cvar_t r_shadow_shadowmapping_nearclip = {CVAR_SAVE, "r_shadow_shadowmapping_nearclip", "1", "shadowmap nearclip in world units"};
315 cvar_t r_shadow_shadowmapping_bias = {CVAR_SAVE, "r_shadow_shadowmapping_bias", "0.03", "shadowmap bias parameter (this is multiplied by nearclip * 1024 / lodsize)"};
316 cvar_t r_shadow_shadowmapping_polygonfactor = {CVAR_SAVE, "r_shadow_shadowmapping_polygonfactor", "2", "slope-dependent shadowmapping bias"};
317 cvar_t r_shadow_shadowmapping_polygonoffset = {CVAR_SAVE, "r_shadow_shadowmapping_polygonoffset", "0", "constant shadowmapping bias"};
318 cvar_t r_shadow_sortsurfaces = {0, "r_shadow_sortsurfaces", "1", "improve performance by sorting illuminated surfaces by texture"};
319 cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
320 cvar_t r_shadow_polygonoffset = {0, "r_shadow_polygonoffset", "1", "how much to push shadow volumes into the distance when rendering, to reduce chances of zfighting artifacts (should not be less than 0)"};
321 cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "1", "use 3D voxel textures for spherical attenuation rather than cylindrical (does not affect OpenGL 2.0 render path)"};
322 cvar_t r_shadow_bouncegrid = {CVAR_SAVE, "r_shadow_bouncegrid", "0", "perform particle tracing for indirect lighting (Global Illumination / radiosity) using a 3D texture covering the scene, requires r_shadow_realtime_world 1"};
323 cvar_t r_shadow_bouncegrid_bounceanglediffuse = {CVAR_SAVE, "r_shadow_bouncegrid_bounceanglediffuse", "0", "use random bounce direction rather than true reflection, makes some corner areas dark"};
324 cvar_t r_shadow_bouncegrid_dlightparticlemultiplier = {CVAR_SAVE, "r_shadow_bouncegrid_dlightparticlemultiplier", "0", "if set to a high value like 16 this can make dlights look great, but 0 is recommended for performance reasons"};
325 cvar_t r_shadow_bouncegrid_hitmodels = {CVAR_SAVE, "r_shadow_bouncegrid_hitmodels", "0", "enables hitting character model geometry (SLOW)"};
326 cvar_t r_shadow_bouncegrid_intensity = {CVAR_SAVE, "r_shadow_bouncegrid_intensity", "4", "overall brightness of bouncegrid texture"};
327 cvar_t r_shadow_bouncegrid_lightradiusscale = {CVAR_SAVE, "r_shadow_bouncegrid_lightradiusscale", "2", "particles stop at this fraction of light radius (can be more than 1)"};
328 cvar_t r_shadow_bouncegrid_maxbounce = {CVAR_SAVE, "r_shadow_bouncegrid_maxbounce", "3", "maximum number of bounces for a particle (minimum is 1)"};
329 cvar_t r_shadow_bouncegrid_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"};
330 cvar_t r_shadow_bouncegrid_particleintensity = {CVAR_SAVE, "r_shadow_bouncegrid_particleintensity", "2", "brightness of particles contributing to bouncegrid texture"};
331 cvar_t r_shadow_bouncegrid_photons = {CVAR_SAVE, "r_shadow_bouncegrid_photons", "2000", "total photons to shoot per update, divided proportionately between lights"};
332 cvar_t r_shadow_bouncegrid_spacingx = {CVAR_SAVE, "r_shadow_bouncegrid_spacingx", "64", "unit size of bouncegrid pixel on X axis"};
333 cvar_t r_shadow_bouncegrid_spacingy = {CVAR_SAVE, "r_shadow_bouncegrid_spacingy", "64", "unit size of bouncegrid pixel on Y axis"};
334 cvar_t r_shadow_bouncegrid_spacingz = {CVAR_SAVE, "r_shadow_bouncegrid_spacingz", "64", "unit size of bouncegrid pixel on Z axis"};
335 cvar_t r_shadow_bouncegrid_stablerandom = {CVAR_SAVE, "r_shadow_bouncegrid_stablerandom", "1", "make particle distribution consistent from frame to frame"};
336 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"};
337 cvar_t r_shadow_bouncegrid_x = {CVAR_SAVE, "r_shadow_bouncegrid_x", "64", "maximum texture size of bouncegrid on X axis"};
338 cvar_t r_shadow_bouncegrid_y = {CVAR_SAVE, "r_shadow_bouncegrid_y", "64", "maximum texture size of bouncegrid on Y axis"};
339 cvar_t r_shadow_bouncegrid_z = {CVAR_SAVE, "r_shadow_bouncegrid_z", "32", "maximum texture size of bouncegrid on Z axis"};
340 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "1", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
341 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"};
342 cvar_t r_coronas_occlusionquery = {CVAR_SAVE, "r_coronas_occlusionquery", "1", "use GL_ARB_occlusion_query extension if supported (fades coronas according to visibility)"};
343 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
344 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
345 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
346 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
347 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
348 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
349 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
350 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
351 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
353 rtexture_t *r_shadow_bouncegridtexture;
354 matrix4x4_t r_shadow_bouncegridmatrix;
355 vec_t r_shadow_bouncegridintensity;
356 static double r_shadow_bouncegridtime;
357 static int r_shadow_bouncegridresolution[3];
358 static int r_shadow_bouncegridnumpixels;
359 static unsigned char *r_shadow_bouncegridpixels;
360 static unsigned short *r_shadow_bouncegridhighpixels;
362 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
363 #define ATTENTABLESIZE 256
364 // 1D gradient, 2D circle and 3D sphere attenuation textures
365 #define ATTEN1DSIZE 32
366 #define ATTEN2DSIZE 64
367 #define ATTEN3DSIZE 32
369 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
370 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
371 static float r_shadow_attentable[ATTENTABLESIZE+1];
373 rtlight_t *r_shadow_compilingrtlight;
374 static memexpandablearray_t r_shadow_worldlightsarray;
375 dlight_t *r_shadow_selectedlight;
376 dlight_t r_shadow_bufferlight;
377 vec3_t r_editlights_cursorlocation;
378 qboolean r_editlights_lockcursor;
380 extern int con_vislines;
382 void R_Shadow_UncompileWorldLights(void);
383 void R_Shadow_ClearWorldLights(void);
384 void R_Shadow_SaveWorldLights(void);
385 void R_Shadow_LoadWorldLights(void);
386 void R_Shadow_LoadLightsFile(void);
387 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
388 void R_Shadow_EditLights_Reload_f(void);
389 void R_Shadow_ValidateCvars(void);
390 static void R_Shadow_MakeTextures(void);
392 #define EDLIGHTSPRSIZE 8
393 skinframe_t *r_editlights_sprcursor;
394 skinframe_t *r_editlights_sprlight;
395 skinframe_t *r_editlights_sprnoshadowlight;
396 skinframe_t *r_editlights_sprcubemaplight;
397 skinframe_t *r_editlights_sprcubemapnoshadowlight;
398 skinframe_t *r_editlights_sprselection;
400 void R_Shadow_SetShadowMode(void)
402 r_shadow_shadowmapmaxsize = bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4);
403 r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20;
404 r_shadow_shadowmapfilterquality = r_shadow_shadowmapping_filterquality.integer;
405 r_shadow_shadowmapdepthbits = r_shadow_shadowmapping_depthbits.integer;
406 r_shadow_shadowmapborder = bound(0, r_shadow_shadowmapping_bordersize.integer, 16);
407 r_shadow_shadowmaplod = -1;
408 r_shadow_shadowmapsize = 0;
409 r_shadow_shadowmapsampler = false;
410 r_shadow_shadowmappcf = 0;
411 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
412 if ((r_shadow_shadowmapping.integer || r_shadow_deferred.integer) && vid.support.ext_framebuffer_object)
414 switch(vid.renderpath)
416 case RENDERPATH_GL20:
417 if(r_shadow_shadowmapfilterquality < 0)
419 if(vid.support.amd_texture_texture4 || vid.support.arb_texture_gather)
420 r_shadow_shadowmappcf = 1;
421 else if(strstr(gl_vendor, "NVIDIA") || strstr(gl_renderer, "Radeon HD"))
423 r_shadow_shadowmapsampler = vid.support.arb_shadow;
424 r_shadow_shadowmappcf = 1;
426 else if(strstr(gl_vendor, "ATI"))
427 r_shadow_shadowmappcf = 1;
429 r_shadow_shadowmapsampler = vid.support.arb_shadow;
433 switch (r_shadow_shadowmapfilterquality)
436 r_shadow_shadowmapsampler = vid.support.arb_shadow;
439 r_shadow_shadowmapsampler = vid.support.arb_shadow;
440 r_shadow_shadowmappcf = 1;
443 r_shadow_shadowmappcf = 1;
446 r_shadow_shadowmappcf = 2;
450 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
452 case RENDERPATH_D3D9:
453 case RENDERPATH_D3D10:
454 case RENDERPATH_D3D11:
455 case RENDERPATH_SOFT:
456 r_shadow_shadowmapsampler = false;
457 r_shadow_shadowmappcf = 1;
458 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
460 case RENDERPATH_GL13:
462 case RENDERPATH_GL11:
464 case RENDERPATH_GLES2:
470 qboolean R_Shadow_ShadowMappingEnabled(void)
472 switch (r_shadow_shadowmode)
474 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
481 void R_Shadow_FreeShadowMaps(void)
483 R_Shadow_SetShadowMode();
485 R_Mesh_DestroyFramebufferObject(r_shadow_fbo2d);
489 if (r_shadow_shadowmap2dtexture)
490 R_FreeTexture(r_shadow_shadowmap2dtexture);
491 r_shadow_shadowmap2dtexture = NULL;
493 if (r_shadow_shadowmap2dcolortexture)
494 R_FreeTexture(r_shadow_shadowmap2dcolortexture);
495 r_shadow_shadowmap2dcolortexture = NULL;
497 if (r_shadow_shadowmapvsdcttexture)
498 R_FreeTexture(r_shadow_shadowmapvsdcttexture);
499 r_shadow_shadowmapvsdcttexture = NULL;
502 void r_shadow_start(void)
504 // allocate vertex processing arrays
505 r_shadow_bouncegridpixels = NULL;
506 r_shadow_bouncegridhighpixels = NULL;
507 r_shadow_bouncegridnumpixels = 0;
508 r_shadow_bouncegridtexture = NULL;
509 r_shadow_attenuationgradienttexture = NULL;
510 r_shadow_attenuation2dtexture = NULL;
511 r_shadow_attenuation3dtexture = NULL;
512 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
513 r_shadow_shadowmap2dtexture = NULL;
514 r_shadow_shadowmap2dcolortexture = NULL;
515 r_shadow_shadowmapvsdcttexture = NULL;
516 r_shadow_shadowmapmaxsize = 0;
517 r_shadow_shadowmapsize = 0;
518 r_shadow_shadowmaplod = 0;
519 r_shadow_shadowmapfilterquality = -1;
520 r_shadow_shadowmapdepthbits = 0;
521 r_shadow_shadowmapvsdct = false;
522 r_shadow_shadowmapsampler = false;
523 r_shadow_shadowmappcf = 0;
526 R_Shadow_FreeShadowMaps();
528 r_shadow_texturepool = NULL;
529 r_shadow_filters_texturepool = NULL;
530 R_Shadow_ValidateCvars();
531 R_Shadow_MakeTextures();
532 maxshadowtriangles = 0;
533 shadowelements = NULL;
534 maxshadowvertices = 0;
535 shadowvertex3f = NULL;
543 shadowmarklist = NULL;
548 shadowsideslist = NULL;
549 r_shadow_buffer_numleafpvsbytes = 0;
550 r_shadow_buffer_visitingleafpvs = NULL;
551 r_shadow_buffer_leafpvs = NULL;
552 r_shadow_buffer_leaflist = NULL;
553 r_shadow_buffer_numsurfacepvsbytes = 0;
554 r_shadow_buffer_surfacepvs = NULL;
555 r_shadow_buffer_surfacelist = NULL;
556 r_shadow_buffer_surfacesides = NULL;
557 r_shadow_buffer_numshadowtrispvsbytes = 0;
558 r_shadow_buffer_shadowtrispvs = NULL;
559 r_shadow_buffer_numlighttrispvsbytes = 0;
560 r_shadow_buffer_lighttrispvs = NULL;
562 r_shadow_usingdeferredprepass = false;
563 r_shadow_prepass_width = r_shadow_prepass_height = 0;
566 static void R_Shadow_FreeDeferred(void);
567 void r_shadow_shutdown(void)
570 R_Shadow_UncompileWorldLights();
572 R_Shadow_FreeShadowMaps();
574 r_shadow_usingdeferredprepass = false;
575 if (r_shadow_prepass_width)
576 R_Shadow_FreeDeferred();
577 r_shadow_prepass_width = r_shadow_prepass_height = 0;
580 r_shadow_bouncegridtexture = NULL;
581 r_shadow_bouncegridpixels = NULL;
582 r_shadow_bouncegridhighpixels = NULL;
583 r_shadow_bouncegridnumpixels = 0;
584 r_shadow_attenuationgradienttexture = NULL;
585 r_shadow_attenuation2dtexture = NULL;
586 r_shadow_attenuation3dtexture = NULL;
587 R_FreeTexturePool(&r_shadow_texturepool);
588 R_FreeTexturePool(&r_shadow_filters_texturepool);
589 maxshadowtriangles = 0;
591 Mem_Free(shadowelements);
592 shadowelements = NULL;
594 Mem_Free(shadowvertex3f);
595 shadowvertex3f = NULL;
598 Mem_Free(vertexupdate);
601 Mem_Free(vertexremap);
607 Mem_Free(shadowmark);
610 Mem_Free(shadowmarklist);
611 shadowmarklist = NULL;
616 Mem_Free(shadowsides);
619 Mem_Free(shadowsideslist);
620 shadowsideslist = NULL;
621 r_shadow_buffer_numleafpvsbytes = 0;
622 if (r_shadow_buffer_visitingleafpvs)
623 Mem_Free(r_shadow_buffer_visitingleafpvs);
624 r_shadow_buffer_visitingleafpvs = NULL;
625 if (r_shadow_buffer_leafpvs)
626 Mem_Free(r_shadow_buffer_leafpvs);
627 r_shadow_buffer_leafpvs = NULL;
628 if (r_shadow_buffer_leaflist)
629 Mem_Free(r_shadow_buffer_leaflist);
630 r_shadow_buffer_leaflist = NULL;
631 r_shadow_buffer_numsurfacepvsbytes = 0;
632 if (r_shadow_buffer_surfacepvs)
633 Mem_Free(r_shadow_buffer_surfacepvs);
634 r_shadow_buffer_surfacepvs = NULL;
635 if (r_shadow_buffer_surfacelist)
636 Mem_Free(r_shadow_buffer_surfacelist);
637 r_shadow_buffer_surfacelist = NULL;
638 if (r_shadow_buffer_surfacesides)
639 Mem_Free(r_shadow_buffer_surfacesides);
640 r_shadow_buffer_surfacesides = NULL;
641 r_shadow_buffer_numshadowtrispvsbytes = 0;
642 if (r_shadow_buffer_shadowtrispvs)
643 Mem_Free(r_shadow_buffer_shadowtrispvs);
644 r_shadow_buffer_numlighttrispvsbytes = 0;
645 if (r_shadow_buffer_lighttrispvs)
646 Mem_Free(r_shadow_buffer_lighttrispvs);
649 void r_shadow_newmap(void)
651 if (r_shadow_bouncegridtexture) R_FreeTexture(r_shadow_bouncegridtexture);r_shadow_bouncegridtexture = NULL;
652 if (r_shadow_lightcorona) R_SkinFrame_MarkUsed(r_shadow_lightcorona);
653 if (r_editlights_sprcursor) R_SkinFrame_MarkUsed(r_editlights_sprcursor);
654 if (r_editlights_sprlight) R_SkinFrame_MarkUsed(r_editlights_sprlight);
655 if (r_editlights_sprnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprnoshadowlight);
656 if (r_editlights_sprcubemaplight) R_SkinFrame_MarkUsed(r_editlights_sprcubemaplight);
657 if (r_editlights_sprcubemapnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprcubemapnoshadowlight);
658 if (r_editlights_sprselection) R_SkinFrame_MarkUsed(r_editlights_sprselection);
659 if (strncmp(cl.worldname, r_shadow_mapname, sizeof(r_shadow_mapname)))
660 R_Shadow_EditLights_Reload_f();
663 void R_Shadow_Init(void)
665 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
666 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
667 Cvar_RegisterVariable(&r_shadow_usebihculling);
668 Cvar_RegisterVariable(&r_shadow_usenormalmap);
669 Cvar_RegisterVariable(&r_shadow_debuglight);
670 Cvar_RegisterVariable(&r_shadow_deferred);
671 Cvar_RegisterVariable(&r_shadow_deferred_8bitrange);
672 // Cvar_RegisterVariable(&r_shadow_deferred_fp);
673 Cvar_RegisterVariable(&r_shadow_gloss);
674 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
675 Cvar_RegisterVariable(&r_shadow_glossintensity);
676 Cvar_RegisterVariable(&r_shadow_glossexponent);
677 Cvar_RegisterVariable(&r_shadow_gloss2exponent);
678 Cvar_RegisterVariable(&r_shadow_glossexact);
679 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
680 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
681 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
682 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
683 Cvar_RegisterVariable(&r_shadow_projectdistance);
684 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
685 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
686 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
687 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
688 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
689 Cvar_RegisterVariable(&r_shadow_realtime_world);
690 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
691 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
692 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
693 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
694 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
695 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
696 Cvar_RegisterVariable(&r_shadow_scissor);
697 Cvar_RegisterVariable(&r_shadow_shadowmapping);
698 Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
699 Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
700 Cvar_RegisterVariable(&r_shadow_shadowmapping_depthbits);
701 Cvar_RegisterVariable(&r_shadow_shadowmapping_precision);
702 Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
703 Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
704 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
705 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
706 Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
707 Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
708 Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
709 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonfactor);
710 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonoffset);
711 Cvar_RegisterVariable(&r_shadow_sortsurfaces);
712 Cvar_RegisterVariable(&r_shadow_polygonfactor);
713 Cvar_RegisterVariable(&r_shadow_polygonoffset);
714 Cvar_RegisterVariable(&r_shadow_texture3d);
715 Cvar_RegisterVariable(&r_shadow_bouncegrid);
716 Cvar_RegisterVariable(&r_shadow_bouncegrid_bounceanglediffuse);
717 Cvar_RegisterVariable(&r_shadow_bouncegrid_dlightparticlemultiplier);
718 Cvar_RegisterVariable(&r_shadow_bouncegrid_hitmodels);
719 Cvar_RegisterVariable(&r_shadow_bouncegrid_intensity);
720 Cvar_RegisterVariable(&r_shadow_bouncegrid_lightradiusscale);
721 Cvar_RegisterVariable(&r_shadow_bouncegrid_maxbounce);
722 Cvar_RegisterVariable(&r_shadow_bouncegrid_particlebounceintensity);
723 Cvar_RegisterVariable(&r_shadow_bouncegrid_particleintensity);
724 Cvar_RegisterVariable(&r_shadow_bouncegrid_photons);
725 Cvar_RegisterVariable(&r_shadow_bouncegrid_spacingx);
726 Cvar_RegisterVariable(&r_shadow_bouncegrid_spacingy);
727 Cvar_RegisterVariable(&r_shadow_bouncegrid_spacingz);
728 Cvar_RegisterVariable(&r_shadow_bouncegrid_stablerandom);
729 Cvar_RegisterVariable(&r_shadow_bouncegrid_updateinterval);
730 Cvar_RegisterVariable(&r_shadow_bouncegrid_x);
731 Cvar_RegisterVariable(&r_shadow_bouncegrid_y);
732 Cvar_RegisterVariable(&r_shadow_bouncegrid_z);
733 Cvar_RegisterVariable(&r_coronas);
734 Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
735 Cvar_RegisterVariable(&r_coronas_occlusionquery);
736 Cvar_RegisterVariable(&gl_flashblend);
737 Cvar_RegisterVariable(&gl_ext_separatestencil);
738 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
739 R_Shadow_EditLights_Init();
740 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
741 maxshadowtriangles = 0;
742 shadowelements = NULL;
743 maxshadowvertices = 0;
744 shadowvertex3f = NULL;
752 shadowmarklist = NULL;
757 shadowsideslist = NULL;
758 r_shadow_buffer_numleafpvsbytes = 0;
759 r_shadow_buffer_visitingleafpvs = NULL;
760 r_shadow_buffer_leafpvs = NULL;
761 r_shadow_buffer_leaflist = NULL;
762 r_shadow_buffer_numsurfacepvsbytes = 0;
763 r_shadow_buffer_surfacepvs = NULL;
764 r_shadow_buffer_surfacelist = NULL;
765 r_shadow_buffer_surfacesides = NULL;
766 r_shadow_buffer_shadowtrispvs = NULL;
767 r_shadow_buffer_lighttrispvs = NULL;
768 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap, NULL, NULL);
771 matrix4x4_t matrix_attenuationxyz =
774 {0.5, 0.0, 0.0, 0.5},
775 {0.0, 0.5, 0.0, 0.5},
776 {0.0, 0.0, 0.5, 0.5},
781 matrix4x4_t matrix_attenuationz =
784 {0.0, 0.0, 0.5, 0.5},
785 {0.0, 0.0, 0.0, 0.5},
786 {0.0, 0.0, 0.0, 0.5},
791 void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles, int vertscale, int triscale)
793 numvertices = ((numvertices + 255) & ~255) * vertscale;
794 numtriangles = ((numtriangles + 255) & ~255) * triscale;
795 // make sure shadowelements is big enough for this volume
796 if (maxshadowtriangles < numtriangles)
798 maxshadowtriangles = numtriangles;
800 Mem_Free(shadowelements);
801 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[3]));
803 // make sure shadowvertex3f is big enough for this volume
804 if (maxshadowvertices < numvertices)
806 maxshadowvertices = numvertices;
808 Mem_Free(shadowvertex3f);
809 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[3]));
813 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
815 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
816 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
817 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
818 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
819 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
821 if (r_shadow_buffer_visitingleafpvs)
822 Mem_Free(r_shadow_buffer_visitingleafpvs);
823 if (r_shadow_buffer_leafpvs)
824 Mem_Free(r_shadow_buffer_leafpvs);
825 if (r_shadow_buffer_leaflist)
826 Mem_Free(r_shadow_buffer_leaflist);
827 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
828 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
829 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
830 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
832 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
834 if (r_shadow_buffer_surfacepvs)
835 Mem_Free(r_shadow_buffer_surfacepvs);
836 if (r_shadow_buffer_surfacelist)
837 Mem_Free(r_shadow_buffer_surfacelist);
838 if (r_shadow_buffer_surfacesides)
839 Mem_Free(r_shadow_buffer_surfacesides);
840 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
841 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
842 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
843 r_shadow_buffer_surfacesides = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
845 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
847 if (r_shadow_buffer_shadowtrispvs)
848 Mem_Free(r_shadow_buffer_shadowtrispvs);
849 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
850 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
852 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
854 if (r_shadow_buffer_lighttrispvs)
855 Mem_Free(r_shadow_buffer_lighttrispvs);
856 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
857 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
861 void R_Shadow_PrepareShadowMark(int numtris)
863 // make sure shadowmark is big enough for this volume
864 if (maxshadowmark < numtris)
866 maxshadowmark = numtris;
868 Mem_Free(shadowmark);
870 Mem_Free(shadowmarklist);
871 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
872 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
876 // if shadowmarkcount wrapped we clear the array and adjust accordingly
877 if (shadowmarkcount == 0)
880 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
885 void R_Shadow_PrepareShadowSides(int numtris)
887 if (maxshadowsides < numtris)
889 maxshadowsides = numtris;
891 Mem_Free(shadowsides);
893 Mem_Free(shadowsideslist);
894 shadowsides = (unsigned char *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsides));
895 shadowsideslist = (int *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsideslist));
900 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)
903 int outtriangles = 0, outvertices = 0;
906 float ratio, direction[3], projectvector[3];
908 if (projectdirection)
909 VectorScale(projectdirection, projectdistance, projectvector);
911 VectorClear(projectvector);
913 // create the vertices
914 if (projectdirection)
916 for (i = 0;i < numshadowmarktris;i++)
918 element = inelement3i + shadowmarktris[i] * 3;
919 for (j = 0;j < 3;j++)
921 if (vertexupdate[element[j]] != vertexupdatenum)
923 vertexupdate[element[j]] = vertexupdatenum;
924 vertexremap[element[j]] = outvertices;
925 vertex = invertex3f + element[j] * 3;
926 // project one copy of the vertex according to projectvector
927 VectorCopy(vertex, outvertex3f);
928 VectorAdd(vertex, projectvector, (outvertex3f + 3));
937 for (i = 0;i < numshadowmarktris;i++)
939 element = inelement3i + shadowmarktris[i] * 3;
940 for (j = 0;j < 3;j++)
942 if (vertexupdate[element[j]] != vertexupdatenum)
944 vertexupdate[element[j]] = vertexupdatenum;
945 vertexremap[element[j]] = outvertices;
946 vertex = invertex3f + element[j] * 3;
947 // project one copy of the vertex to the sphere radius of the light
948 // (FIXME: would projecting it to the light box be better?)
949 VectorSubtract(vertex, projectorigin, direction);
950 ratio = projectdistance / VectorLength(direction);
951 VectorCopy(vertex, outvertex3f);
952 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
960 if (r_shadow_frontsidecasting.integer)
962 for (i = 0;i < numshadowmarktris;i++)
964 int remappedelement[3];
966 const int *neighbortriangle;
968 markindex = shadowmarktris[i] * 3;
969 element = inelement3i + markindex;
970 neighbortriangle = inneighbor3i + markindex;
971 // output the front and back triangles
972 outelement3i[0] = vertexremap[element[0]];
973 outelement3i[1] = vertexremap[element[1]];
974 outelement3i[2] = vertexremap[element[2]];
975 outelement3i[3] = vertexremap[element[2]] + 1;
976 outelement3i[4] = vertexremap[element[1]] + 1;
977 outelement3i[5] = vertexremap[element[0]] + 1;
981 // output the sides (facing outward from this triangle)
982 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
984 remappedelement[0] = vertexremap[element[0]];
985 remappedelement[1] = vertexremap[element[1]];
986 outelement3i[0] = remappedelement[1];
987 outelement3i[1] = remappedelement[0];
988 outelement3i[2] = remappedelement[0] + 1;
989 outelement3i[3] = remappedelement[1];
990 outelement3i[4] = remappedelement[0] + 1;
991 outelement3i[5] = remappedelement[1] + 1;
996 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
998 remappedelement[1] = vertexremap[element[1]];
999 remappedelement[2] = vertexremap[element[2]];
1000 outelement3i[0] = remappedelement[2];
1001 outelement3i[1] = remappedelement[1];
1002 outelement3i[2] = remappedelement[1] + 1;
1003 outelement3i[3] = remappedelement[2];
1004 outelement3i[4] = remappedelement[1] + 1;
1005 outelement3i[5] = remappedelement[2] + 1;
1010 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1012 remappedelement[0] = vertexremap[element[0]];
1013 remappedelement[2] = vertexremap[element[2]];
1014 outelement3i[0] = remappedelement[0];
1015 outelement3i[1] = remappedelement[2];
1016 outelement3i[2] = remappedelement[2] + 1;
1017 outelement3i[3] = remappedelement[0];
1018 outelement3i[4] = remappedelement[2] + 1;
1019 outelement3i[5] = remappedelement[0] + 1;
1028 for (i = 0;i < numshadowmarktris;i++)
1030 int remappedelement[3];
1032 const int *neighbortriangle;
1034 markindex = shadowmarktris[i] * 3;
1035 element = inelement3i + markindex;
1036 neighbortriangle = inneighbor3i + markindex;
1037 // output the front and back triangles
1038 outelement3i[0] = vertexremap[element[2]];
1039 outelement3i[1] = vertexremap[element[1]];
1040 outelement3i[2] = vertexremap[element[0]];
1041 outelement3i[3] = vertexremap[element[0]] + 1;
1042 outelement3i[4] = vertexremap[element[1]] + 1;
1043 outelement3i[5] = vertexremap[element[2]] + 1;
1047 // output the sides (facing outward from this triangle)
1048 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
1050 remappedelement[0] = vertexremap[element[0]];
1051 remappedelement[1] = vertexremap[element[1]];
1052 outelement3i[0] = remappedelement[0];
1053 outelement3i[1] = remappedelement[1];
1054 outelement3i[2] = remappedelement[1] + 1;
1055 outelement3i[3] = remappedelement[0];
1056 outelement3i[4] = remappedelement[1] + 1;
1057 outelement3i[5] = remappedelement[0] + 1;
1062 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1064 remappedelement[1] = vertexremap[element[1]];
1065 remappedelement[2] = vertexremap[element[2]];
1066 outelement3i[0] = remappedelement[1];
1067 outelement3i[1] = remappedelement[2];
1068 outelement3i[2] = remappedelement[2] + 1;
1069 outelement3i[3] = remappedelement[1];
1070 outelement3i[4] = remappedelement[2] + 1;
1071 outelement3i[5] = remappedelement[1] + 1;
1076 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1078 remappedelement[0] = vertexremap[element[0]];
1079 remappedelement[2] = vertexremap[element[2]];
1080 outelement3i[0] = remappedelement[2];
1081 outelement3i[1] = remappedelement[0];
1082 outelement3i[2] = remappedelement[0] + 1;
1083 outelement3i[3] = remappedelement[2];
1084 outelement3i[4] = remappedelement[0] + 1;
1085 outelement3i[5] = remappedelement[2] + 1;
1093 *outnumvertices = outvertices;
1094 return outtriangles;
1097 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)
1100 int outtriangles = 0, outvertices = 0;
1102 const float *vertex;
1103 float ratio, direction[3], projectvector[3];
1106 if (projectdirection)
1107 VectorScale(projectdirection, projectdistance, projectvector);
1109 VectorClear(projectvector);
1111 for (i = 0;i < numshadowmarktris;i++)
1113 int remappedelement[3];
1115 const int *neighbortriangle;
1117 markindex = shadowmarktris[i] * 3;
1118 neighbortriangle = inneighbor3i + markindex;
1119 side[0] = shadowmark[neighbortriangle[0]] == shadowmarkcount;
1120 side[1] = shadowmark[neighbortriangle[1]] == shadowmarkcount;
1121 side[2] = shadowmark[neighbortriangle[2]] == shadowmarkcount;
1122 if (side[0] + side[1] + side[2] == 0)
1126 element = inelement3i + markindex;
1128 // create the vertices
1129 for (j = 0;j < 3;j++)
1131 if (side[j] + side[j+1] == 0)
1134 if (vertexupdate[k] != vertexupdatenum)
1136 vertexupdate[k] = vertexupdatenum;
1137 vertexremap[k] = outvertices;
1138 vertex = invertex3f + k * 3;
1139 VectorCopy(vertex, outvertex3f);
1140 if (projectdirection)
1142 // project one copy of the vertex according to projectvector
1143 VectorAdd(vertex, projectvector, (outvertex3f + 3));
1147 // project one copy of the vertex to the sphere radius of the light
1148 // (FIXME: would projecting it to the light box be better?)
1149 VectorSubtract(vertex, projectorigin, direction);
1150 ratio = projectdistance / VectorLength(direction);
1151 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1158 // output the sides (facing outward from this triangle)
1161 remappedelement[0] = vertexremap[element[0]];
1162 remappedelement[1] = vertexremap[element[1]];
1163 outelement3i[0] = remappedelement[1];
1164 outelement3i[1] = remappedelement[0];
1165 outelement3i[2] = remappedelement[0] + 1;
1166 outelement3i[3] = remappedelement[1];
1167 outelement3i[4] = remappedelement[0] + 1;
1168 outelement3i[5] = remappedelement[1] + 1;
1175 remappedelement[1] = vertexremap[element[1]];
1176 remappedelement[2] = vertexremap[element[2]];
1177 outelement3i[0] = remappedelement[2];
1178 outelement3i[1] = remappedelement[1];
1179 outelement3i[2] = remappedelement[1] + 1;
1180 outelement3i[3] = remappedelement[2];
1181 outelement3i[4] = remappedelement[1] + 1;
1182 outelement3i[5] = remappedelement[2] + 1;
1189 remappedelement[0] = vertexremap[element[0]];
1190 remappedelement[2] = vertexremap[element[2]];
1191 outelement3i[0] = remappedelement[0];
1192 outelement3i[1] = remappedelement[2];
1193 outelement3i[2] = remappedelement[2] + 1;
1194 outelement3i[3] = remappedelement[0];
1195 outelement3i[4] = remappedelement[2] + 1;
1196 outelement3i[5] = remappedelement[0] + 1;
1203 *outnumvertices = outvertices;
1204 return outtriangles;
1207 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)
1213 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1215 tend = firsttriangle + numtris;
1216 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1218 // surface box entirely inside light box, no box cull
1219 if (projectdirection)
1221 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1223 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
1224 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1225 shadowmarklist[numshadowmark++] = t;
1230 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1231 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
1232 shadowmarklist[numshadowmark++] = t;
1237 // surface box not entirely inside light box, cull each triangle
1238 if (projectdirection)
1240 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1242 v[0] = invertex3f + e[0] * 3;
1243 v[1] = invertex3f + e[1] * 3;
1244 v[2] = invertex3f + e[2] * 3;
1245 TriangleNormal(v[0], v[1], v[2], normal);
1246 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1247 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1248 shadowmarklist[numshadowmark++] = t;
1253 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1255 v[0] = invertex3f + e[0] * 3;
1256 v[1] = invertex3f + e[1] * 3;
1257 v[2] = invertex3f + e[2] * 3;
1258 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1259 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1260 shadowmarklist[numshadowmark++] = t;
1266 qboolean R_Shadow_UseZPass(vec3_t mins, vec3_t maxs)
1271 if (r_shadow_compilingrtlight || !r_shadow_frontsidecasting.integer || !r_shadow_usezpassifpossible.integer)
1273 // check if the shadow volume intersects the near plane
1275 // a ray between the eye and light origin may intersect the caster,
1276 // indicating that the shadow may touch the eye location, however we must
1277 // test the near plane (a polygon), not merely the eye location, so it is
1278 // easiest to enlarge the caster bounding shape slightly for this.
1284 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)
1286 int i, tris, outverts;
1287 if (projectdistance < 0.1)
1289 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
1292 if (!numverts || !nummarktris)
1294 // make sure shadowelements is big enough for this volume
1295 if (maxshadowtriangles < nummarktris*8 || maxshadowvertices < numverts*2)
1296 R_Shadow_ResizeShadowArrays(numverts, nummarktris, 2, 8);
1298 if (maxvertexupdate < numverts)
1300 maxvertexupdate = numverts;
1302 Mem_Free(vertexupdate);
1304 Mem_Free(vertexremap);
1305 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1306 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1307 vertexupdatenum = 0;
1310 if (vertexupdatenum == 0)
1312 vertexupdatenum = 1;
1313 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
1314 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
1317 for (i = 0;i < nummarktris;i++)
1318 shadowmark[marktris[i]] = shadowmarkcount;
1320 if (r_shadow_compilingrtlight)
1322 // if we're compiling an rtlight, capture the mesh
1323 //tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1324 //Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zpass, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1325 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1326 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zfail, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1328 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
1330 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1331 R_Mesh_PrepareVertices_Vertex3f(outverts, shadowvertex3f, NULL);
1332 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1336 // decide which type of shadow to generate and set stencil mode
1337 R_Shadow_RenderMode_StencilShadowVolumes(R_Shadow_UseZPass(trismins, trismaxs));
1338 // generate the sides or a solid volume, depending on type
1339 if (r_shadow_rendermode >= R_SHADOW_RENDERMODE_ZPASS_STENCIL && r_shadow_rendermode <= R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE)
1340 tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1342 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1343 r_refdef.stats.lights_dynamicshadowtriangles += tris;
1344 r_refdef.stats.lights_shadowtriangles += tris;
1345 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
1347 // increment stencil if frontface is infront of depthbuffer
1348 GL_CullFace(r_refdef.view.cullface_front);
1349 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
1350 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1351 // decrement stencil if backface is infront of depthbuffer
1352 GL_CullFace(r_refdef.view.cullface_back);
1353 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
1355 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
1357 // decrement stencil if backface is behind depthbuffer
1358 GL_CullFace(r_refdef.view.cullface_front);
1359 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
1360 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1361 // increment stencil if frontface is behind depthbuffer
1362 GL_CullFace(r_refdef.view.cullface_back);
1363 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
1365 R_Mesh_PrepareVertices_Vertex3f(outverts, shadowvertex3f, NULL);
1366 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1370 int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias)
1372 // p1, p2, p3 are in the cubemap's local coordinate system
1373 // bias = border/(size - border)
1376 float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1377 dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2),
1378 dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3);
1379 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1381 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1382 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1383 | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1384 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1386 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1387 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1388 | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1390 dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1391 dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2),
1392 dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3);
1393 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1395 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1396 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1397 | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1398 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1400 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1401 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1402 | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1404 dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1405 dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2),
1406 dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3);
1407 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1409 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1410 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1411 | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1412 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1414 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1415 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1416 | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1421 int R_Shadow_CalcBBoxSideMask(const vec3_t mins, const vec3_t maxs, const matrix4x4_t *worldtolight, const matrix4x4_t *radiustolight, float bias)
1423 vec3_t center, radius, lightcenter, lightradius, pmin, pmax;
1424 float dp1, dn1, ap1, an1, dp2, dn2, ap2, an2;
1427 VectorSubtract(maxs, mins, radius);
1428 VectorScale(radius, 0.5f, radius);
1429 VectorAdd(mins, radius, center);
1430 Matrix4x4_Transform(worldtolight, center, lightcenter);
1431 Matrix4x4_Transform3x3(radiustolight, radius, lightradius);
1432 VectorSubtract(lightcenter, lightradius, pmin);
1433 VectorAdd(lightcenter, lightradius, pmax);
1435 dp1 = pmax[0] + pmax[1], dn1 = pmax[0] - pmin[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1436 dp2 = pmin[0] + pmin[1], dn2 = pmin[0] - pmax[1], ap2 = fabs(dp2), an2 = fabs(dn2);
1437 if(ap1 > bias*an1 && ap2 > bias*an2)
1439 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1440 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1441 if(an1 > bias*ap1 && an2 > bias*ap2)
1443 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1444 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1446 dp1 = pmax[1] + pmax[2], dn1 = pmax[1] - pmin[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1447 dp2 = pmin[1] + pmin[2], dn2 = pmin[1] - pmax[2], ap2 = fabs(dp2), an2 = fabs(dn2);
1448 if(ap1 > bias*an1 && ap2 > bias*an2)
1450 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1451 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1452 if(an1 > bias*ap1 && an2 > bias*ap2)
1454 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1455 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1457 dp1 = pmax[2] + pmax[0], dn1 = pmax[2] - pmin[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1458 dp2 = pmin[2] + pmin[0], dn2 = pmin[2] - pmax[0], ap2 = fabs(dp2), an2 = fabs(dn2);
1459 if(ap1 > bias*an1 && ap2 > bias*an2)
1461 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1462 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1463 if(an1 > bias*ap1 && an2 > bias*ap2)
1465 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1466 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1471 #define R_Shadow_CalcEntitySideMask(ent, worldtolight, radiustolight, bias) R_Shadow_CalcBBoxSideMask((ent)->mins, (ent)->maxs, worldtolight, radiustolight, bias)
1473 int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
1475 // p is in the cubemap's local coordinate system
1476 // bias = border/(size - border)
1477 float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn);
1478 float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn);
1479 float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn);
1481 if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
1482 if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
1483 if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
1484 if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
1485 if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
1486 if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
1490 int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
1494 int sides = 0x3F, masks[6] = { 3<<4, 3<<4, 3<<0, 3<<0, 3<<2, 3<<2 };
1495 float scale = (size - 2*border)/size, len;
1496 float bias = border / (float)(size - border), dp, dn, ap, an;
1497 // check if cone enclosing side would cross frustum plane
1498 scale = 2 / (scale*scale + 2);
1499 for (i = 0;i < 5;i++)
1501 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) > -0.03125)
1503 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[i].normal, n);
1504 len = scale*VectorLength2(n);
1505 if(n[0]*n[0] > len) sides &= n[0] < 0 ? ~(1<<0) : ~(2 << 0);
1506 if(n[1]*n[1] > len) sides &= n[1] < 0 ? ~(1<<2) : ~(2 << 2);
1507 if(n[2]*n[2] > len) sides &= n[2] < 0 ? ~(1<<4) : ~(2 << 4);
1509 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[4]) >= r_refdef.farclip - r_refdef.nearclip + 0.03125)
1511 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[4].normal, n);
1512 len = scale*VectorLength(n);
1513 if(n[0]*n[0] > len) sides &= n[0] >= 0 ? ~(1<<0) : ~(2 << 0);
1514 if(n[1]*n[1] > len) sides &= n[1] >= 0 ? ~(1<<2) : ~(2 << 2);
1515 if(n[2]*n[2] > len) sides &= n[2] >= 0 ? ~(1<<4) : ~(2 << 4);
1517 // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results
1518 // check if frustum corners/origin cross plane sides
1520 // infinite version, assumes frustum corners merely give direction and extend to infinite distance
1521 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.origin, p);
1522 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1523 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1524 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1525 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1526 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1527 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1528 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1529 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1530 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1531 for (i = 0;i < 4;i++)
1533 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.frustumcorner[i], n);
1534 VectorSubtract(n, p, n);
1535 dp = n[0] + n[1], dn = n[0] - n[1], ap = fabs(dp), an = fabs(dn);
1536 if(ap > 0) masks[0] |= dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2);
1537 if(an > 0) masks[1] |= dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2);
1538 dp = n[1] + n[2], dn = n[1] - n[2], ap = fabs(dp), an = fabs(dn);
1539 if(ap > 0) masks[2] |= dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4);
1540 if(an > 0) masks[3] |= dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4);
1541 dp = n[2] + n[0], dn = n[2] - n[0], ap = fabs(dp), an = fabs(dn);
1542 if(ap > 0) masks[4] |= dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0);
1543 if(an > 0) masks[5] |= dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0);
1546 // finite version, assumes corners are a finite distance from origin dependent on far plane
1547 for (i = 0;i < 5;i++)
1549 Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p);
1550 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1551 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1552 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1553 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1554 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1555 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1556 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1557 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1558 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1561 return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5];
1564 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)
1572 int mask, surfacemask = 0;
1573 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1575 bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
1576 tend = firsttriangle + numtris;
1577 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1579 // surface box entirely inside light box, no box cull
1580 if (projectdirection)
1582 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1584 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1585 TriangleNormal(v[0], v[1], v[2], normal);
1586 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1588 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1589 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1590 surfacemask |= mask;
1593 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;
1594 shadowsides[numshadowsides] = mask;
1595 shadowsideslist[numshadowsides++] = t;
1602 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1604 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1605 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]))
1607 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1608 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1609 surfacemask |= mask;
1612 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;
1613 shadowsides[numshadowsides] = mask;
1614 shadowsideslist[numshadowsides++] = t;
1622 // surface box not entirely inside light box, cull each triangle
1623 if (projectdirection)
1625 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1627 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1628 TriangleNormal(v[0], v[1], v[2], normal);
1629 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1630 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1632 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1633 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1634 surfacemask |= mask;
1637 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;
1638 shadowsides[numshadowsides] = mask;
1639 shadowsideslist[numshadowsides++] = t;
1646 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1648 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1649 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1650 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1652 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1653 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1654 surfacemask |= mask;
1657 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;
1658 shadowsides[numshadowsides] = mask;
1659 shadowsideslist[numshadowsides++] = t;
1668 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)
1670 int i, j, outtriangles = 0;
1671 int *outelement3i[6];
1672 if (!numverts || !numsidetris || !r_shadow_compilingrtlight)
1674 outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5];
1675 // make sure shadowelements is big enough for this mesh
1676 if (maxshadowtriangles < outtriangles)
1677 R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1);
1679 // compute the offset and size of the separate index lists for each cubemap side
1681 for (i = 0;i < 6;i++)
1683 outelement3i[i] = shadowelements + outtriangles * 3;
1684 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles;
1685 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i];
1686 outtriangles += sidetotals[i];
1689 // gather up the (sparse) triangles into separate index lists for each cubemap side
1690 for (i = 0;i < numsidetris;i++)
1692 const int *element = elements + sidetris[i] * 3;
1693 for (j = 0;j < 6;j++)
1695 if (sides[i] & (1 << j))
1697 outelement3i[j][0] = element[0];
1698 outelement3i[j][1] = element[1];
1699 outelement3i[j][2] = element[2];
1700 outelement3i[j] += 3;
1705 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, outtriangles, shadowelements);
1708 static void R_Shadow_MakeTextures_MakeCorona(void)
1712 unsigned char pixels[32][32][4];
1713 for (y = 0;y < 32;y++)
1715 dy = (y - 15.5f) * (1.0f / 16.0f);
1716 for (x = 0;x < 32;x++)
1718 dx = (x - 15.5f) * (1.0f / 16.0f);
1719 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1720 a = bound(0, a, 255);
1721 pixels[y][x][0] = a;
1722 pixels[y][x][1] = a;
1723 pixels[y][x][2] = a;
1724 pixels[y][x][3] = 255;
1727 r_shadow_lightcorona = R_SkinFrame_LoadInternalBGRA("lightcorona", TEXF_FORCELINEAR, &pixels[0][0][0], 32, 32);
1730 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1732 float dist = sqrt(x*x+y*y+z*z);
1733 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1734 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1735 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1738 static void R_Shadow_MakeTextures(void)
1741 float intensity, dist;
1743 R_Shadow_FreeShadowMaps();
1744 R_FreeTexturePool(&r_shadow_texturepool);
1745 r_shadow_texturepool = R_AllocTexturePool();
1746 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1747 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1748 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1749 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1750 for (x = 0;x <= ATTENTABLESIZE;x++)
1752 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1753 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1754 r_shadow_attentable[x] = bound(0, intensity, 1);
1756 // 1D gradient texture
1757 for (x = 0;x < ATTEN1DSIZE;x++)
1758 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1759 r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1760 // 2D circle texture
1761 for (y = 0;y < ATTEN2DSIZE;y++)
1762 for (x = 0;x < ATTEN2DSIZE;x++)
1763 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);
1764 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1765 // 3D sphere texture
1766 if (r_shadow_texture3d.integer && vid.support.ext_texture_3d)
1768 for (z = 0;z < ATTEN3DSIZE;z++)
1769 for (y = 0;y < ATTEN3DSIZE;y++)
1770 for (x = 0;x < ATTEN3DSIZE;x++)
1771 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));
1772 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);
1775 r_shadow_attenuation3dtexture = NULL;
1778 R_Shadow_MakeTextures_MakeCorona();
1780 // Editor light sprites
1781 r_editlights_sprcursor = R_SkinFrame_LoadInternal8bit("gfx/editlights/cursor", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1798 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1799 r_editlights_sprlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/light", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1816 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1817 r_editlights_sprnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/noshadow", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1834 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1835 r_editlights_sprcubemaplight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemaplight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1852 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1853 r_editlights_sprcubemapnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemapnoshadowlight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1870 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1871 r_editlights_sprselection = R_SkinFrame_LoadInternal8bit("gfx/editlights/selection", TEXF_ALPHA | TEXF_CLAMP, (unsigned char *)
1888 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1891 void R_Shadow_ValidateCvars(void)
1893 if (r_shadow_texture3d.integer && !vid.support.ext_texture_3d)
1894 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1895 if (gl_ext_separatestencil.integer && !vid.support.ati_separate_stencil)
1896 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
1897 if (gl_ext_stenciltwoside.integer && !vid.support.ext_stencil_two_side)
1898 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1901 void R_Shadow_RenderMode_Begin(void)
1907 R_Shadow_ValidateCvars();
1909 if (!r_shadow_attenuation2dtexture
1910 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1911 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1912 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1913 R_Shadow_MakeTextures();
1916 R_Mesh_ResetTextureState();
1917 GL_BlendFunc(GL_ONE, GL_ZERO);
1918 GL_DepthRange(0, 1);
1919 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1921 GL_DepthMask(false);
1922 GL_Color(0, 0, 0, 1);
1923 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1925 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1927 if (gl_ext_separatestencil.integer && vid.support.ati_separate_stencil)
1929 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
1930 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
1932 else if (gl_ext_stenciltwoside.integer && vid.support.ext_stencil_two_side)
1934 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
1935 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
1939 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
1940 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
1943 switch(vid.renderpath)
1945 case RENDERPATH_GL20:
1946 case RENDERPATH_D3D9:
1947 case RENDERPATH_D3D10:
1948 case RENDERPATH_D3D11:
1949 case RENDERPATH_SOFT:
1950 case RENDERPATH_GLES2:
1951 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1953 case RENDERPATH_GL13:
1954 case RENDERPATH_GL11:
1955 if (r_textureunits.integer >= 2 && vid.texunits >= 2 && r_shadow_texture3d.integer && r_shadow_attenuation3dtexture)
1956 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN;
1957 else if (r_textureunits.integer >= 3 && vid.texunits >= 3)
1958 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN;
1959 else if (r_textureunits.integer >= 2 && vid.texunits >= 2)
1960 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN;
1962 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1968 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
1969 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
1970 r_shadow_drawbuffer = drawbuffer;
1971 r_shadow_readbuffer = readbuffer;
1973 r_shadow_cullface_front = r_refdef.view.cullface_front;
1974 r_shadow_cullface_back = r_refdef.view.cullface_back;
1977 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
1979 rsurface.rtlight = rtlight;
1982 void R_Shadow_RenderMode_Reset(void)
1984 R_Mesh_ResetRenderTargets();
1985 R_SetViewport(&r_refdef.view.viewport);
1986 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
1987 R_Mesh_ResetTextureState();
1988 GL_DepthRange(0, 1);
1990 GL_DepthMask(false);
1991 GL_DepthFunc(GL_LEQUAL);
1992 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1993 r_refdef.view.cullface_front = r_shadow_cullface_front;
1994 r_refdef.view.cullface_back = r_shadow_cullface_back;
1995 GL_CullFace(r_refdef.view.cullface_back);
1996 GL_Color(1, 1, 1, 1);
1997 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
1998 GL_BlendFunc(GL_ONE, GL_ZERO);
1999 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
2000 r_shadow_usingshadowmap2d = false;
2001 r_shadow_usingshadowmaportho = false;
2002 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
2005 void R_Shadow_ClearStencil(void)
2007 GL_Clear(GL_STENCIL_BUFFER_BIT, NULL, 1.0f, 128);
2008 r_refdef.stats.lights_clears++;
2011 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
2013 r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
2014 if (r_shadow_rendermode == mode)
2016 R_Shadow_RenderMode_Reset();
2017 GL_DepthFunc(GL_LESS);
2018 GL_ColorMask(0, 0, 0, 0);
2019 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2020 GL_CullFace(GL_NONE);
2021 R_SetupShader_DepthOrShadow();
2022 r_shadow_rendermode = mode;
2027 case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
2028 case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
2029 R_SetStencilSeparate(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, GL_ALWAYS, 128, 255);
2031 case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
2032 case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
2033 R_SetStencilSeparate(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, GL_ALWAYS, 128, 255);
2038 static void R_Shadow_MakeVSDCT(void)
2040 // maps to a 2x3 texture rectangle with normalized coordinates
2045 // stores abs(dir.xy), offset.xy/2.5
2046 unsigned char data[4*6] =
2048 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
2049 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
2050 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
2051 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
2052 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
2053 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
2055 r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
2058 static void R_Shadow_MakeShadowMap(int side, int size)
2060 switch (r_shadow_shadowmode)
2062 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2063 if (r_shadow_shadowmap2dtexture) return;
2064 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);
2065 r_shadow_shadowmap2dcolortexture = NULL;
2066 switch(vid.renderpath)
2069 case RENDERPATH_D3D9:
2070 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);
2071 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
2075 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2dtexture, NULL, NULL, NULL, NULL);
2083 // render depth into the fbo, do not render color at all
2084 // validate the fbo now
2088 qglDrawBuffer(GL_NONE);CHECKGLERROR
2089 qglReadBuffer(GL_NONE);CHECKGLERROR
2090 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2091 if (status != GL_FRAMEBUFFER_COMPLETE_EXT && (r_shadow_shadowmapping.integer || r_shadow_deferred.integer))
2093 Con_Printf("R_Shadow_MakeShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2094 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2095 Cvar_SetValueQuick(&r_shadow_deferred, 0);
2100 void R_Shadow_RenderMode_ShadowMap(int side, int clear, int size)
2102 float nearclip, farclip, bias;
2103 r_viewport_t viewport;
2106 float clearcolor[4];
2107 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
2109 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
2110 r_shadow_shadowmap_parameters[1] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
2111 r_shadow_shadowmap_parameters[3] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
2112 r_shadow_shadowmapside = side;
2113 r_shadow_shadowmapsize = size;
2115 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2116 r_shadow_shadowmap_parameters[2] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2117 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
2118 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D) goto init_done;
2120 // complex unrolled cube approach (more flexible)
2121 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2122 R_Shadow_MakeVSDCT();
2123 if (!r_shadow_shadowmap2dtexture)
2124 R_Shadow_MakeShadowMap(side, r_shadow_shadowmapmaxsize);
2125 if (r_shadow_shadowmap2dtexture) fbo = r_shadow_fbo2d;
2126 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
2127 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
2128 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
2130 R_Mesh_ResetTextureState();
2131 R_Mesh_ResetRenderTargets();
2132 R_Shadow_RenderMode_Reset();
2135 R_Mesh_SetRenderTargets(fbo, r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
2136 R_SetupShader_DepthOrShadow();
2139 R_SetupShader_ShowDepth();
2140 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
2145 R_SetViewport(&viewport);
2146 flipped = (side & 1) ^ (side >> 2);
2147 r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
2148 r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
2149 switch(vid.renderpath)
2151 case RENDERPATH_GL11:
2152 case RENDERPATH_GL13:
2153 case RENDERPATH_GL20:
2154 case RENDERPATH_SOFT:
2155 case RENDERPATH_GLES2:
2156 GL_CullFace(r_refdef.view.cullface_back);
2157 // OpenGL lets us scissor larger than the viewport, so go ahead and clear all views at once
2158 if ((clear & ((2 << side) - 1)) == (1 << side)) // only clear if the side is the first in the mask
2160 // get tightest scissor rectangle that encloses all viewports in the clear mask
2161 int x1 = clear & 0x15 ? 0 : size;
2162 int x2 = clear & 0x2A ? 2 * size : size;
2163 int y1 = clear & 0x03 ? 0 : (clear & 0xC ? size : 2 * size);
2164 int y2 = clear & 0x30 ? 3 * size : (clear & 0xC ? 2 * size : size);
2165 GL_Scissor(x1, y1, x2 - x1, y2 - y1);
2166 GL_Clear(GL_DEPTH_BUFFER_BIT, NULL, 1.0f, 0);
2168 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2170 case RENDERPATH_D3D9:
2171 case RENDERPATH_D3D10:
2172 case RENDERPATH_D3D11:
2173 Vector4Set(clearcolor, 1,1,1,1);
2174 // completely different meaning than in OpenGL path
2175 r_shadow_shadowmap_parameters[1] = 0;
2176 r_shadow_shadowmap_parameters[3] = -bias;
2177 // we invert the cull mode because we flip the projection matrix
2178 // NOTE: this actually does nothing because the DrawShadowMap code sets it to doublesided...
2179 GL_CullFace(r_refdef.view.cullface_front);
2180 // D3D considers it an error to use a scissor larger than the viewport... clear just this view
2181 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2182 if (r_shadow_shadowmapsampler)
2184 GL_ColorMask(0,0,0,0);
2186 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
2190 GL_ColorMask(1,1,1,1);
2192 GL_Clear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
2198 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
2200 R_Mesh_ResetTextureState();
2201 R_Mesh_ResetRenderTargets();
2204 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2205 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2206 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2207 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2209 R_Shadow_RenderMode_Reset();
2210 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2212 GL_DepthFunc(GL_EQUAL);
2213 // do global setup needed for the chosen lighting mode
2214 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2215 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2216 r_shadow_usingshadowmap2d = shadowmapping;
2217 r_shadow_rendermode = r_shadow_lightingrendermode;
2218 // only draw light where this geometry was already rendered AND the
2219 // stencil is 128 (values other than this mean shadow)
2221 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2223 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
2226 static const unsigned short bboxelements[36] =
2236 static const float bboxpoints[8][3] =
2248 void R_Shadow_RenderMode_DrawDeferredLight(qboolean stenciltest, qboolean shadowmapping)
2251 float vertex3f[8*3];
2252 const matrix4x4_t *matrix = &rsurface.rtlight->matrix_lighttoworld;
2253 // do global setup needed for the chosen lighting mode
2254 R_Shadow_RenderMode_Reset();
2255 r_shadow_rendermode = r_shadow_lightingrendermode;
2256 R_EntityMatrix(&identitymatrix);
2257 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2258 // only draw light where this geometry was already rendered AND the
2259 // stencil is 128 (values other than this mean shadow)
2260 R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2261 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
2263 r_shadow_usingshadowmap2d = shadowmapping;
2265 // render the lighting
2266 R_SetupShader_DeferredLight(rsurface.rtlight);
2267 for (i = 0;i < 8;i++)
2268 Matrix4x4_Transform(matrix, bboxpoints[i], vertex3f + i*3);
2269 GL_ColorMask(1,1,1,1);
2270 GL_DepthMask(false);
2271 GL_DepthRange(0, 1);
2272 GL_PolygonOffset(0, 0);
2274 GL_DepthFunc(GL_GREATER);
2275 GL_CullFace(r_refdef.view.cullface_back);
2276 R_Mesh_PrepareVertices_Vertex3f(8, vertex3f, NULL);
2277 R_Mesh_Draw(0, 8, 0, 12, NULL, NULL, 0, bboxelements, NULL, 0);
2280 static void R_Shadow_UpdateBounceGridTexture(void)
2282 #define MAXBOUNCEGRIDPARTICLESPERLIGHT 1048576
2284 int flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
2287 int hitsupercontentsmask;
2297 //trace_t cliptrace2;
2298 //trace_t cliptrace3;
2299 unsigned char *pixel;
2300 unsigned char *pixels;
2301 unsigned short *highpixel;
2302 unsigned short *highpixels;
2303 unsigned int lightindex;
2305 unsigned int range1;
2306 unsigned int range2;
2307 unsigned int seed = (unsigned int)(realtime * 1000.0f);
2309 vec3_t baseshotcolor;
2322 vec_t lightintensity;
2323 vec_t photonscaling;
2324 vec_t photonresidual;
2326 qboolean isstatic = r_shadow_bouncegrid_updateinterval.value > 1.0f;
2328 if (!r_shadow_bouncegrid.integer || !vid.support.ext_texture_3d)
2330 if (r_shadow_bouncegridtexture)
2332 R_FreeTexture(r_shadow_bouncegridtexture);
2333 r_shadow_bouncegridtexture = NULL;
2335 if (r_shadow_bouncegridpixels)
2336 Mem_Free(r_shadow_bouncegridpixels);
2337 r_shadow_bouncegridpixels = NULL;
2338 if (r_shadow_bouncegridhighpixels)
2339 Mem_Free(r_shadow_bouncegridhighpixels);
2340 r_shadow_bouncegridhighpixels = NULL;
2341 r_shadow_bouncegridnumpixels = 0;
2344 if (r_refdef.scene.worldmodel && isstatic)
2346 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));
2347 VectorMA(r_refdef.scene.worldmodel->normalmins, -2.0f, spacing, mins);
2348 VectorMA(r_refdef.scene.worldmodel->normalmaxs, 2.0f, spacing, maxs);
2349 VectorSubtract(maxs, mins, size);
2350 resolution[0] = (int)floor(size[0] / spacing[0] + 0.5f);
2351 resolution[1] = (int)floor(size[1] / spacing[1] + 0.5f);
2352 resolution[2] = (int)floor(size[2] / spacing[2] + 0.5f);
2353 resolution[0] = min(resolution[0], bound(4, r_shadow_bouncegrid_x.integer, (int)vid.maxtexturesize_3d));
2354 resolution[1] = min(resolution[1], bound(4, r_shadow_bouncegrid_y.integer, (int)vid.maxtexturesize_3d));
2355 resolution[2] = min(resolution[2], bound(4, r_shadow_bouncegrid_z.integer, (int)vid.maxtexturesize_3d));
2356 spacing[0] = size[0] / resolution[0];
2357 spacing[1] = size[1] / resolution[1];
2358 spacing[2] = size[2] / resolution[2];
2359 ispacing[0] = 1.0f / spacing[0];
2360 ispacing[1] = 1.0f / spacing[1];
2361 ispacing[2] = 1.0f / spacing[2];
2365 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));
2366 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));
2367 VectorMultiply(resolution, spacing, size);
2368 ispacing[0] = 1.0f / spacing[0];
2369 ispacing[1] = 1.0f / spacing[1];
2370 ispacing[2] = 1.0f / spacing[2];
2371 mins[0] = floor(r_refdef.view.origin[0] * ispacing[0] + 0.5f) * spacing[0] - 0.5f * size[0];
2372 mins[1] = floor(r_refdef.view.origin[1] * ispacing[1] + 0.5f) * spacing[1] - 0.5f * size[1];
2373 mins[2] = floor(r_refdef.view.origin[2] * ispacing[2] + 0.5f) * spacing[2] - 0.5f * size[2];
2374 VectorAdd(mins, size, maxs);
2376 r_shadow_bouncegridintensity = r_shadow_bouncegrid_intensity.value;
2377 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])
2379 // we're going to update the bouncegrid, update the matrix...
2380 memset(m, 0, sizeof(m));
2381 m[0] = 1.0f / size[0];
2382 m[3] = -mins[0] * m[0];
2383 m[5] = 1.0f / size[1];
2384 m[7] = -mins[1] * m[5];
2385 m[10] = 1.0f / size[2];
2386 m[11] = -mins[2] * m[10];
2388 Matrix4x4_FromArrayFloatD3D(&r_shadow_bouncegridmatrix, m);
2389 numpixels = resolution[0]*resolution[1]*resolution[2];
2390 // reallocate pixels for this update if needed...
2391 if (r_shadow_bouncegridnumpixels != numpixels || !r_shadow_bouncegridpixels || !r_shadow_bouncegridhighpixels)
2393 r_shadow_bouncegridpixels = (unsigned char *)Mem_Realloc(r_main_mempool, r_shadow_bouncegridpixels, numpixels * sizeof(unsigned char[4]));
2394 r_shadow_bouncegridhighpixels = (unsigned short *)Mem_Realloc(r_main_mempool, r_shadow_bouncegridhighpixels, numpixels * sizeof(unsigned short[4]));
2396 r_shadow_bouncegridnumpixels = numpixels;
2397 pixels = r_shadow_bouncegridpixels;
2398 highpixels = r_shadow_bouncegridhighpixels;
2399 memset(pixels, 0, numpixels * sizeof(unsigned char[4]));
2400 memset(highpixels, 0, numpixels * sizeof(unsigned short[3]));
2401 // figure out what we want to interact with
2402 if (r_shadow_bouncegrid_hitmodels.integer)
2403 hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_LIQUIDSMASK;
2405 hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_LIQUIDSMASK;
2406 maxbounce = bound(1, r_shadow_bouncegrid_maxbounce.integer, 16);
2407 // iterate world rtlights
2408 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
2409 range1 = isstatic ? 0 : r_refdef.scene.numlights;
2410 range2 = range + range1;
2412 for (lightindex = 0;lightindex < range2;lightindex++)
2416 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2417 if (!light || !(light->flags & flag))
2419 rtlight = &light->rtlight;
2420 // when static, we skip styled lights because they tend to change...
2421 if (rtlight->style > 0)
2423 VectorScale(rtlight->color, (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) * (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1), lightcolor);
2427 if (lightindex < range)
2429 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2430 rtlight = &light->rtlight;
2433 rtlight = r_refdef.scene.lights[lightindex - range];
2434 // draw only visible lights (major speedup)
2437 VectorScale(rtlight->currentcolor, rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale, lightcolor);
2439 if (!VectorLength2(lightcolor))
2441 // shoot particles from this light
2442 // use a calculation for the number of particles that will not
2443 // vary with lightstyle, otherwise we get randomized particle
2444 // distribution, the seeded random is only consistent for a
2445 // consistent number of particles on this light...
2446 radius = rtlight->radius * bound(0.0001f, r_shadow_bouncegrid_lightradiusscale.value, 1024.0f);
2447 s = rtlight->radius;
2448 lightintensity = VectorLength(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2449 if (lightindex >= range)
2450 lightintensity *= r_shadow_bouncegrid_dlightparticlemultiplier.value;
2451 photoncount += max(0.0f, lightintensity * s * s);
2453 photonscaling = bound(1, r_shadow_bouncegrid_photons.value, 1048576) / max(1, photoncount);
2454 photonresidual = 0.0f;
2455 for (lightindex = 0;lightindex < range2;lightindex++)
2459 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2460 if (!light || !(light->flags & flag))
2462 rtlight = &light->rtlight;
2463 // when static, we skip styled lights because they tend to change...
2464 if (rtlight->style > 0)
2466 VectorScale(rtlight->color, (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) * (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1), lightcolor);
2470 if (lightindex < range)
2472 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2473 rtlight = &light->rtlight;
2476 rtlight = r_refdef.scene.lights[lightindex - range];
2477 // draw only visible lights (major speedup)
2480 VectorScale(rtlight->currentcolor, rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale, lightcolor);
2482 if (!VectorLength2(lightcolor))
2484 // shoot particles from this light
2485 // use a calculation for the number of particles that will not
2486 // vary with lightstyle, otherwise we get randomized particle
2487 // distribution, the seeded random is only consistent for a
2488 // consistent number of particles on this light...
2489 radius = rtlight->radius * bound(0.0001f, r_shadow_bouncegrid_lightradiusscale.value, 1024.0f);
2490 s = rtlight->radius;
2491 lightintensity = VectorLength(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2492 if (lightindex >= range)
2493 lightintensity *= r_shadow_bouncegrid_dlightparticlemultiplier.value;
2494 photonresidual += lightintensity * s * s * photonscaling;
2495 shootparticles = (int)bound(0, photonresidual, MAXBOUNCEGRIDPARTICLESPERLIGHT);
2496 if (!shootparticles)
2498 photonresidual -= shootparticles;
2499 s = 65535.0f * r_shadow_bouncegrid_particleintensity.value / shootparticles;
2500 VectorScale(lightcolor, s, baseshotcolor);
2501 if (VectorLength2(baseshotcolor) < 3.0f)
2503 r_refdef.stats.bouncegrid_lights++;
2504 r_refdef.stats.bouncegrid_particles += shootparticles;
2505 for (shotparticles = 0;shotparticles < shootparticles;shotparticles++)
2507 if (r_shadow_bouncegrid_stablerandom.integer > 0)
2508 seed = lightindex * 11937 + shotparticles;
2509 VectorCopy(baseshotcolor, shotcolor);
2510 VectorCopy(rtlight->shadoworigin, clipstart);
2511 if (r_shadow_bouncegrid_stablerandom.integer < 0)
2512 VectorRandom(clipend);
2514 VectorCheeseRandom(clipend);
2515 VectorMA(clipstart, radius, clipend, clipend);
2516 for (bouncecount = 0;;bouncecount++)
2518 r_refdef.stats.bouncegrid_traces++;
2519 //r_refdef.scene.worldmodel->TraceLineAgainstSurfaces(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace, clipstart, clipend, hitsupercontentsmask);
2520 //r_refdef.scene.worldmodel->TraceLine(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace2, clipstart, clipend, hitsupercontentsmask);
2521 cliptrace = CL_TraceLine(clipstart, clipend, r_shadow_bouncegrid_hitmodels.integer ? MOVE_HITMODEL : MOVE_NOMONSTERS, NULL, hitsupercontentsmask, true, false, NULL, true, true);
2522 //Collision_ClipLineToWorld(&cliptrace, cl.worldmodel, clipstart, clipend, hitsupercontentsmask);
2523 if (cliptrace.fraction >= 1.0f)
2525 r_refdef.stats.bouncegrid_hits++;
2526 if (bouncecount > 0)
2528 r_refdef.stats.bouncegrid_splats++;
2529 // figure out which texture pixel this is in
2530 tex[0] = (int)((cliptrace.endpos[0] - mins[0]) * ispacing[0]);
2531 tex[1] = (int)((cliptrace.endpos[1] - mins[1]) * ispacing[1]);
2532 tex[2] = (int)((cliptrace.endpos[2] - mins[2]) * ispacing[2]);
2533 if (tex[0] >= 1 && tex[1] >= 1 && tex[2] >= 1 && tex[0] < resolution[0] - 1 && tex[1] < resolution[1] - 1 && tex[2] < resolution[2] - 1)
2535 // it is within bounds...
2536 pixelindex = ((tex[2]*resolution[1]+tex[1])*resolution[0]+tex[0]);
2537 pixel = pixels + 4 * pixelindex;
2538 highpixel = highpixels + 3 * pixelindex;
2539 // add to the high precision pixel color
2540 c[0] = highpixel[0] + (int)shotcolor[2];
2541 c[1] = highpixel[1] + (int)shotcolor[1];
2542 c[2] = highpixel[2] + (int)shotcolor[0];
2543 highpixel[0] = (unsigned short)min(c[0], 65535);
2544 highpixel[1] = (unsigned short)min(c[1], 65535);
2545 highpixel[2] = (unsigned short)min(c[2], 65535);
2546 // update the low precision pixel color
2547 pixel[0] = highpixel[0] >> 8;
2548 pixel[1] = highpixel[1] >> 8;
2549 pixel[2] = highpixel[2] >> 8;
2553 if (bouncecount >= maxbounce)
2555 // scale down shot color by bounce intensity and texture color (or 50% if no texture reported)
2556 // also clamp the resulting color to never add energy, even if the user requests extreme values
2557 if (cliptrace.hittexture && cliptrace.hittexture->currentskinframe)
2558 VectorCopy(cliptrace.hittexture->currentskinframe->avgcolor, surfcolor);
2560 VectorSet(surfcolor, 0.5f, 0.5f, 0.5f);
2561 VectorScale(surfcolor, r_shadow_bouncegrid_particlebounceintensity.value, surfcolor);
2562 surfcolor[0] = min(surfcolor[0], 1.0f);
2563 surfcolor[1] = min(surfcolor[1], 1.0f);
2564 surfcolor[2] = min(surfcolor[2], 1.0f);
2565 VectorMultiply(shotcolor, surfcolor, shotcolor);
2566 if (VectorLength2(shotcolor) < 3.0f)
2568 r_refdef.stats.bouncegrid_bounces++;
2569 if (r_shadow_bouncegrid_bounceanglediffuse.integer)
2571 // random direction, primarily along plane normal
2572 s = VectorDistance(cliptrace.endpos, clipend);
2573 if (r_shadow_bouncegrid_stablerandom.integer < 0)
2574 VectorRandom(clipend);
2576 VectorCheeseRandom(clipend);
2577 VectorMA(cliptrace.plane.normal, 0.95f, clipend, clipend);
2578 VectorNormalize(clipend);
2579 VectorScale(clipend, s, clipend);
2583 // reflect the remaining portion of the line across plane normal
2584 VectorSubtract(clipend, cliptrace.endpos, clipdiff);
2585 VectorReflect(clipdiff, 1.0, cliptrace.plane.normal, clipend);
2587 // calculate the new line start and end
2588 VectorCopy(cliptrace.endpos, clipstart);
2589 VectorAdd(clipstart, clipend, clipend);
2593 if (r_shadow_bouncegridtexture && r_shadow_bouncegridresolution[0] == resolution[0] && r_shadow_bouncegridresolution[1] == resolution[1] && r_shadow_bouncegridresolution[2] == resolution[2])
2594 R_UpdateTexture(r_shadow_bouncegridtexture, pixels, 0, 0, 0, resolution[0], resolution[1], resolution[2]);
2597 VectorCopy(resolution, r_shadow_bouncegridresolution);
2598 if (r_shadow_bouncegridtexture)
2599 R_FreeTexture(r_shadow_bouncegridtexture);
2600 r_shadow_bouncegridtexture = R_LoadTexture3D(r_shadow_texturepool, "bouncegrid", resolution[0], resolution[1], resolution[2], pixels, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, 0, NULL);
2602 r_shadow_bouncegridtime = realtime;
2605 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
2607 R_Shadow_RenderMode_Reset();
2608 GL_BlendFunc(GL_ONE, GL_ONE);
2609 GL_DepthRange(0, 1);
2610 GL_DepthTest(r_showshadowvolumes.integer < 2);
2611 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
2612 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2613 GL_CullFace(GL_NONE);
2614 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
2617 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
2619 R_Shadow_RenderMode_Reset();
2620 GL_BlendFunc(GL_ONE, GL_ONE);
2621 GL_DepthRange(0, 1);
2622 GL_DepthTest(r_showlighting.integer < 2);
2623 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2625 GL_DepthFunc(GL_EQUAL);
2626 R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2627 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2630 void R_Shadow_RenderMode_End(void)
2632 R_Shadow_RenderMode_Reset();
2633 R_Shadow_RenderMode_ActiveLight(NULL);
2635 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2636 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2639 int bboxedges[12][2] =
2658 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2660 if (!r_shadow_scissor.integer)
2662 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2663 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2664 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2665 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2668 if(R_ScissorForBBox(mins, maxs, r_shadow_lightscissor))
2669 return true; // invisible
2670 if(r_shadow_lightscissor[0] != r_refdef.view.viewport.x
2671 || r_shadow_lightscissor[1] != r_refdef.view.viewport.y
2672 || r_shadow_lightscissor[2] != r_refdef.view.viewport.width
2673 || r_shadow_lightscissor[3] != r_refdef.view.viewport.height)
2674 r_refdef.stats.lights_scissored++;
2678 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, const float *diffusecolor, const float *ambientcolor)
2681 const float *vertex3f;
2682 const float *normal3f;
2684 float dist, dot, distintensity, shadeintensity, v[3], n[3];
2685 switch (r_shadow_rendermode)
2687 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2688 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2689 if (VectorLength2(diffusecolor) > 0)
2691 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)
2693 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2694 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2695 if ((dot = DotProduct(n, v)) < 0)
2697 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2698 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
2701 VectorCopy(ambientcolor, color4f);
2702 if (r_refdef.fogenabled)
2705 f = RSurf_FogVertex(vertex3f);
2706 VectorScale(color4f, f, color4f);
2713 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
2715 VectorCopy(ambientcolor, color4f);
2716 if (r_refdef.fogenabled)
2719 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2720 f = RSurf_FogVertex(vertex3f);
2721 VectorScale(color4f + 4*i, f, color4f);
2727 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2728 if (VectorLength2(diffusecolor) > 0)
2730 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)
2732 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2733 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2735 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2736 if ((dot = DotProduct(n, v)) < 0)
2738 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2739 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2740 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2741 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2745 color4f[0] = ambientcolor[0] * distintensity;
2746 color4f[1] = ambientcolor[1] * distintensity;
2747 color4f[2] = ambientcolor[2] * distintensity;
2749 if (r_refdef.fogenabled)
2752 f = RSurf_FogVertex(vertex3f);
2753 VectorScale(color4f, f, color4f);
2757 VectorClear(color4f);
2763 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
2765 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2766 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2768 color4f[0] = ambientcolor[0] * distintensity;
2769 color4f[1] = ambientcolor[1] * distintensity;
2770 color4f[2] = ambientcolor[2] * distintensity;
2771 if (r_refdef.fogenabled)
2774 f = RSurf_FogVertex(vertex3f);
2775 VectorScale(color4f, f, color4f);
2779 VectorClear(color4f);
2784 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2785 if (VectorLength2(diffusecolor) > 0)
2787 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)
2789 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2790 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2792 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2793 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2794 if ((dot = DotProduct(n, v)) < 0)
2796 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2797 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2798 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2799 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2803 color4f[0] = ambientcolor[0] * distintensity;
2804 color4f[1] = ambientcolor[1] * distintensity;
2805 color4f[2] = ambientcolor[2] * distintensity;
2807 if (r_refdef.fogenabled)
2810 f = RSurf_FogVertex(vertex3f);
2811 VectorScale(color4f, f, color4f);
2815 VectorClear(color4f);
2821 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
2823 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2824 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2826 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2827 color4f[0] = ambientcolor[0] * distintensity;
2828 color4f[1] = ambientcolor[1] * distintensity;
2829 color4f[2] = ambientcolor[2] * distintensity;
2830 if (r_refdef.fogenabled)
2833 f = RSurf_FogVertex(vertex3f);
2834 VectorScale(color4f, f, color4f);
2838 VectorClear(color4f);
2848 static void R_Shadow_RenderLighting_VisibleLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
2850 // used to display how many times a surface is lit for level design purposes
2851 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
2852 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
2856 static void R_Shadow_RenderLighting_Light_GLSL(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale, float specularscale)
2858 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2859 R_SetupShader_Surface(lightcolor, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT, texturenumsurfaces, texturesurfacelist, NULL);
2860 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2861 GL_DepthFunc(GL_EQUAL);
2863 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2864 GL_DepthFunc(GL_LEQUAL);
2867 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
2874 int newnumtriangles;
2878 int maxtriangles = 4096;
2879 static int newelements[4096*3];
2880 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, diffusecolor2, ambientcolor2);
2881 for (renders = 0;renders < 4;renders++)
2886 newnumtriangles = 0;
2888 // due to low fillrate on the cards this vertex lighting path is
2889 // designed for, we manually cull all triangles that do not
2890 // contain a lit vertex
2891 // this builds batches of triangles from multiple surfaces and
2892 // renders them at once
2893 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
2895 if (VectorLength2(rsurface.passcolor4f + e[0] * 4) + VectorLength2(rsurface.passcolor4f + e[1] * 4) + VectorLength2(rsurface.passcolor4f + e[2] * 4) >= 0.01)
2897 if (newnumtriangles)
2899 newfirstvertex = min(newfirstvertex, e[0]);
2900 newlastvertex = max(newlastvertex, e[0]);
2904 newfirstvertex = e[0];
2905 newlastvertex = e[0];
2907 newfirstvertex = min(newfirstvertex, e[1]);
2908 newlastvertex = max(newlastvertex, e[1]);
2909 newfirstvertex = min(newfirstvertex, e[2]);
2910 newlastvertex = max(newlastvertex, e[2]);
2916 if (newnumtriangles >= maxtriangles)
2918 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
2919 newnumtriangles = 0;
2925 if (newnumtriangles >= 1)
2927 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
2930 // if we couldn't find any lit triangles, exit early
2933 // now reduce the intensity for the next overbright pass
2934 // we have to clamp to 0 here incase the drivers have improper
2935 // handling of negative colors
2936 // (some old drivers even have improper handling of >1 color)
2938 for (i = 0, c = rsurface.passcolor4f + 4 * firstvertex;i < numvertices;i++, c += 4)
2940 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
2942 c[0] = max(0, c[0] - 1);
2943 c[1] = max(0, c[1] - 1);
2944 c[2] = max(0, c[2] - 1);
2956 static void R_Shadow_RenderLighting_Light_Vertex(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale)
2958 // OpenGL 1.1 path (anything)
2959 float ambientcolorbase[3], diffusecolorbase[3];
2960 float ambientcolorpants[3], diffusecolorpants[3];
2961 float ambientcolorshirt[3], diffusecolorshirt[3];
2962 const float *surfacecolor = rsurface.texture->dlightcolor;
2963 const float *surfacepants = rsurface.colormap_pantscolor;
2964 const float *surfaceshirt = rsurface.colormap_shirtcolor;
2965 rtexture_t *basetexture = rsurface.texture->basetexture;
2966 rtexture_t *pantstexture = rsurface.texture->pantstexture;
2967 rtexture_t *shirttexture = rsurface.texture->shirttexture;
2968 qboolean dopants = pantstexture && VectorLength2(surfacepants) >= (1.0f / 1048576.0f);
2969 qboolean doshirt = shirttexture && VectorLength2(surfaceshirt) >= (1.0f / 1048576.0f);
2970 ambientscale *= 2 * r_refdef.view.colorscale;
2971 diffusescale *= 2 * r_refdef.view.colorscale;
2972 ambientcolorbase[0] = lightcolor[0] * ambientscale * surfacecolor[0];ambientcolorbase[1] = lightcolor[1] * ambientscale * surfacecolor[1];ambientcolorbase[2] = lightcolor[2] * ambientscale * surfacecolor[2];
2973 diffusecolorbase[0] = lightcolor[0] * diffusescale * surfacecolor[0];diffusecolorbase[1] = lightcolor[1] * diffusescale * surfacecolor[1];diffusecolorbase[2] = lightcolor[2] * diffusescale * surfacecolor[2];
2974 ambientcolorpants[0] = ambientcolorbase[0] * surfacepants[0];ambientcolorpants[1] = ambientcolorbase[1] * surfacepants[1];ambientcolorpants[2] = ambientcolorbase[2] * surfacepants[2];
2975 diffusecolorpants[0] = diffusecolorbase[0] * surfacepants[0];diffusecolorpants[1] = diffusecolorbase[1] * surfacepants[1];diffusecolorpants[2] = diffusecolorbase[2] * surfacepants[2];
2976 ambientcolorshirt[0] = ambientcolorbase[0] * surfaceshirt[0];ambientcolorshirt[1] = ambientcolorbase[1] * surfaceshirt[1];ambientcolorshirt[2] = ambientcolorbase[2] * surfaceshirt[2];
2977 diffusecolorshirt[0] = diffusecolorbase[0] * surfaceshirt[0];diffusecolorshirt[1] = diffusecolorbase[1] * surfaceshirt[1];diffusecolorshirt[2] = diffusecolorbase[2] * surfaceshirt[2];
2978 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | (diffusescale > 0 ? BATCHNEED_ARRAY_NORMAL : 0) | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
2979 rsurface.passcolor4f = (float *)R_FrameData_Alloc((rsurface.batchfirstvertex + rsurface.batchnumvertices) * sizeof(float[4]));
2980 R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
2981 R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.passcolor4f, 0, 0);
2982 R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
2983 R_Mesh_TexBind(0, basetexture);
2984 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
2985 R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
2986 switch(r_shadow_rendermode)
2988 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2989 R_Mesh_TexBind(1, r_shadow_attenuation3dtexture);
2990 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
2991 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
2992 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
2994 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2995 R_Mesh_TexBind(2, r_shadow_attenuation2dtexture);
2996 R_Mesh_TexMatrix(2, &rsurface.entitytoattenuationz);
2997 R_Mesh_TexCombine(2, GL_MODULATE, GL_MODULATE, 1, 1);
2998 R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3000 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
3001 R_Mesh_TexBind(1, r_shadow_attenuation2dtexture);
3002 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
3003 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
3004 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3006 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3011 //R_Mesh_TexBind(0, basetexture);
3012 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorbase, ambientcolorbase);
3015 R_Mesh_TexBind(0, pantstexture);
3016 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorpants, ambientcolorpants);
3020 R_Mesh_TexBind(0, shirttexture);
3021 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorshirt, ambientcolorshirt);
3025 extern cvar_t gl_lightmaps;
3026 void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
3028 float ambientscale, diffusescale, specularscale;
3030 float lightcolor[3];
3031 VectorCopy(rsurface.rtlight->currentcolor, lightcolor);
3032 ambientscale = rsurface.rtlight->ambientscale;
3033 diffusescale = rsurface.rtlight->diffusescale;
3034 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
3035 if (!r_shadow_usenormalmap.integer)
3037 ambientscale += 1.0f * diffusescale;
3041 if ((ambientscale + diffusescale) * VectorLength2(lightcolor) + specularscale * VectorLength2(lightcolor) < (1.0f / 1048576.0f))
3043 negated = (lightcolor[0] + lightcolor[1] + lightcolor[2] < 0) && vid.support.ext_blend_subtract;
3046 VectorNegate(lightcolor, lightcolor);
3047 switch(vid.renderpath)
3049 case RENDERPATH_GL11:
3050 case RENDERPATH_GL13:
3051 case RENDERPATH_GL20:
3052 case RENDERPATH_GLES2:
3053 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
3055 case RENDERPATH_D3D9:
3057 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_SUBTRACT);
3060 case RENDERPATH_D3D10:
3061 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3063 case RENDERPATH_D3D11:
3064 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3066 case RENDERPATH_SOFT:
3067 DPSOFTRAST_BlendSubtract(true);
3071 RSurf_SetupDepthAndCulling();
3072 switch (r_shadow_rendermode)
3074 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
3075 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
3076 R_Shadow_RenderLighting_VisibleLighting(texturenumsurfaces, texturesurfacelist);
3078 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
3079 R_Shadow_RenderLighting_Light_GLSL(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale, specularscale);
3081 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
3082 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
3083 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
3084 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3085 R_Shadow_RenderLighting_Light_Vertex(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale);
3088 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
3093 switch(vid.renderpath)
3095 case RENDERPATH_GL11:
3096 case RENDERPATH_GL13:
3097 case RENDERPATH_GL20:
3098 case RENDERPATH_GLES2:
3099 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
3101 case RENDERPATH_D3D9:
3103 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_ADD);
3106 case RENDERPATH_D3D10:
3107 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3109 case RENDERPATH_D3D11:
3110 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3112 case RENDERPATH_SOFT:
3113 DPSOFTRAST_BlendSubtract(false);
3119 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)
3121 matrix4x4_t tempmatrix = *matrix;
3122 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
3124 // if this light has been compiled before, free the associated data
3125 R_RTLight_Uncompile(rtlight);
3127 // clear it completely to avoid any lingering data
3128 memset(rtlight, 0, sizeof(*rtlight));
3130 // copy the properties
3131 rtlight->matrix_lighttoworld = tempmatrix;
3132 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
3133 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
3134 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
3135 VectorCopy(color, rtlight->color);
3136 rtlight->cubemapname[0] = 0;
3137 if (cubemapname && cubemapname[0])
3138 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
3139 rtlight->shadow = shadow;
3140 rtlight->corona = corona;
3141 rtlight->style = style;
3142 rtlight->isstatic = isstatic;
3143 rtlight->coronasizescale = coronasizescale;
3144 rtlight->ambientscale = ambientscale;
3145 rtlight->diffusescale = diffusescale;
3146 rtlight->specularscale = specularscale;
3147 rtlight->flags = flags;
3149 // compute derived data
3150 //rtlight->cullradius = rtlight->radius;
3151 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
3152 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3153 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3154 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3155 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3156 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3157 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3160 // compiles rtlight geometry
3161 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
3162 void R_RTLight_Compile(rtlight_t *rtlight)
3165 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
3166 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
3167 entity_render_t *ent = r_refdef.scene.worldentity;
3168 dp_model_t *model = r_refdef.scene.worldmodel;
3169 unsigned char *data;
3172 // compile the light
3173 rtlight->compiled = true;
3174 rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
3175 rtlight->static_numleafs = 0;
3176 rtlight->static_numleafpvsbytes = 0;
3177 rtlight->static_leaflist = NULL;
3178 rtlight->static_leafpvs = NULL;
3179 rtlight->static_numsurfaces = 0;
3180 rtlight->static_surfacelist = NULL;
3181 rtlight->static_shadowmap_receivers = 0x3F;
3182 rtlight->static_shadowmap_casters = 0x3F;
3183 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3184 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3185 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3186 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3187 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3188 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3190 if (model && model->GetLightInfo)
3192 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
3193 r_shadow_compilingrtlight = rtlight;
3194 R_FrameData_SetMark();
3195 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);
3196 R_FrameData_ReturnToMark();
3197 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
3198 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
3199 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3200 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
3201 rtlight->static_numsurfaces = numsurfaces;
3202 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
3203 rtlight->static_numleafs = numleafs;
3204 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
3205 rtlight->static_numleafpvsbytes = numleafpvsbytes;
3206 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
3207 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
3208 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
3209 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
3210 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3211 if (rtlight->static_numsurfaces)
3212 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3213 if (rtlight->static_numleafs)
3214 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3215 if (rtlight->static_numleafpvsbytes)
3216 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3217 if (rtlight->static_numshadowtrispvsbytes)
3218 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3219 if (rtlight->static_numlighttrispvsbytes)
3220 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3221 R_FrameData_SetMark();
3222 switch (rtlight->shadowmode)
3224 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
3225 if (model->CompileShadowMap && rtlight->shadow)
3226 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3229 if (model->CompileShadowVolume && rtlight->shadow)
3230 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3233 R_FrameData_ReturnToMark();
3234 // now we're done compiling the rtlight
3235 r_shadow_compilingrtlight = NULL;
3239 // use smallest available cullradius - box radius or light radius
3240 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3241 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3243 shadowzpasstris = 0;
3244 if (rtlight->static_meshchain_shadow_zpass)
3245 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
3246 shadowzpasstris += mesh->numtriangles;
3248 shadowzfailtris = 0;
3249 if (rtlight->static_meshchain_shadow_zfail)
3250 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
3251 shadowzfailtris += mesh->numtriangles;
3254 if (rtlight->static_numlighttrispvsbytes)
3255 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3256 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3260 if (rtlight->static_numlighttrispvsbytes)
3261 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3262 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3265 if (developer_extra.integer)
3266 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);
3269 void R_RTLight_Uncompile(rtlight_t *rtlight)
3271 if (rtlight->compiled)
3273 if (rtlight->static_meshchain_shadow_zpass)
3274 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
3275 rtlight->static_meshchain_shadow_zpass = NULL;
3276 if (rtlight->static_meshchain_shadow_zfail)
3277 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
3278 rtlight->static_meshchain_shadow_zfail = NULL;
3279 if (rtlight->static_meshchain_shadow_shadowmap)
3280 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
3281 rtlight->static_meshchain_shadow_shadowmap = NULL;
3282 // these allocations are grouped
3283 if (rtlight->static_surfacelist)
3284 Mem_Free(rtlight->static_surfacelist);
3285 rtlight->static_numleafs = 0;
3286 rtlight->static_numleafpvsbytes = 0;
3287 rtlight->static_leaflist = NULL;
3288 rtlight->static_leafpvs = NULL;
3289 rtlight->static_numsurfaces = 0;
3290 rtlight->static_surfacelist = NULL;
3291 rtlight->static_numshadowtrispvsbytes = 0;
3292 rtlight->static_shadowtrispvs = NULL;
3293 rtlight->static_numlighttrispvsbytes = 0;
3294 rtlight->static_lighttrispvs = NULL;
3295 rtlight->compiled = false;
3299 void R_Shadow_UncompileWorldLights(void)
3303 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3304 for (lightindex = 0;lightindex < range;lightindex++)
3306 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3309 R_RTLight_Uncompile(&light->rtlight);
3313 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3317 // reset the count of frustum planes
3318 // see rtlight->cached_frustumplanes definition for how much this array
3320 rtlight->cached_numfrustumplanes = 0;
3322 // haven't implemented a culling path for ortho rendering
3323 if (!r_refdef.view.useperspective)
3325 // check if the light is on screen and copy the 4 planes if it is
3326 for (i = 0;i < 4;i++)
3327 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3330 for (i = 0;i < 4;i++)
3331 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3336 // generate a deformed frustum that includes the light origin, this is
3337 // used to cull shadow casting surfaces that can not possibly cast a
3338 // shadow onto the visible light-receiving surfaces, which can be a
3341 // if the light origin is onscreen the result will be 4 planes exactly
3342 // if the light origin is offscreen on only one axis the result will
3343 // be exactly 5 planes (split-side case)
3344 // if the light origin is offscreen on two axes the result will be
3345 // exactly 4 planes (stretched corner case)
3346 for (i = 0;i < 4;i++)
3348 // quickly reject standard frustum planes that put the light
3349 // origin outside the frustum
3350 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3353 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3355 // if all the standard frustum planes were accepted, the light is onscreen
3356 // otherwise we need to generate some more planes below...
3357 if (rtlight->cached_numfrustumplanes < 4)
3359 // at least one of the stock frustum planes failed, so we need to
3360 // create one or two custom planes to enclose the light origin
3361 for (i = 0;i < 4;i++)
3363 // create a plane using the view origin and light origin, and a
3364 // single point from the frustum corner set
3365 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3366 VectorNormalize(plane.normal);
3367 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3368 // see if this plane is backwards and flip it if so
3369 for (j = 0;j < 4;j++)
3370 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3374 VectorNegate(plane.normal, plane.normal);
3376 // flipped plane, test again to see if it is now valid
3377 for (j = 0;j < 4;j++)
3378 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3380 // if the plane is still not valid, then it is dividing the
3381 // frustum and has to be rejected
3385 // we have created a valid plane, compute extra info
3386 PlaneClassify(&plane);
3388 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3390 // if we've found 5 frustum planes then we have constructed a
3391 // proper split-side case and do not need to keep searching for
3392 // planes to enclose the light origin
3393 if (rtlight->cached_numfrustumplanes == 5)
3401 for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
3403 plane = rtlight->cached_frustumplanes[i];
3404 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));
3409 // now add the light-space box planes if the light box is rotated, as any
3410 // caster outside the oriented light box is irrelevant (even if it passed
3411 // the worldspace light box, which is axial)
3412 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3414 for (i = 0;i < 6;i++)
3418 v[i >> 1] = (i & 1) ? -1 : 1;
3419 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3420 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3421 plane.dist = VectorNormalizeLength(plane.normal);
3422 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3423 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3429 // add the world-space reduced box planes
3430 for (i = 0;i < 6;i++)
3432 VectorClear(plane.normal);
3433 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3434 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
3435 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3444 // reduce all plane distances to tightly fit the rtlight cull box, which
3446 VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3447 VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3448 VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3449 VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3450 VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3451 VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3452 VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3453 VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3454 oldnum = rtlight->cached_numfrustumplanes;
3455 rtlight->cached_numfrustumplanes = 0;
3456 for (j = 0;j < oldnum;j++)
3458 // find the nearest point on the box to this plane
3459 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
3460 for (i = 1;i < 8;i++)
3462 dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
3463 if (bestdist > dist)
3466 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);
3467 // if the nearest point is near or behind the plane, we want this
3468 // plane, otherwise the plane is useless as it won't cull anything
3469 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
3471 PlaneClassify(&rtlight->cached_frustumplanes[j]);
3472 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
3479 void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
3483 RSurf_ActiveWorldEntity();
3485 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3488 GL_CullFace(GL_NONE);
3489 mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3490 for (;mesh;mesh = mesh->next)
3492 if (!mesh->sidetotals[r_shadow_shadowmapside])
3494 r_refdef.stats.lights_shadowtriangles += mesh->sidetotals[r_shadow_shadowmapside];
3495 if (mesh->vertex3fbuffer)
3496 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vertex3fbuffer);
3498 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer);
3499 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);
3503 else if (r_refdef.scene.worldentity->model)
3504 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);
3506 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3509 void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3511 qboolean zpass = false;
3514 int surfacelistindex;
3515 msurface_t *surface;
3517 // if triangle neighbors are disabled, shadowvolumes are disabled
3518 if (r_refdef.scene.worldmodel->brush.shadowmesh ? !r_refdef.scene.worldmodel->brush.shadowmesh->neighbor3i : !r_refdef.scene.worldmodel->surfmesh.data_neighbor3i)
3521 RSurf_ActiveWorldEntity();
3523 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3526 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
3528 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
3529 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
3531 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
3532 for (;mesh;mesh = mesh->next)
3534 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
3535 if (mesh->vertex3fbuffer)
3536 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vertex3fbuffer);
3538 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer);
3539 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
3541 // increment stencil if frontface is infront of depthbuffer
3542 GL_CullFace(r_refdef.view.cullface_back);
3543 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
3544 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);
3545 // decrement stencil if backface is infront of depthbuffer
3546 GL_CullFace(r_refdef.view.cullface_front);
3547 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
3549 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
3551 // decrement stencil if backface is behind depthbuffer
3552 GL_CullFace(r_refdef.view.cullface_front);
3553 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
3554 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);
3555 // increment stencil if frontface is behind depthbuffer
3556 GL_CullFace(r_refdef.view.cullface_back);
3557 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
3559 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);
3563 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh)
3565 // use the shadow trispvs calculated earlier by GetLightInfo to cull world triangles on this dynamic light
3566 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
3567 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
3569 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
3570 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
3571 if (CHECKPVSBIT(trispvs, t))
3572 shadowmarklist[numshadowmark++] = t;
3574 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);
3576 else if (numsurfaces)
3578 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);
3581 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3584 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3586 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3587 vec_t relativeshadowradius;
3588 RSurf_ActiveModelEntity(ent, false, false, false);
3589 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3590 // we need to re-init the shader for each entity because the matrix changed
3591 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3592 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3593 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3594 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3595 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3596 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3597 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3598 switch (r_shadow_rendermode)
3600 case R_SHADOW_RENDERMODE_SHADOWMAP2D:
3601 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
3604 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3607 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3610 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3612 // set up properties for rendering light onto this entity
3613 RSurf_ActiveModelEntity(ent, true, true, false);
3614 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3615 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3616 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3617 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3620 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
3622 if (!r_refdef.scene.worldmodel->DrawLight)
3625 // set up properties for rendering light onto this entity
3626 RSurf_ActiveWorldEntity();
3627 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3628 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3629 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3630 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3632 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
3634 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3637 void R_Shadow_DrawEntityLight(entity_render_t *ent)
3639 dp_model_t *model = ent->model;
3640 if (!model->DrawLight)
3643 R_Shadow_SetupEntityLight(ent);
3645 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3647 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3650 void R_Shadow_PrepareLight(rtlight_t *rtlight)
3654 int numleafs, numsurfaces;
3655 int *leaflist, *surfacelist;
3656 unsigned char *leafpvs;
3657 unsigned char *shadowtrispvs;
3658 unsigned char *lighttrispvs;
3659 //unsigned char *surfacesides;
3660 int numlightentities;
3661 int numlightentities_noselfshadow;
3662 int numshadowentities;
3663 int numshadowentities_noselfshadow;
3664 static entity_render_t *lightentities[MAX_EDICTS];
3665 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3666 static entity_render_t *shadowentities[MAX_EDICTS];
3667 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3670 rtlight->draw = false;
3672 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3673 // skip lights that are basically invisible (color 0 0 0)
3674 nolight = VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f);
3676 // loading is done before visibility checks because loading should happen
3677 // all at once at the start of a level, not when it stalls gameplay.
3678 // (especially important to benchmarks)
3680 if (rtlight->isstatic && !nolight && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
3682 if (rtlight->compiled)
3683 R_RTLight_Uncompile(rtlight);
3684 R_RTLight_Compile(rtlight);
3688 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
3690 // look up the light style value at this time
3691 f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3692 VectorScale(rtlight->color, f, rtlight->currentcolor);
3694 if (rtlight->selected)
3696 f = 2 + sin(realtime * M_PI * 4.0);
3697 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3701 // if lightstyle is currently off, don't draw the light
3702 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3705 // skip processing on corona-only lights
3709 // if the light box is offscreen, skip it
3710 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3713 VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
3714 VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
3716 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3718 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3720 // compiled light, world available and can receive realtime lighting
3721 // retrieve leaf information
3722 numleafs = rtlight->static_numleafs;
3723 leaflist = rtlight->static_leaflist;
3724 leafpvs = rtlight->static_leafpvs;
3725 numsurfaces = rtlight->static_numsurfaces;
3726 surfacelist = rtlight->static_surfacelist;
3727 //surfacesides = NULL;
3728 shadowtrispvs = rtlight->static_shadowtrispvs;
3729 lighttrispvs = rtlight->static_lighttrispvs;
3731 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3733 // dynamic light, world available and can receive realtime lighting
3734 // calculate lit surfaces and leafs
3735 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);
3736 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3737 leaflist = r_shadow_buffer_leaflist;
3738 leafpvs = r_shadow_buffer_leafpvs;
3739 surfacelist = r_shadow_buffer_surfacelist;
3740 //surfacesides = r_shadow_buffer_surfacesides;
3741 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3742 lighttrispvs = r_shadow_buffer_lighttrispvs;
3743 // if the reduced leaf bounds are offscreen, skip it
3744 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3755 //surfacesides = NULL;
3756 shadowtrispvs = NULL;
3757 lighttrispvs = NULL;
3759 // check if light is illuminating any visible leafs
3762 for (i = 0;i < numleafs;i++)
3763 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3769 // make a list of lit entities and shadow casting entities
3770 numlightentities = 0;
3771 numlightentities_noselfshadow = 0;
3772 numshadowentities = 0;
3773 numshadowentities_noselfshadow = 0;
3775 // add dynamic entities that are lit by the light
3776 for (i = 0;i < r_refdef.scene.numentities;i++)
3779 entity_render_t *ent = r_refdef.scene.entities[i];
3781 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3783 // skip the object entirely if it is not within the valid
3784 // shadow-casting region (which includes the lit region)
3785 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
3787 if (!(model = ent->model))
3789 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
3791 // this entity wants to receive light, is visible, and is
3792 // inside the light box
3793 // TODO: check if the surfaces in the model can receive light
3794 // so now check if it's in a leaf seen by the light
3795 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))
3797 if (ent->flags & RENDER_NOSELFSHADOW)
3798 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
3800 lightentities[numlightentities++] = ent;
3801 // since it is lit, it probably also casts a shadow...
3802 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3803 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3804 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3806 // note: exterior models without the RENDER_NOSELFSHADOW
3807 // flag still create a RENDER_NOSELFSHADOW shadow but
3808 // are lit normally, this means that they are
3809 // self-shadowing but do not shadow other
3810 // RENDER_NOSELFSHADOW entities such as the gun
3811 // (very weird, but keeps the player shadow off the gun)
3812 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3813 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3815 shadowentities[numshadowentities++] = ent;
3818 else if (ent->flags & RENDER_SHADOW)
3820 // this entity is not receiving light, but may still need to
3822 // TODO: check if the surfaces in the model can cast shadow
3823 // now check if it is in a leaf seen by the light
3824 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))
3826 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3827 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3828 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3830 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3831 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3833 shadowentities[numshadowentities++] = ent;
3838 // return if there's nothing at all to light
3839 if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
3842 // count this light in the r_speeds
3843 r_refdef.stats.lights++;
3845 // flag it as worth drawing later
3846 rtlight->draw = true;
3848 // cache all the animated entities that cast a shadow but are not visible
3849 for (i = 0;i < numshadowentities;i++)
3850 if (!shadowentities[i]->animcache_vertex3f)
3851 R_AnimCache_GetEntity(shadowentities[i], false, false);
3852 for (i = 0;i < numshadowentities_noselfshadow;i++)
3853 if (!shadowentities_noselfshadow[i]->animcache_vertex3f)
3854 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
3856 // allocate some temporary memory for rendering this light later in the frame
3857 // reusable buffers need to be copied, static data can be used as-is
3858 rtlight->cached_numlightentities = numlightentities;
3859 rtlight->cached_numlightentities_noselfshadow = numlightentities_noselfshadow;
3860 rtlight->cached_numshadowentities = numshadowentities;
3861 rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
3862 rtlight->cached_numsurfaces = numsurfaces;
3863 rtlight->cached_lightentities = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
3864 rtlight->cached_lightentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
3865 rtlight->cached_shadowentities = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
3866 rtlight->cached_shadowentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
3867 if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
3869 int numshadowtrispvsbytes = (((r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles) + 7) >> 3);
3870 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
3871 rtlight->cached_shadowtrispvs = (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
3872 rtlight->cached_lighttrispvs = (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
3873 rtlight->cached_surfacelist = (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
3877 // compiled light data
3878 rtlight->cached_shadowtrispvs = shadowtrispvs;
3879 rtlight->cached_lighttrispvs = lighttrispvs;
3880 rtlight->cached_surfacelist = surfacelist;
3884 void R_Shadow_DrawLight(rtlight_t *rtlight)
3888 unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
3889 int numlightentities;
3890 int numlightentities_noselfshadow;
3891 int numshadowentities;
3892 int numshadowentities_noselfshadow;
3893 entity_render_t **lightentities;
3894 entity_render_t **lightentities_noselfshadow;
3895 entity_render_t **shadowentities;
3896 entity_render_t **shadowentities_noselfshadow;
3898 static unsigned char entitysides[MAX_EDICTS];
3899 static unsigned char entitysides_noselfshadow[MAX_EDICTS];
3900 vec3_t nearestpoint;
3902 qboolean castshadows;
3905 // check if we cached this light this frame (meaning it is worth drawing)
3909 numlightentities = rtlight->cached_numlightentities;
3910 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
3911 numshadowentities = rtlight->cached_numshadowentities;
3912 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
3913 numsurfaces = rtlight->cached_numsurfaces;
3914 lightentities = rtlight->cached_lightentities;
3915 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
3916 shadowentities = rtlight->cached_shadowentities;
3917 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
3918 shadowtrispvs = rtlight->cached_shadowtrispvs;
3919 lighttrispvs = rtlight->cached_lighttrispvs;
3920 surfacelist = rtlight->cached_surfacelist;
3922 // set up a scissor rectangle for this light
3923 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3926 // don't let sound skip if going slow
3927 if (r_refdef.scene.extraupdate)
3930 // make this the active rtlight for rendering purposes
3931 R_Shadow_RenderMode_ActiveLight(rtlight);
3933 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
3935 // optionally draw visible shape of the shadow volumes
3936 // for performance analysis by level designers
3937 R_Shadow_RenderMode_VisibleShadowVolumes();
3939 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
3940 for (i = 0;i < numshadowentities;i++)
3941 R_Shadow_DrawEntityShadow(shadowentities[i]);
3942 for (i = 0;i < numshadowentities_noselfshadow;i++)
3943 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3944 R_Shadow_RenderMode_VisibleLighting(false, false);
3947 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
3949 // optionally draw the illuminated areas
3950 // for performance analysis by level designers
3951 R_Shadow_RenderMode_VisibleLighting(false, false);
3953 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3954 for (i = 0;i < numlightentities;i++)
3955 R_Shadow_DrawEntityLight(lightentities[i]);
3956 for (i = 0;i < numlightentities_noselfshadow;i++)
3957 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3960 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
3962 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
3963 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
3964 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
3965 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
3967 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance/rtlight->radius));
3968 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
3969 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
3971 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
3977 int receivermask = 0;
3978 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
3979 Matrix4x4_Abs(&radiustolight);
3981 r_shadow_shadowmaplod = 0;
3982 for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
3983 if ((r_shadow_shadowmapmaxsize >> i) > lodlinear)
3984 r_shadow_shadowmaplod = i;
3986 size = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
3988 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
3990 surfacesides = NULL;
3993 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3995 castermask = rtlight->static_shadowmap_casters;
3996 receivermask = rtlight->static_shadowmap_receivers;
4000 surfacesides = r_shadow_buffer_surfacesides;
4001 for(i = 0;i < numsurfaces;i++)
4003 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
4004 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4005 castermask |= surfacesides[i];
4006 receivermask |= surfacesides[i];
4010 if (receivermask < 0x3F)
4012 for (i = 0;i < numlightentities;i++)
4013 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4014 if (receivermask < 0x3F)
4015 for(i = 0; i < numlightentities_noselfshadow;i++)
4016 receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4019 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
4023 for (i = 0;i < numshadowentities;i++)
4024 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
4025 for (i = 0;i < numshadowentities_noselfshadow;i++)
4026 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
4029 //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
4031 // render shadow casters into 6 sided depth texture
4032 for (side = 0;side < 6;side++) if (receivermask & (1 << side))
4034 R_Shadow_RenderMode_ShadowMap(side, receivermask, size);
4035 if (! (castermask & (1 << side))) continue;
4037 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
4038 for (i = 0;i < numshadowentities;i++) if (entitysides[i] & (1 << side))
4039 R_Shadow_DrawEntityShadow(shadowentities[i]);
4042 if (numlightentities_noselfshadow)
4044 // render lighting using the depth texture as shadowmap
4045 // draw lighting in the unmasked areas
4046 R_Shadow_RenderMode_Lighting(false, false, true);
4047 for (i = 0;i < numlightentities_noselfshadow;i++)
4048 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4051 // render shadow casters into 6 sided depth texture
4052 if (numshadowentities_noselfshadow)
4054 for (side = 0;side < 6;side++) if ((receivermask & castermask) & (1 << side))
4056 R_Shadow_RenderMode_ShadowMap(side, 0, size);
4057 for (i = 0;i < numshadowentities_noselfshadow;i++) if (entitysides_noselfshadow[i] & (1 << side))
4058 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
4062 // render lighting using the depth texture as shadowmap
4063 // draw lighting in the unmasked areas
4064 R_Shadow_RenderMode_Lighting(false, false, true);
4065 // draw lighting in the unmasked areas
4067 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4068 for (i = 0;i < numlightentities;i++)
4069 R_Shadow_DrawEntityLight(lightentities[i]);
4071 else if (castshadows && vid.stencil)
4073 // draw stencil shadow volumes to mask off pixels that are in shadow
4074 // so that they won't receive lighting
4075 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
4076 R_Shadow_ClearStencil();
4079 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
4080 for (i = 0;i < numshadowentities;i++)
4081 R_Shadow_DrawEntityShadow(shadowentities[i]);
4083 // draw lighting in the unmasked areas
4084 R_Shadow_RenderMode_Lighting(true, false, false);
4085 for (i = 0;i < numlightentities_noselfshadow;i++)
4086 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4088 for (i = 0;i < numshadowentities_noselfshadow;i++)
4089 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
4091 // draw lighting in the unmasked areas
4092 R_Shadow_RenderMode_Lighting(true, false, false);
4094 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4095 for (i = 0;i < numlightentities;i++)
4096 R_Shadow_DrawEntityLight(lightentities[i]);
4100 // draw lighting in the unmasked areas
4101 R_Shadow_RenderMode_Lighting(false, false, false);
4103 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4104 for (i = 0;i < numlightentities;i++)
4105 R_Shadow_DrawEntityLight(lightentities[i]);
4106 for (i = 0;i < numlightentities_noselfshadow;i++)
4107 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4110 if (r_shadow_usingdeferredprepass)
4112 // when rendering deferred lighting, we simply rasterize the box
4113 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
4114 R_Shadow_RenderMode_DrawDeferredLight(false, true);
4115 else if (castshadows && vid.stencil)
4116 R_Shadow_RenderMode_DrawDeferredLight(true, false);
4118 R_Shadow_RenderMode_DrawDeferredLight(false, false);
4122 static void R_Shadow_FreeDeferred(void)
4124 R_Mesh_DestroyFramebufferObject(r_shadow_prepassgeometryfbo);
4125 r_shadow_prepassgeometryfbo = 0;
4127 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusespecularfbo);
4128 r_shadow_prepasslightingdiffusespecularfbo = 0;
4130 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusefbo);
4131 r_shadow_prepasslightingdiffusefbo = 0;
4133 if (r_shadow_prepassgeometrydepthtexture)
4134 R_FreeTexture(r_shadow_prepassgeometrydepthtexture);
4135 r_shadow_prepassgeometrydepthtexture = NULL;
4137 if (r_shadow_prepassgeometrydepthcolortexture)
4138 R_FreeTexture(r_shadow_prepassgeometrydepthcolortexture);
4139 r_shadow_prepassgeometrydepthcolortexture = NULL;
4141 if (r_shadow_prepassgeometrynormalmaptexture)
4142 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
4143 r_shadow_prepassgeometrynormalmaptexture = NULL;
4145 if (r_shadow_prepasslightingdiffusetexture)
4146 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
4147 r_shadow_prepasslightingdiffusetexture = NULL;
4149 if (r_shadow_prepasslightingspeculartexture)
4150 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
4151 r_shadow_prepasslightingspeculartexture = NULL;
4154 void R_Shadow_DrawPrepass(void)
4162 entity_render_t *ent;
4163 float clearcolor[4];
4165 R_Mesh_ResetTextureState();
4167 GL_ColorMask(1,1,1,1);
4168 GL_BlendFunc(GL_ONE, GL_ZERO);
4171 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, r_shadow_prepassgeometrydepthcolortexture, NULL, NULL);
4172 Vector4Set(clearcolor, 0.5f,0.5f,0.5f,1.0f);
4173 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4174 if (r_timereport_active)
4175 R_TimeReport("prepasscleargeom");
4177 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
4178 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
4179 if (r_timereport_active)
4180 R_TimeReport("prepassworld");
4182 for (i = 0;i < r_refdef.scene.numentities;i++)
4184 if (!r_refdef.viewcache.entityvisible[i])
4186 ent = r_refdef.scene.entities[i];
4187 if (ent->model && ent->model->DrawPrepass != NULL)
4188 ent->model->DrawPrepass(ent);
4191 if (r_timereport_active)
4192 R_TimeReport("prepassmodels");
4194 GL_DepthMask(false);
4195 GL_ColorMask(1,1,1,1);
4198 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4199 Vector4Set(clearcolor, 0, 0, 0, 0);
4200 GL_Clear(GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
4201 if (r_timereport_active)
4202 R_TimeReport("prepassclearlit");
4204 R_Shadow_RenderMode_Begin();
4206 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4207 if (r_shadow_debuglight.integer >= 0)
4209 lightindex = r_shadow_debuglight.integer;
4210 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4211 if (light && (light->flags & flag) && light->rtlight.draw)
4212 R_Shadow_DrawLight(&light->rtlight);
4216 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4217 for (lightindex = 0;lightindex < range;lightindex++)
4219 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4220 if (light && (light->flags & flag) && light->rtlight.draw)
4221 R_Shadow_DrawLight(&light->rtlight);
4224 if (r_refdef.scene.rtdlight)
4225 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4226 if (r_refdef.scene.lights[lnum]->draw)
4227 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4229 R_Mesh_ResetRenderTargets();
4231 R_Shadow_RenderMode_End();
4233 if (r_timereport_active)
4234 R_TimeReport("prepasslights");
4237 void R_Shadow_DrawLightSprites(void);
4238 void R_Shadow_PrepareLights(void)
4248 if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4) ||
4249 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
4250 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20) ||
4251 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
4252 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
4253 r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
4254 R_Shadow_FreeShadowMaps();
4256 r_shadow_usingshadowmaportho = false;
4258 switch (vid.renderpath)
4260 case RENDERPATH_GL20:
4261 case RENDERPATH_D3D9:
4262 case RENDERPATH_D3D10:
4263 case RENDERPATH_D3D11:
4264 case RENDERPATH_SOFT:
4265 case RENDERPATH_GLES2:
4266 if (!r_shadow_deferred.integer || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_STENCIL || !vid.support.ext_framebuffer_object || vid.maxdrawbuffers < 2)
4268 r_shadow_usingdeferredprepass = false;
4269 if (r_shadow_prepass_width)
4270 R_Shadow_FreeDeferred();
4271 r_shadow_prepass_width = r_shadow_prepass_height = 0;
4275 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
4277 R_Shadow_FreeDeferred();
4279 r_shadow_usingdeferredprepass = true;
4280 r_shadow_prepass_width = vid.width;
4281 r_shadow_prepass_height = vid.height;
4282 r_shadow_prepassgeometrydepthtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "prepassgeometrydepthmap", vid.width, vid.height, 24, false);
4283 switch (vid.renderpath)
4285 case RENDERPATH_D3D9:
4286 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);
4291 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);
4292 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);
4293 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);
4295 // set up the geometry pass fbo (depth + normalmap)
4296 r_shadow_prepassgeometryfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4297 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, r_shadow_prepassgeometrydepthcolortexture, NULL, NULL);
4298 // render depth into one texture and normalmap into the other
4299 if (qglDrawBuffersARB)
4301 qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);CHECKGLERROR
4302 qglReadBuffer(GL_NONE);CHECKGLERROR
4303 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4304 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4306 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4307 Cvar_SetValueQuick(&r_shadow_deferred, 0);
4308 r_shadow_usingdeferredprepass = false;
4312 // set up the lighting pass fbo (diffuse + specular)
4313 r_shadow_prepasslightingdiffusespecularfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4314 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4315 // render diffuse into one texture and specular into another,
4316 // with depth and normalmap bound as textures,
4317 // with depth bound as attachment as well
4318 if (qglDrawBuffersARB)
4320 qglDrawBuffersARB(2, r_shadow_prepasslightingdrawbuffers);CHECKGLERROR
4321 qglReadBuffer(GL_NONE);CHECKGLERROR
4322 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4323 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4325 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4326 Cvar_SetValueQuick(&r_shadow_deferred, 0);
4327 r_shadow_usingdeferredprepass = false;
4331 // set up the lighting pass fbo (diffuse)
4332 r_shadow_prepasslightingdiffusefbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
4333 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
4334 // render diffuse into one texture,
4335 // with depth and normalmap bound as textures,
4336 // with depth bound as attachment as well
4337 if (qglDrawBuffersARB)
4339 qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);CHECKGLERROR
4340 qglReadBuffer(GL_NONE);CHECKGLERROR
4341 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4342 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4344 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4345 Cvar_SetValueQuick(&r_shadow_deferred, 0);
4346 r_shadow_usingdeferredprepass = false;
4351 case RENDERPATH_GL13:
4352 case RENDERPATH_GL11:
4353 r_shadow_usingdeferredprepass = false;
4357 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);
4359 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4360 if (r_shadow_debuglight.integer >= 0)
4362 lightindex = r_shadow_debuglight.integer;
4363 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4364 if (light && (light->flags & flag))
4365 R_Shadow_PrepareLight(&light->rtlight);
4369 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4370 for (lightindex = 0;lightindex < range;lightindex++)
4372 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4373 if (light && (light->flags & flag))
4374 R_Shadow_PrepareLight(&light->rtlight);
4377 if (r_refdef.scene.rtdlight)
4379 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4380 R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
4382 else if(gl_flashblend.integer)
4384 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4386 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
4387 f = (rtlight->style >= 0 ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4388 VectorScale(rtlight->color, f, rtlight->currentcolor);
4392 if (r_editlights.integer)
4393 R_Shadow_DrawLightSprites();
4395 R_Shadow_UpdateBounceGridTexture();
4398 void R_Shadow_DrawLights(void)
4406 R_Shadow_RenderMode_Begin();
4408 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4409 if (r_shadow_debuglight.integer >= 0)
4411 lightindex = r_shadow_debuglight.integer;
4412 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4413 if (light && (light->flags & flag))
4414 R_Shadow_DrawLight(&light->rtlight);
4418 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4419 for (lightindex = 0;lightindex < range;lightindex++)
4421 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4422 if (light && (light->flags & flag))
4423 R_Shadow_DrawLight(&light->rtlight);
4426 if (r_refdef.scene.rtdlight)
4427 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4428 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4430 R_Shadow_RenderMode_End();
4433 extern const float r_screenvertex3f[12];
4434 extern void R_SetupView(qboolean allowwaterclippingplane);
4435 extern void R_ResetViewRendering3D(void);
4436 extern void R_ResetViewRendering2D(void);
4437 extern cvar_t r_shadows;
4438 extern cvar_t r_shadows_darken;
4439 extern cvar_t r_shadows_drawafterrtlighting;
4440 extern cvar_t r_shadows_castfrombmodels;
4441 extern cvar_t r_shadows_throwdistance;
4442 extern cvar_t r_shadows_throwdirection;
4443 extern cvar_t r_shadows_focus;
4444 extern cvar_t r_shadows_shadowmapscale;
4446 void R_Shadow_PrepareModelShadows(void)
4449 float scale, size, radius, dot1, dot2;
4450 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
4451 entity_render_t *ent;
4453 if (!r_refdef.scene.numentities)
4456 switch (r_shadow_shadowmode)
4458 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4459 if (r_shadows.integer >= 2)
4462 case R_SHADOW_SHADOWMODE_STENCIL:
4463 for (i = 0;i < r_refdef.scene.numentities;i++)
4465 ent = r_refdef.scene.entities[i];
4466 if (!ent->animcache_vertex3f && ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4467 R_AnimCache_GetEntity(ent, false, false);
4474 size = 2*r_shadow_shadowmapmaxsize;
4475 scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
4476 radius = 0.5f * size / scale;
4478 Math_atov(r_shadows_throwdirection.string, shadowdir);
4479 VectorNormalize(shadowdir);
4480 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4481 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4482 if (fabs(dot1) <= fabs(dot2))
4483 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4485 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4486 VectorNormalize(shadowforward);
4487 CrossProduct(shadowdir, shadowforward, shadowright);
4488 Math_atov(r_shadows_focus.string, shadowfocus);
4489 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4490 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4491 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4492 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4493 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4495 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4497 shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4498 shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4499 shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4500 shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4501 shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4502 shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4504 for (i = 0;i < r_refdef.scene.numentities;i++)
4506 ent = r_refdef.scene.entities[i];
4507 if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
4509 // cast shadows from anything of the map (submodels are optional)
4510 if (!ent->animcache_vertex3f && ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4511 R_AnimCache_GetEntity(ent, false, false);
4515 void R_DrawModelShadowMaps(void)
4518 float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
4519 entity_render_t *ent;
4520 vec3_t relativelightorigin;
4521 vec3_t relativelightdirection, relativeforward, relativeright;
4522 vec3_t relativeshadowmins, relativeshadowmaxs;
4523 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
4525 matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
4526 r_viewport_t viewport;
4528 float clearcolor[4];
4530 if (!r_refdef.scene.numentities)
4533 switch (r_shadow_shadowmode)
4535 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4541 R_ResetViewRendering3D();
4542 R_Shadow_RenderMode_Begin();
4543 R_Shadow_RenderMode_ActiveLight(NULL);
4545 switch (r_shadow_shadowmode)
4547 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4548 if (!r_shadow_shadowmap2dtexture)
4549 R_Shadow_MakeShadowMap(0, r_shadow_shadowmapmaxsize);
4550 fbo = r_shadow_fbo2d;
4551 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
4552 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
4553 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
4559 size = 2*r_shadow_shadowmapmaxsize;
4560 scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
4561 radius = 0.5f / scale;
4562 nearclip = -r_shadows_throwdistance.value;
4563 farclip = r_shadows_throwdistance.value;
4564 bias = r_shadow_shadowmapping_bias.value * r_shadow_shadowmapping_nearclip.value / (2 * r_shadows_throwdistance.value) * (1024.0f / size);
4566 r_shadow_shadowmap_parameters[0] = size;
4567 r_shadow_shadowmap_parameters[1] = size;
4568 r_shadow_shadowmap_parameters[2] = 1.0;
4569 r_shadow_shadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
4571 Math_atov(r_shadows_throwdirection.string, shadowdir);
4572 VectorNormalize(shadowdir);
4573 Math_atov(r_shadows_focus.string, shadowfocus);
4574 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4575 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4576 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4577 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4578 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4579 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4580 if (fabs(dot1) <= fabs(dot2))
4581 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4583 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4584 VectorNormalize(shadowforward);
4585 VectorM(scale, shadowforward, &m[0]);
4586 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4588 m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
4589 CrossProduct(shadowdir, shadowforward, shadowright);
4590 VectorM(scale, shadowright, &m[4]);
4591 m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
4592 VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
4593 m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
4594 Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
4595 Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
4596 R_Viewport_InitOrtho(&viewport, &cameramatrix, 0, 0, size, size, 0, 0, 1, 1, 0, -1, NULL);
4598 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4600 R_Mesh_SetRenderTargets(fbo, r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
4601 R_SetupShader_DepthOrShadow();
4602 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
4605 R_SetViewport(&viewport);
4606 GL_Scissor(viewport.x, viewport.y, min(viewport.width + r_shadow_shadowmapborder, 2*r_shadow_shadowmapmaxsize), viewport.height + r_shadow_shadowmapborder);
4607 Vector4Set(clearcolor, 1,1,1,1);
4608 // in D3D9 we have to render to a color texture shadowmap
4609 // in GL we render directly to a depth texture only
4610 if (r_shadow_shadowmap2dtexture)
4611 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4613 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4614 // render into a slightly restricted region so that the borders of the
4615 // shadowmap area fade away, rather than streaking across everything
4616 // outside the usable area
4617 GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
4621 R_Mesh_ResetRenderTargets();
4622 R_SetupShader_ShowDepth();
4623 GL_ColorMask(1,1,1,1);
4624 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4627 for (i = 0;i < r_refdef.scene.numentities;i++)
4629 ent = r_refdef.scene.entities[i];
4631 // cast shadows from anything of the map (submodels are optional)
4632 if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4634 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4635 Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
4636 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4637 Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
4638 Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
4639 relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4640 relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4641 relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4642 relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4643 relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4644 relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4645 RSurf_ActiveModelEntity(ent, false, false, false);
4646 ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
4647 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4654 unsigned char *rawpixels = Z_Malloc(viewport.width*viewport.height*4);
4656 qglReadPixels(viewport.x, viewport.y, viewport.width, viewport.height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, rawpixels);
4658 Image_WriteTGABGRA("r_shadows_2.tga", viewport.width, viewport.height, rawpixels);
4659 Cvar_SetValueQuick(&r_test, 0);
4664 R_Shadow_RenderMode_End();
4666 Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
4667 Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
4668 Matrix4x4_CreateScale3(&scalematrix, size, -size, 1);
4669 Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
4670 Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
4671 Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
4673 switch (vid.renderpath)
4675 case RENDERPATH_GL11:
4676 case RENDERPATH_GL13:
4677 case RENDERPATH_GL20:
4678 case RENDERPATH_SOFT:
4679 case RENDERPATH_GLES2:
4681 case RENDERPATH_D3D9:
4682 case RENDERPATH_D3D10:
4683 case RENDERPATH_D3D11:
4684 #ifdef OPENGL_ORIENTATION
4685 r_shadow_shadowmapmatrix.m[0][0] *= -1.0f;
4686 r_shadow_shadowmapmatrix.m[0][1] *= -1.0f;
4687 r_shadow_shadowmapmatrix.m[0][2] *= -1.0f;
4688 r_shadow_shadowmapmatrix.m[0][3] *= -1.0f;
4690 r_shadow_shadowmapmatrix.m[0][0] *= -1.0f;
4691 r_shadow_shadowmapmatrix.m[1][0] *= -1.0f;
4692 r_shadow_shadowmapmatrix.m[2][0] *= -1.0f;
4693 r_shadow_shadowmapmatrix.m[3][0] *= -1.0f;
4698 r_shadow_usingshadowmaportho = true;
4699 switch (r_shadow_shadowmode)
4701 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4702 r_shadow_usingshadowmap2d = true;
4709 void R_DrawModelShadows(void)
4712 float relativethrowdistance;
4713 entity_render_t *ent;
4714 vec3_t relativelightorigin;
4715 vec3_t relativelightdirection;
4716 vec3_t relativeshadowmins, relativeshadowmaxs;
4717 vec3_t tmp, shadowdir;
4719 if (!r_refdef.scene.numentities || !vid.stencil || (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL && r_shadows.integer != 1))
4722 R_ResetViewRendering3D();
4723 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4724 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4725 R_Shadow_RenderMode_Begin();
4726 R_Shadow_RenderMode_ActiveLight(NULL);
4727 r_shadow_lightscissor[0] = r_refdef.view.x;
4728 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
4729 r_shadow_lightscissor[2] = r_refdef.view.width;
4730 r_shadow_lightscissor[3] = r_refdef.view.height;
4731 R_Shadow_RenderMode_StencilShadowVolumes(false);
4734 if (r_shadows.integer == 2)
4736 Math_atov(r_shadows_throwdirection.string, shadowdir);
4737 VectorNormalize(shadowdir);
4740 R_Shadow_ClearStencil();
4742 for (i = 0;i < r_refdef.scene.numentities;i++)
4744 ent = r_refdef.scene.entities[i];
4746 // cast shadows from anything of the map (submodels are optional)
4747 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4749 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4750 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
4751 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
4752 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
4753 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4756 if(ent->entitynumber != 0)
4758 if(ent->entitynumber >= MAX_EDICTS) // csqc entity
4760 // FIXME handle this
4761 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4765 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
4766 int entnum, entnum2, recursion;
4767 entnum = entnum2 = ent->entitynumber;
4768 for(recursion = 32; recursion > 0; --recursion)
4770 entnum2 = cl.entities[entnum].state_current.tagentity;
4771 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
4776 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
4778 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
4779 // transform into modelspace of OUR entity
4780 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
4781 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
4784 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4788 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4791 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
4792 RSurf_ActiveModelEntity(ent, false, false, false);
4793 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4794 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4798 // not really the right mode, but this will disable any silly stencil features
4799 R_Shadow_RenderMode_End();
4801 // set up ortho view for rendering this pass
4802 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4803 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4804 //GL_ScissorTest(true);
4805 //R_EntityMatrix(&identitymatrix);
4806 //R_Mesh_ResetTextureState();
4807 R_ResetViewRendering2D();
4809 // set up a darkening blend on shadowed areas
4810 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4811 //GL_DepthRange(0, 1);
4812 //GL_DepthTest(false);
4813 //GL_DepthMask(false);
4814 //GL_PolygonOffset(0, 0);CHECKGLERROR
4815 GL_Color(0, 0, 0, r_shadows_darken.value);
4816 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4817 //GL_DepthFunc(GL_ALWAYS);
4818 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_NOTEQUAL, 128, 255);
4820 // apply the blend to the shadowed areas
4821 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, NULL);
4822 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
4823 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4825 // restore the viewport
4826 R_SetViewport(&r_refdef.view.viewport);
4828 // restore other state to normal
4829 //R_Shadow_RenderMode_End();
4832 void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4835 vec3_t centerorigin;
4837 // if it's too close, skip it
4838 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
4840 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4843 if (usequery && r_numqueries + 2 <= r_maxqueries)
4845 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4846 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4847 // 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
4848 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4850 switch(vid.renderpath)
4852 case RENDERPATH_GL20:
4853 case RENDERPATH_GL13:
4854 case RENDERPATH_GL11:
4855 case RENDERPATH_GLES2:
4857 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use GL_DepthFunc instead
4858 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
4859 GL_DepthFunc(GL_ALWAYS);
4860 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4861 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL);
4862 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4863 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4864 GL_DepthFunc(GL_LEQUAL);
4865 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
4866 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4867 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL);
4868 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4869 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4872 case RENDERPATH_D3D9:
4873 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4875 case RENDERPATH_D3D10:
4876 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4878 case RENDERPATH_D3D11:
4879 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4881 case RENDERPATH_SOFT:
4882 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4886 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4889 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
4891 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4894 GLint allpixels = 0, visiblepixels = 0;
4895 // now we have to check the query result
4896 if (rtlight->corona_queryindex_visiblepixels)
4898 switch(vid.renderpath)
4900 case RENDERPATH_GL20:
4901 case RENDERPATH_GL13:
4902 case RENDERPATH_GL11:
4903 case RENDERPATH_GLES2:
4905 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
4906 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
4909 case RENDERPATH_D3D9:
4910 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4912 case RENDERPATH_D3D10:
4913 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4915 case RENDERPATH_D3D11:
4916 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4918 case RENDERPATH_SOFT:
4919 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4922 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
4923 if (visiblepixels < 1 || allpixels < 1)
4925 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
4926 cscale *= rtlight->corona_visibility;
4930 // FIXME: these traces should scan all render entities instead of cl.world
4931 if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false, true).fraction < 1)
4934 VectorScale(rtlight->currentcolor, cscale, color);
4935 if (VectorLength(color) > (1.0f / 256.0f))
4938 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
4941 VectorNegate(color, color);
4942 switch(vid.renderpath)
4944 case RENDERPATH_GL11:
4945 case RENDERPATH_GL13:
4946 case RENDERPATH_GL20:
4947 case RENDERPATH_GLES2:
4948 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
4950 case RENDERPATH_D3D9:
4952 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_SUBTRACT);
4955 case RENDERPATH_D3D10:
4956 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4958 case RENDERPATH_D3D11:
4959 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4961 case RENDERPATH_SOFT:
4962 DPSOFTRAST_BlendSubtract(true);
4966 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4967 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);
4968 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4971 switch(vid.renderpath)
4973 case RENDERPATH_GL11:
4974 case RENDERPATH_GL13:
4975 case RENDERPATH_GL20:
4976 case RENDERPATH_GLES2:
4977 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
4979 case RENDERPATH_D3D9:
4981 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_ADD);
4984 case RENDERPATH_D3D10:
4985 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4987 case RENDERPATH_D3D11:
4988 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4990 case RENDERPATH_SOFT:
4991 DPSOFTRAST_BlendSubtract(false);
4998 void R_Shadow_DrawCoronas(void)
5001 qboolean usequery = false;
5006 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
5008 if (r_waterstate.renderingscene)
5010 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
5011 R_EntityMatrix(&identitymatrix);
5013 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5015 // check occlusion of coronas
5016 // use GL_ARB_occlusion_query if available
5017 // otherwise use raytraces
5019 switch (vid.renderpath)
5021 case RENDERPATH_GL11:
5022 case RENDERPATH_GL13:
5023 case RENDERPATH_GL20:
5024 case RENDERPATH_GLES2:
5025 usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
5028 GL_ColorMask(0,0,0,0);
5029 if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
5030 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
5033 r_maxqueries = (range + r_refdef.scene.numlights) * 4;
5034 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
5036 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
5039 RSurf_ActiveWorldEntity();
5040 GL_BlendFunc(GL_ONE, GL_ZERO);
5041 GL_CullFace(GL_NONE);
5042 GL_DepthMask(false);
5043 GL_DepthRange(0, 1);
5044 GL_PolygonOffset(0, 0);
5046 R_Mesh_ResetTextureState();
5047 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
5050 case RENDERPATH_D3D9:
5052 //Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5054 case RENDERPATH_D3D10:
5055 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5057 case RENDERPATH_D3D11:
5058 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5060 case RENDERPATH_SOFT:
5062 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5065 for (lightindex = 0;lightindex < range;lightindex++)
5067 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5070 rtlight = &light->rtlight;
5071 rtlight->corona_visibility = 0;
5072 rtlight->corona_queryindex_visiblepixels = 0;
5073 rtlight->corona_queryindex_allpixels = 0;
5074 if (!(rtlight->flags & flag))
5076 if (rtlight->corona <= 0)
5078 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
5080 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
5082 for (i = 0;i < r_refdef.scene.numlights;i++)
5084 rtlight = r_refdef.scene.lights[i];
5085 rtlight->corona_visibility = 0;
5086 rtlight->corona_queryindex_visiblepixels = 0;
5087 rtlight->corona_queryindex_allpixels = 0;
5088 if (!(rtlight->flags & flag))
5090 if (rtlight->corona <= 0)
5092 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
5095 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5097 // now draw the coronas using the query data for intensity info
5098 for (lightindex = 0;lightindex < range;lightindex++)
5100 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5103 rtlight = &light->rtlight;
5104 if (rtlight->corona_visibility <= 0)
5106 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
5108 for (i = 0;i < r_refdef.scene.numlights;i++)
5110 rtlight = r_refdef.scene.lights[i];
5111 if (rtlight->corona_visibility <= 0)
5113 if (gl_flashblend.integer)
5114 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
5116 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
5122 dlight_t *R_Shadow_NewWorldLight(void)
5124 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
5127 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)
5130 // validate parameters
5131 if (style < 0 || style >= MAX_LIGHTSTYLES)
5133 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
5139 // copy to light properties
5140 VectorCopy(origin, light->origin);
5141 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
5142 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
5143 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
5145 light->color[0] = max(color[0], 0);
5146 light->color[1] = max(color[1], 0);
5147 light->color[2] = max(color[2], 0);
5149 light->color[0] = color[0];
5150 light->color[1] = color[1];
5151 light->color[2] = color[2];
5152 light->radius = max(radius, 0);
5153 light->style = style;
5154 light->shadow = shadowenable;
5155 light->corona = corona;
5156 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
5157 light->coronasizescale = coronasizescale;
5158 light->ambientscale = ambientscale;
5159 light->diffusescale = diffusescale;
5160 light->specularscale = specularscale;
5161 light->flags = flags;
5163 // update renderable light data
5164 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
5165 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);
5168 void R_Shadow_FreeWorldLight(dlight_t *light)
5170 if (r_shadow_selectedlight == light)
5171 r_shadow_selectedlight = NULL;
5172 R_RTLight_Uncompile(&light->rtlight);
5173 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
5176 void R_Shadow_ClearWorldLights(void)
5180 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5181 for (lightindex = 0;lightindex < range;lightindex++)
5183 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5185 R_Shadow_FreeWorldLight(light);
5187 r_shadow_selectedlight = NULL;
5190 void R_Shadow_SelectLight(dlight_t *light)
5192 if (r_shadow_selectedlight)
5193 r_shadow_selectedlight->selected = false;
5194 r_shadow_selectedlight = light;
5195 if (r_shadow_selectedlight)
5196 r_shadow_selectedlight->selected = true;
5199 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
5201 // this is never batched (there can be only one)
5203 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
5204 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
5205 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5208 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
5213 skinframe_t *skinframe;
5216 // this is never batched (due to the ent parameter changing every time)
5217 // so numsurfaces == 1 and surfacelist[0] == lightnumber
5218 const dlight_t *light = (dlight_t *)ent;
5221 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
5224 VectorScale(light->color, intensity, spritecolor);
5225 if (VectorLength(spritecolor) < 0.1732f)
5226 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
5227 if (VectorLength(spritecolor) > 1.0f)
5228 VectorNormalize(spritecolor);
5230 // draw light sprite
5231 if (light->cubemapname[0] && !light->shadow)
5232 skinframe = r_editlights_sprcubemapnoshadowlight;
5233 else if (light->cubemapname[0])
5234 skinframe = r_editlights_sprcubemaplight;
5235 else if (!light->shadow)
5236 skinframe = r_editlights_sprnoshadowlight;
5238 skinframe = r_editlights_sprlight;
5240 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);
5241 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5243 // draw selection sprite if light is selected
5244 if (light->selected)
5246 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
5247 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5248 // VorteX todo: add normalmode/realtime mode light overlay sprites?
5252 void R_Shadow_DrawLightSprites(void)
5256 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5257 for (lightindex = 0;lightindex < range;lightindex++)
5259 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5261 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
5263 if (!r_editlights_lockcursor)
5264 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
5267 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
5272 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
5273 if (lightindex >= range)
5275 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5278 rtlight = &light->rtlight;
5279 //if (!(rtlight->flags & flag))
5281 VectorCopy(rtlight->shadoworigin, origin);
5282 *radius = rtlight->radius;
5283 VectorCopy(rtlight->color, color);
5287 void R_Shadow_SelectLightInView(void)
5289 float bestrating, rating, temp[3];
5293 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5297 if (r_editlights_lockcursor)
5299 for (lightindex = 0;lightindex < range;lightindex++)
5301 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5304 VectorSubtract(light->origin, r_refdef.view.origin, temp);
5305 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
5308 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
5309 if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false, true).fraction == 1.0f)
5311 bestrating = rating;
5316 R_Shadow_SelectLight(best);
5319 void R_Shadow_LoadWorldLights(void)
5321 int n, a, style, shadow, flags;
5322 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
5323 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
5324 if (cl.worldmodel == NULL)
5326 Con_Print("No map loaded.\n");
5329 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
5330 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5340 for (;COM_Parse(t, true) && strcmp(
5341 if (COM_Parse(t, true))
5343 if (com_token[0] == '!')
5346 origin[0] = atof(com_token+1);
5349 origin[0] = atof(com_token);
5354 while (*s && *s != '\n' && *s != '\r')
5360 // check for modifier flags
5367 #if _MSC_VER >= 1400
5368 #define sscanf sscanf_s
5370 cubemapname[sizeof(cubemapname)-1] = 0;
5371 #if MAX_QPATH != 128
5372 #error update this code if MAX_QPATH changes
5374 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
5375 #if _MSC_VER >= 1400
5376 , sizeof(cubemapname)
5378 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
5381 flags = LIGHTFLAG_REALTIMEMODE;
5389 coronasizescale = 0.25f;
5391 VectorClear(angles);
5394 if (a < 9 || !strcmp(cubemapname, "\"\""))
5396 // remove quotes on cubemapname
5397 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
5400 namelen = strlen(cubemapname) - 2;
5401 memmove(cubemapname, cubemapname + 1, namelen);
5402 cubemapname[namelen] = '\0';
5406 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);
5409 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5417 Con_Printf("invalid rtlights file \"%s\"\n", name);
5418 Mem_Free(lightsstring);
5422 void R_Shadow_SaveWorldLights(void)
5426 size_t bufchars, bufmaxchars;
5428 char name[MAX_QPATH];
5429 char line[MAX_INPUTLINE];
5430 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
5431 // I hate lines which are 3 times my screen size :( --blub
5434 if (cl.worldmodel == NULL)
5436 Con_Print("No map loaded.\n");
5439 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
5440 bufchars = bufmaxchars = 0;
5442 for (lightindex = 0;lightindex < range;lightindex++)
5444 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5447 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
5448 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);
5449 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
5450 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]);
5452 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);
5453 if (bufchars + strlen(line) > bufmaxchars)
5455 bufmaxchars = bufchars + strlen(line) + 2048;
5457 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
5461 memcpy(buf, oldbuf, bufchars);
5467 memcpy(buf + bufchars, line, strlen(line));
5468 bufchars += strlen(line);
5472 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
5477 void R_Shadow_LoadLightsFile(void)
5480 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
5481 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
5482 if (cl.worldmodel == NULL)
5484 Con_Print("No map loaded.\n");
5487 dpsnprintf(name, sizeof(name), "%s.lights", cl.worldnamenoextension);
5488 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5496 while (*s && *s != '\n' && *s != '\r')
5502 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);
5506 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);
5509 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
5510 radius = bound(15, radius, 4096);
5511 VectorScale(color, (2.0f / (8388608.0f)), color);
5512 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5520 Con_Printf("invalid lights file \"%s\"\n", name);
5521 Mem_Free(lightsstring);
5525 // tyrlite/hmap2 light types in the delay field
5526 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
5528 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
5540 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
5541 char key[256], value[MAX_INPUTLINE];
5543 if (cl.worldmodel == NULL)
5545 Con_Print("No map loaded.\n");
5548 // try to load a .ent file first
5549 dpsnprintf(key, sizeof(key), "%s.ent", cl.worldnamenoextension);
5550 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
5551 // and if that is not found, fall back to the bsp file entity string
5553 data = cl.worldmodel->brush.entities;
5556 for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
5558 type = LIGHTTYPE_MINUSX;
5559 origin[0] = origin[1] = origin[2] = 0;
5560 originhack[0] = originhack[1] = originhack[2] = 0;
5561 angles[0] = angles[1] = angles[2] = 0;
5562 color[0] = color[1] = color[2] = 1;
5563 light[0] = light[1] = light[2] = 1;light[3] = 300;
5564 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
5574 if (!COM_ParseToken_Simple(&data, false, false))
5576 if (com_token[0] == '}')
5577 break; // end of entity
5578 if (com_token[0] == '_')
5579 strlcpy(key, com_token + 1, sizeof(key));
5581 strlcpy(key, com_token, sizeof(key));
5582 while (key[strlen(key)-1] == ' ') // remove trailing spaces
5583 key[strlen(key)-1] = 0;
5584 if (!COM_ParseToken_Simple(&data, false, false))
5586 strlcpy(value, com_token, sizeof(value));
5588 // now that we have the key pair worked out...
5589 if (!strcmp("light", key))
5591 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5595 light[0] = vec[0] * (1.0f / 256.0f);
5596 light[1] = vec[0] * (1.0f / 256.0f);
5597 light[2] = vec[0] * (1.0f / 256.0f);
5603 light[0] = vec[0] * (1.0f / 255.0f);
5604 light[1] = vec[1] * (1.0f / 255.0f);
5605 light[2] = vec[2] * (1.0f / 255.0f);
5609 else if (!strcmp("delay", key))
5611 else if (!strcmp("origin", key))
5612 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5613 else if (!strcmp("angle", key))
5614 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5615 else if (!strcmp("angles", key))
5616 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5617 else if (!strcmp("color", key))
5618 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5619 else if (!strcmp("wait", key))
5620 fadescale = atof(value);
5621 else if (!strcmp("classname", key))
5623 if (!strncmp(value, "light", 5))
5626 if (!strcmp(value, "light_fluoro"))
5631 overridecolor[0] = 1;
5632 overridecolor[1] = 1;
5633 overridecolor[2] = 1;
5635 if (!strcmp(value, "light_fluorospark"))
5640 overridecolor[0] = 1;
5641 overridecolor[1] = 1;
5642 overridecolor[2] = 1;
5644 if (!strcmp(value, "light_globe"))
5649 overridecolor[0] = 1;
5650 overridecolor[1] = 0.8;
5651 overridecolor[2] = 0.4;
5653 if (!strcmp(value, "light_flame_large_yellow"))
5658 overridecolor[0] = 1;
5659 overridecolor[1] = 0.5;
5660 overridecolor[2] = 0.1;
5662 if (!strcmp(value, "light_flame_small_yellow"))
5667 overridecolor[0] = 1;
5668 overridecolor[1] = 0.5;
5669 overridecolor[2] = 0.1;
5671 if (!strcmp(value, "light_torch_small_white"))
5676 overridecolor[0] = 1;
5677 overridecolor[1] = 0.5;
5678 overridecolor[2] = 0.1;
5680 if (!strcmp(value, "light_torch_small_walltorch"))
5685 overridecolor[0] = 1;
5686 overridecolor[1] = 0.5;
5687 overridecolor[2] = 0.1;
5691 else if (!strcmp("style", key))
5692 style = atoi(value);
5693 else if (!strcmp("skin", key))
5694 skin = (int)atof(value);
5695 else if (!strcmp("pflags", key))
5696 pflags = (int)atof(value);
5697 //else if (!strcmp("effects", key))
5698 // effects = (int)atof(value);
5699 else if (cl.worldmodel->type == mod_brushq3)
5701 if (!strcmp("scale", key))
5702 lightscale = atof(value);
5703 if (!strcmp("fade", key))
5704 fadescale = atof(value);
5709 if (lightscale <= 0)
5713 if (color[0] == color[1] && color[0] == color[2])
5715 color[0] *= overridecolor[0];
5716 color[1] *= overridecolor[1];
5717 color[2] *= overridecolor[2];
5719 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5720 color[0] = color[0] * light[0];
5721 color[1] = color[1] * light[1];
5722 color[2] = color[2] * light[2];
5725 case LIGHTTYPE_MINUSX:
5727 case LIGHTTYPE_RECIPX:
5729 VectorScale(color, (1.0f / 16.0f), color);
5731 case LIGHTTYPE_RECIPXX:
5733 VectorScale(color, (1.0f / 16.0f), color);
5736 case LIGHTTYPE_NONE:
5740 case LIGHTTYPE_MINUSXX:
5743 VectorAdd(origin, originhack, origin);
5745 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);
5748 Mem_Free(entfiledata);
5752 void R_Shadow_SetCursorLocationForView(void)
5755 vec3_t dest, endpos;
5757 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5758 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false, true);
5759 if (trace.fraction < 1)
5761 dist = trace.fraction * r_editlights_cursordistance.value;
5762 push = r_editlights_cursorpushback.value;
5766 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5767 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5771 VectorClear( endpos );
5773 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5774 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5775 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5778 void R_Shadow_UpdateWorldLightSelection(void)
5780 if (r_editlights.integer)
5782 R_Shadow_SetCursorLocationForView();
5783 R_Shadow_SelectLightInView();
5786 R_Shadow_SelectLight(NULL);
5789 void R_Shadow_EditLights_Clear_f(void)
5791 R_Shadow_ClearWorldLights();
5794 void R_Shadow_EditLights_Reload_f(void)
5798 strlcpy(r_shadow_mapname, cl.worldname, sizeof(r_shadow_mapname));
5799 R_Shadow_ClearWorldLights();
5800 R_Shadow_LoadWorldLights();
5801 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5803 R_Shadow_LoadLightsFile();
5804 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5805 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5809 void R_Shadow_EditLights_Save_f(void)
5813 R_Shadow_SaveWorldLights();
5816 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
5818 R_Shadow_ClearWorldLights();
5819 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5822 void R_Shadow_EditLights_ImportLightsFile_f(void)
5824 R_Shadow_ClearWorldLights();
5825 R_Shadow_LoadLightsFile();
5828 void R_Shadow_EditLights_Spawn_f(void)
5831 if (!r_editlights.integer)
5833 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5836 if (Cmd_Argc() != 1)
5838 Con_Print("r_editlights_spawn does not take parameters\n");
5841 color[0] = color[1] = color[2] = 1;
5842 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5845 void R_Shadow_EditLights_Edit_f(void)
5847 vec3_t origin, angles, color;
5848 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5849 int style, shadows, flags, normalmode, realtimemode;
5850 char cubemapname[MAX_INPUTLINE];
5851 if (!r_editlights.integer)
5853 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5856 if (!r_shadow_selectedlight)
5858 Con_Print("No selected light.\n");
5861 VectorCopy(r_shadow_selectedlight->origin, origin);
5862 VectorCopy(r_shadow_selectedlight->angles, angles);
5863 VectorCopy(r_shadow_selectedlight->color, color);
5864 radius = r_shadow_selectedlight->radius;
5865 style = r_shadow_selectedlight->style;
5866 if (r_shadow_selectedlight->cubemapname)
5867 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5870 shadows = r_shadow_selectedlight->shadow;
5871 corona = r_shadow_selectedlight->corona;
5872 coronasizescale = r_shadow_selectedlight->coronasizescale;
5873 ambientscale = r_shadow_selectedlight->ambientscale;
5874 diffusescale = r_shadow_selectedlight->diffusescale;
5875 specularscale = r_shadow_selectedlight->specularscale;
5876 flags = r_shadow_selectedlight->flags;
5877 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5878 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5879 if (!strcmp(Cmd_Argv(1), "origin"))
5881 if (Cmd_Argc() != 5)
5883 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5886 origin[0] = atof(Cmd_Argv(2));
5887 origin[1] = atof(Cmd_Argv(3));
5888 origin[2] = atof(Cmd_Argv(4));
5890 else if (!strcmp(Cmd_Argv(1), "originx"))
5892 if (Cmd_Argc() != 3)
5894 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5897 origin[0] = atof(Cmd_Argv(2));
5899 else if (!strcmp(Cmd_Argv(1), "originy"))
5901 if (Cmd_Argc() != 3)
5903 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5906 origin[1] = atof(Cmd_Argv(2));
5908 else if (!strcmp(Cmd_Argv(1), "originz"))
5910 if (Cmd_Argc() != 3)
5912 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5915 origin[2] = atof(Cmd_Argv(2));
5917 else if (!strcmp(Cmd_Argv(1), "move"))
5919 if (Cmd_Argc() != 5)
5921 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5924 origin[0] += atof(Cmd_Argv(2));
5925 origin[1] += atof(Cmd_Argv(3));
5926 origin[2] += atof(Cmd_Argv(4));
5928 else if (!strcmp(Cmd_Argv(1), "movex"))
5930 if (Cmd_Argc() != 3)
5932 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5935 origin[0] += atof(Cmd_Argv(2));
5937 else if (!strcmp(Cmd_Argv(1), "movey"))
5939 if (Cmd_Argc() != 3)
5941 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5944 origin[1] += atof(Cmd_Argv(2));
5946 else if (!strcmp(Cmd_Argv(1), "movez"))
5948 if (Cmd_Argc() != 3)
5950 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5953 origin[2] += atof(Cmd_Argv(2));
5955 else if (!strcmp(Cmd_Argv(1), "angles"))
5957 if (Cmd_Argc() != 5)
5959 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5962 angles[0] = atof(Cmd_Argv(2));
5963 angles[1] = atof(Cmd_Argv(3));
5964 angles[2] = atof(Cmd_Argv(4));
5966 else if (!strcmp(Cmd_Argv(1), "anglesx"))
5968 if (Cmd_Argc() != 3)
5970 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5973 angles[0] = atof(Cmd_Argv(2));
5975 else if (!strcmp(Cmd_Argv(1), "anglesy"))
5977 if (Cmd_Argc() != 3)
5979 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5982 angles[1] = atof(Cmd_Argv(2));
5984 else if (!strcmp(Cmd_Argv(1), "anglesz"))
5986 if (Cmd_Argc() != 3)
5988 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5991 angles[2] = atof(Cmd_Argv(2));
5993 else if (!strcmp(Cmd_Argv(1), "color"))
5995 if (Cmd_Argc() != 5)
5997 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
6000 color[0] = atof(Cmd_Argv(2));
6001 color[1] = atof(Cmd_Argv(3));
6002 color[2] = atof(Cmd_Argv(4));
6004 else if (!strcmp(Cmd_Argv(1), "radius"))
6006 if (Cmd_Argc() != 3)
6008 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6011 radius = atof(Cmd_Argv(2));
6013 else if (!strcmp(Cmd_Argv(1), "colorscale"))
6015 if (Cmd_Argc() == 3)
6017 double scale = atof(Cmd_Argv(2));
6024 if (Cmd_Argc() != 5)
6026 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
6029 color[0] *= atof(Cmd_Argv(2));
6030 color[1] *= atof(Cmd_Argv(3));
6031 color[2] *= atof(Cmd_Argv(4));
6034 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
6036 if (Cmd_Argc() != 3)
6038 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6041 radius *= atof(Cmd_Argv(2));
6043 else if (!strcmp(Cmd_Argv(1), "style"))
6045 if (Cmd_Argc() != 3)
6047 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6050 style = atoi(Cmd_Argv(2));
6052 else if (!strcmp(Cmd_Argv(1), "cubemap"))
6056 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6059 if (Cmd_Argc() == 3)
6060 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
6064 else if (!strcmp(Cmd_Argv(1), "shadows"))
6066 if (Cmd_Argc() != 3)
6068 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6071 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
6073 else if (!strcmp(Cmd_Argv(1), "corona"))
6075 if (Cmd_Argc() != 3)
6077 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6080 corona = atof(Cmd_Argv(2));
6082 else if (!strcmp(Cmd_Argv(1), "coronasize"))
6084 if (Cmd_Argc() != 3)
6086 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6089 coronasizescale = atof(Cmd_Argv(2));
6091 else if (!strcmp(Cmd_Argv(1), "ambient"))
6093 if (Cmd_Argc() != 3)
6095 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6098 ambientscale = atof(Cmd_Argv(2));
6100 else if (!strcmp(Cmd_Argv(1), "diffuse"))
6102 if (Cmd_Argc() != 3)
6104 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6107 diffusescale = atof(Cmd_Argv(2));
6109 else if (!strcmp(Cmd_Argv(1), "specular"))
6111 if (Cmd_Argc() != 3)
6113 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6116 specularscale = atof(Cmd_Argv(2));
6118 else if (!strcmp(Cmd_Argv(1), "normalmode"))
6120 if (Cmd_Argc() != 3)
6122 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6125 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
6127 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
6129 if (Cmd_Argc() != 3)
6131 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6134 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
6138 Con_Print("usage: r_editlights_edit [property] [value]\n");
6139 Con_Print("Selected light's properties:\n");
6140 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
6141 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
6142 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
6143 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
6144 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
6145 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
6146 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
6147 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
6148 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
6149 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
6150 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
6151 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
6152 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
6153 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
6156 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
6157 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
6160 void R_Shadow_EditLights_EditAll_f(void)
6163 dlight_t *light, *oldselected;
6166 if (!r_editlights.integer)
6168 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
6172 oldselected = r_shadow_selectedlight;
6173 // EditLights doesn't seem to have a "remove" command or something so:
6174 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6175 for (lightindex = 0;lightindex < range;lightindex++)
6177 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6180 R_Shadow_SelectLight(light);
6181 R_Shadow_EditLights_Edit_f();
6183 // return to old selected (to not mess editing once selection is locked)
6184 R_Shadow_SelectLight(oldselected);
6187 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
6189 int lightnumber, lightcount;
6190 size_t lightindex, range;
6194 if (!r_editlights.integer)
6196 x = vid_conwidth.value - 240;
6198 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
6201 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6202 for (lightindex = 0;lightindex < range;lightindex++)
6204 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6207 if (light == r_shadow_selectedlight)
6208 lightnumber = lightindex;
6211 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;
6212 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;
6214 if (r_shadow_selectedlight == NULL)
6216 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;
6217 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;
6218 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;
6219 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;
6220 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;
6221 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;
6222 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;
6223 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;
6224 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;
6225 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;
6226 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;
6227 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;
6228 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;
6229 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;
6230 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;
6233 void R_Shadow_EditLights_ToggleShadow_f(void)
6235 if (!r_editlights.integer)
6237 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6240 if (!r_shadow_selectedlight)
6242 Con_Print("No selected light.\n");
6245 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);
6248 void R_Shadow_EditLights_ToggleCorona_f(void)
6250 if (!r_editlights.integer)
6252 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6255 if (!r_shadow_selectedlight)
6257 Con_Print("No selected light.\n");
6260 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);
6263 void R_Shadow_EditLights_Remove_f(void)
6265 if (!r_editlights.integer)
6267 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
6270 if (!r_shadow_selectedlight)
6272 Con_Print("No selected light.\n");
6275 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
6276 r_shadow_selectedlight = NULL;
6279 void R_Shadow_EditLights_Help_f(void)
6282 "Documentation on r_editlights system:\n"
6284 "r_editlights : enable/disable editing mode\n"
6285 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
6286 "r_editlights_cursorpushback : push back cursor this far from surface\n"
6287 "r_editlights_cursorpushoff : push cursor off surface this far\n"
6288 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
6289 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
6291 "r_editlights_help : this help\n"
6292 "r_editlights_clear : remove all lights\n"
6293 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
6294 "r_editlights_lock : lock selection to current light, if already locked - unlock\n"
6295 "r_editlights_save : save to .rtlights file\n"
6296 "r_editlights_spawn : create a light with default settings\n"
6297 "r_editlights_edit command : edit selected light - more documentation below\n"
6298 "r_editlights_remove : remove selected light\n"
6299 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
6300 "r_editlights_importlightentitiesfrommap : reload light entities\n"
6301 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
6303 "origin x y z : set light location\n"
6304 "originx x: set x component of light location\n"
6305 "originy y: set y component of light location\n"
6306 "originz z: set z component of light location\n"
6307 "move x y z : adjust light location\n"
6308 "movex x: adjust x component of light location\n"
6309 "movey y: adjust y component of light location\n"
6310 "movez z: adjust z component of light location\n"
6311 "angles x y z : set light angles\n"
6312 "anglesx x: set x component of light angles\n"
6313 "anglesy y: set y component of light angles\n"
6314 "anglesz z: set z component of light angles\n"
6315 "color r g b : set color of light (can be brighter than 1 1 1)\n"
6316 "radius radius : set radius (size) of light\n"
6317 "colorscale grey : multiply color of light (1 does nothing)\n"
6318 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
6319 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
6320 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
6321 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
6322 "cubemap basename : set filter cubemap of light (not yet supported)\n"
6323 "shadows 1/0 : turn on/off shadows\n"
6324 "corona n : set corona intensity\n"
6325 "coronasize n : set corona size (0-1)\n"
6326 "ambient n : set ambient intensity (0-1)\n"
6327 "diffuse n : set diffuse intensity (0-1)\n"
6328 "specular n : set specular intensity (0-1)\n"
6329 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
6330 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
6331 "<nothing> : print light properties to console\n"
6335 void R_Shadow_EditLights_CopyInfo_f(void)
6337 if (!r_editlights.integer)
6339 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
6342 if (!r_shadow_selectedlight)
6344 Con_Print("No selected light.\n");
6347 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
6348 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
6349 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
6350 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
6351 if (r_shadow_selectedlight->cubemapname)
6352 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
6354 r_shadow_bufferlight.cubemapname[0] = 0;
6355 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
6356 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
6357 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
6358 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
6359 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
6360 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
6361 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
6364 void R_Shadow_EditLights_PasteInfo_f(void)
6366 if (!r_editlights.integer)
6368 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
6371 if (!r_shadow_selectedlight)
6373 Con_Print("No selected light.\n");
6376 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);
6379 void R_Shadow_EditLights_Lock_f(void)
6381 if (!r_editlights.integer)
6383 Con_Print("Cannot lock on light when not in editing mode. Set r_editlights to 1.\n");
6386 if (r_editlights_lockcursor)
6388 r_editlights_lockcursor = false;
6391 if (!r_shadow_selectedlight)
6393 Con_Print("No selected light to lock on.\n");
6396 r_editlights_lockcursor = true;
6399 void R_Shadow_EditLights_Init(void)
6401 Cvar_RegisterVariable(&r_editlights);
6402 Cvar_RegisterVariable(&r_editlights_cursordistance);
6403 Cvar_RegisterVariable(&r_editlights_cursorpushback);
6404 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
6405 Cvar_RegisterVariable(&r_editlights_cursorgrid);
6406 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
6407 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
6408 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
6409 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)");
6410 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
6411 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
6412 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
6413 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)");
6414 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
6415 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
6416 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
6417 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
6418 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
6419 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
6420 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)");
6421 Cmd_AddCommand("r_editlights_lock", R_Shadow_EditLights_Lock_f, "lock selection to current light, if already locked - unlock");
6427 =============================================================================
6431 =============================================================================
6434 void R_CompleteLightPoint(vec3_t ambient, vec3_t diffuse, vec3_t lightdir, const vec3_t p, const int flags)
6436 int i, numlights, flag;
6439 float relativepoint[3];
6448 if (r_fullbright.integer)
6450 VectorSet(ambient, 1, 1, 1);
6451 VectorClear(diffuse);
6452 VectorClear(lightdir);
6456 if (flags & LP_LIGHTMAP)
6458 VectorSet(ambient, r_refdef.scene.ambient, r_refdef.scene.ambient, r_refdef.scene.ambient);
6459 VectorClear(diffuse);
6460 VectorClear(lightdir);
6461 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
6462 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambient, diffuse, lightdir);
6466 memset(sample, 0, sizeof(sample));
6467 VectorSet(sample, r_refdef.scene.ambient, r_refdef.scene.ambient, r_refdef.scene.ambient);
6469 if ((flags & LP_LIGHTMAP) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
6472 VectorClear(tempambient);
6474 VectorClear(relativepoint);
6475 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, tempambient, color, relativepoint);
6476 VectorScale(tempambient, r_refdef.lightmapintensity, tempambient);
6477 VectorScale(color, r_refdef.lightmapintensity, color);
6478 VectorAdd(sample, tempambient, sample);
6479 VectorMA(sample , 0.5f , color, sample );
6480 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
6481 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
6482 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
6483 // calculate a weighted average light direction as well
6484 intensity = VectorLength(color);
6485 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
6488 if (flags & LP_RTWORLD)
6490 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
6491 numlights = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
6492 for (i = 0; i < numlights; i++)
6494 dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
6497 light = &dlight->rtlight;
6498 if (!(light->flags & flag))
6501 lightradius2 = light->radius * light->radius;
6502 VectorSubtract(light->shadoworigin, p, relativepoint);
6503 dist2 = VectorLength2(relativepoint);
6504 if (dist2 >= lightradius2)
6506 dist = sqrt(dist2) / light->radius;
6507 intensity = min(1.0f, (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) * r_shadow_lightintensityscale.value;
6508 if (intensity <= 0.0f)
6510 if (light->shadow && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false, true).fraction < 1)
6512 // scale down intensity to add to both ambient and diffuse
6513 //intensity *= 0.5f;
6514 VectorNormalize(relativepoint);
6515 VectorScale(light->currentcolor, intensity, color);
6516 VectorMA(sample , 0.5f , color, sample );
6517 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
6518 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
6519 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
6520 // calculate a weighted average light direction as well
6521 intensity *= VectorLength(color);
6522 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
6526 if (flags & LP_DYNLIGHT)
6529 for (i = 0;i < r_refdef.scene.numlights;i++)
6531 light = r_refdef.scene.lights[i];
6533 lightradius2 = light->radius * light->radius;
6534 VectorSubtract(light->shadoworigin, p, relativepoint);
6535 dist2 = VectorLength2(relativepoint);
6536 if (dist2 >= lightradius2)
6538 dist = sqrt(dist2) / light->radius;
6539 intensity = (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist) * r_shadow_lightintensityscale.value;
6540 if (intensity <= 0.0f)
6542 if (light->shadow && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false, true).fraction < 1)
6544 // scale down intensity to add to both ambient and diffuse
6545 //intensity *= 0.5f;
6546 VectorNormalize(relativepoint);
6547 VectorScale(light->currentcolor, intensity, color);
6548 VectorMA(sample , 0.5f , color, sample );
6549 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
6550 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
6551 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
6552 // calculate a weighted average light direction as well
6553 intensity *= VectorLength(color);
6554 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
6558 // calculate the direction we'll use to reduce the sample to a directional light source
6559 VectorCopy(sample + 12, dir);
6560 //VectorSet(dir, sample[3] + sample[4] + sample[5], sample[6] + sample[7] + sample[8], sample[9] + sample[10] + sample[11]);
6561 VectorNormalize(dir);
6562 // extract the diffuse color along the chosen direction and scale it
6563 diffuse[0] = (dir[0]*sample[3] + dir[1]*sample[6] + dir[2]*sample[ 9] + sample[ 0]);
6564 diffuse[1] = (dir[0]*sample[4] + dir[1]*sample[7] + dir[2]*sample[10] + sample[ 1]);
6565 diffuse[2] = (dir[0]*sample[5] + dir[1]*sample[8] + dir[2]*sample[11] + sample[ 2]);
6566 // subtract some of diffuse from ambient
6567 VectorMA(sample, -0.333f, diffuse, ambient);
6568 // store the normalized lightdir
6569 VectorCopy(dir, lightdir);