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", "5000", "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 float *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;
2286 int hitsupercontentsmask;
2295 //trace_t cliptrace2;
2296 //trace_t cliptrace3;
2297 unsigned char *pixel;
2298 unsigned char *pixels;
2301 unsigned int lightindex;
2303 unsigned int range1;
2304 unsigned int range2;
2305 unsigned int seed = (unsigned int)(realtime * 1000.0f);
2307 vec3_t baseshotcolor;
2320 vec_t lightintensity;
2321 vec_t photonscaling;
2322 vec_t photonresidual;
2324 float texlerp[2][3];
2325 float splatcolor[3];
2326 float pixelweight[8];
2330 qboolean isstatic = r_shadow_bouncegrid_updateinterval.value > 1.0f;
2332 if (!r_shadow_bouncegrid.integer || !vid.support.ext_texture_3d)
2334 if (r_shadow_bouncegridtexture)
2336 R_FreeTexture(r_shadow_bouncegridtexture);
2337 r_shadow_bouncegridtexture = NULL;
2339 if (r_shadow_bouncegridpixels)
2340 Mem_Free(r_shadow_bouncegridpixels);
2341 r_shadow_bouncegridpixels = NULL;
2342 if (r_shadow_bouncegridhighpixels)
2343 Mem_Free(r_shadow_bouncegridhighpixels);
2344 r_shadow_bouncegridhighpixels = NULL;
2345 r_shadow_bouncegridnumpixels = 0;
2348 if (r_refdef.scene.worldmodel && isstatic)
2350 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));
2351 VectorMA(r_refdef.scene.worldmodel->normalmins, -2.0f, spacing, mins);
2352 VectorMA(r_refdef.scene.worldmodel->normalmaxs, 2.0f, spacing, maxs);
2353 VectorSubtract(maxs, mins, size);
2354 resolution[0] = (int)floor(size[0] / spacing[0] + 0.5f);
2355 resolution[1] = (int)floor(size[1] / spacing[1] + 0.5f);
2356 resolution[2] = (int)floor(size[2] / spacing[2] + 0.5f);
2357 resolution[0] = min(resolution[0], bound(4, r_shadow_bouncegrid_x.integer, (int)vid.maxtexturesize_3d));
2358 resolution[1] = min(resolution[1], bound(4, r_shadow_bouncegrid_y.integer, (int)vid.maxtexturesize_3d));
2359 resolution[2] = min(resolution[2], bound(4, r_shadow_bouncegrid_z.integer, (int)vid.maxtexturesize_3d));
2360 spacing[0] = size[0] / resolution[0];
2361 spacing[1] = size[1] / resolution[1];
2362 spacing[2] = size[2] / resolution[2];
2363 ispacing[0] = 1.0f / spacing[0];
2364 ispacing[1] = 1.0f / spacing[1];
2365 ispacing[2] = 1.0f / spacing[2];
2369 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));
2370 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));
2371 VectorMultiply(resolution, spacing, size);
2372 ispacing[0] = 1.0f / spacing[0];
2373 ispacing[1] = 1.0f / spacing[1];
2374 ispacing[2] = 1.0f / spacing[2];
2375 mins[0] = floor(r_refdef.view.origin[0] * ispacing[0] + 0.5f) * spacing[0] - 0.5f * size[0];
2376 mins[1] = floor(r_refdef.view.origin[1] * ispacing[1] + 0.5f) * spacing[1] - 0.5f * size[1];
2377 mins[2] = floor(r_refdef.view.origin[2] * ispacing[2] + 0.5f) * spacing[2] - 0.5f * size[2];
2378 VectorAdd(mins, size, maxs);
2380 r_shadow_bouncegridintensity = r_shadow_bouncegrid_intensity.value;
2381 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])
2383 // we're going to update the bouncegrid, update the matrix...
2384 memset(m, 0, sizeof(m));
2385 m[0] = 1.0f / size[0];
2386 m[3] = -mins[0] * m[0];
2387 m[5] = 1.0f / size[1];
2388 m[7] = -mins[1] * m[5];
2389 m[10] = 1.0f / size[2];
2390 m[11] = -mins[2] * m[10];
2392 Matrix4x4_FromArrayFloatD3D(&r_shadow_bouncegridmatrix, m);
2393 numpixels = resolution[0]*resolution[1]*resolution[2];
2394 // reallocate pixels for this update if needed...
2395 if (r_shadow_bouncegridnumpixels != numpixels || !r_shadow_bouncegridpixels || !r_shadow_bouncegridhighpixels)
2397 r_shadow_bouncegridpixels = (unsigned char *)Mem_Realloc(r_main_mempool, r_shadow_bouncegridpixels, numpixels * sizeof(unsigned char[4]));
2398 r_shadow_bouncegridhighpixels = (float *)Mem_Realloc(r_main_mempool, r_shadow_bouncegridhighpixels, numpixels * sizeof(float[3]));
2400 r_shadow_bouncegridnumpixels = numpixels;
2401 pixels = r_shadow_bouncegridpixels;
2402 highpixels = r_shadow_bouncegridhighpixels;
2403 memset(pixels, 0, numpixels * sizeof(unsigned char[4]));
2404 memset(highpixels, 0, numpixels * sizeof(float[3]));
2405 // figure out what we want to interact with
2406 if (r_shadow_bouncegrid_hitmodels.integer)
2407 hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_LIQUIDSMASK;
2409 hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_LIQUIDSMASK;
2410 maxbounce = bound(1, r_shadow_bouncegrid_maxbounce.integer, 16);
2411 // iterate world rtlights
2412 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
2413 range1 = isstatic ? 0 : r_refdef.scene.numlights;
2414 range2 = range + range1;
2416 for (lightindex = 0;lightindex < range2;lightindex++)
2420 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2421 if (!light || !(light->flags & flag))
2423 rtlight = &light->rtlight;
2424 // when static, we skip styled lights because they tend to change...
2425 if (rtlight->style > 0)
2427 VectorScale(rtlight->color, (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) * (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1), lightcolor);
2431 if (lightindex < range)
2433 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2434 rtlight = &light->rtlight;
2437 rtlight = r_refdef.scene.lights[lightindex - range];
2438 // draw only visible lights (major speedup)
2441 VectorScale(rtlight->currentcolor, rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale, lightcolor);
2443 if (!VectorLength2(lightcolor))
2445 // shoot particles from this light
2446 // use a calculation for the number of particles that will not
2447 // vary with lightstyle, otherwise we get randomized particle
2448 // distribution, the seeded random is only consistent for a
2449 // consistent number of particles on this light...
2450 radius = rtlight->radius * bound(0.0001f, r_shadow_bouncegrid_lightradiusscale.value, 1024.0f);
2451 s = rtlight->radius;
2452 lightintensity = VectorLength(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2453 if (lightindex >= range)
2454 lightintensity *= r_shadow_bouncegrid_dlightparticlemultiplier.value;
2455 photoncount += max(0.0f, lightintensity * s * s);
2457 photonscaling = bound(1, r_shadow_bouncegrid_photons.value, 1048576) / max(1, photoncount);
2458 photonresidual = 0.0f;
2459 for (lightindex = 0;lightindex < range2;lightindex++)
2463 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2464 if (!light || !(light->flags & flag))
2466 rtlight = &light->rtlight;
2467 // when static, we skip styled lights because they tend to change...
2468 if (rtlight->style > 0)
2470 VectorScale(rtlight->color, (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) * (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1), lightcolor);
2474 if (lightindex < range)
2476 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2477 rtlight = &light->rtlight;
2480 rtlight = r_refdef.scene.lights[lightindex - range];
2481 // draw only visible lights (major speedup)
2484 VectorScale(rtlight->currentcolor, rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale, lightcolor);
2486 if (!VectorLength2(lightcolor))
2488 // shoot particles from this light
2489 // use a calculation for the number of particles that will not
2490 // vary with lightstyle, otherwise we get randomized particle
2491 // distribution, the seeded random is only consistent for a
2492 // consistent number of particles on this light...
2493 radius = rtlight->radius * bound(0.0001f, r_shadow_bouncegrid_lightradiusscale.value, 1024.0f);
2494 s = rtlight->radius;
2495 lightintensity = VectorLength(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2496 if (lightindex >= range)
2497 lightintensity *= r_shadow_bouncegrid_dlightparticlemultiplier.value;
2498 photonresidual += lightintensity * s * s * photonscaling;
2499 shootparticles = (int)bound(0, photonresidual, MAXBOUNCEGRIDPARTICLESPERLIGHT);
2500 if (!shootparticles)
2502 photonresidual -= shootparticles;
2503 s = r_shadow_bouncegrid_particleintensity.value / shootparticles;
2504 VectorScale(lightcolor, s, baseshotcolor);
2505 if (VectorLength2(baseshotcolor) == 0.0f)
2507 r_refdef.stats.bouncegrid_lights++;
2508 r_refdef.stats.bouncegrid_particles += shootparticles;
2509 for (shotparticles = 0;shotparticles < shootparticles;shotparticles++)
2511 if (r_shadow_bouncegrid_stablerandom.integer > 0)
2512 seed = lightindex * 11937 + shotparticles;
2513 VectorCopy(baseshotcolor, shotcolor);
2514 VectorCopy(rtlight->shadoworigin, clipstart);
2515 if (r_shadow_bouncegrid_stablerandom.integer < 0)
2516 VectorRandom(clipend);
2518 VectorCheeseRandom(clipend);
2519 VectorMA(clipstart, radius, clipend, clipend);
2520 for (bouncecount = 0;;bouncecount++)
2522 r_refdef.stats.bouncegrid_traces++;
2523 //r_refdef.scene.worldmodel->TraceLineAgainstSurfaces(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace, clipstart, clipend, hitsupercontentsmask);
2524 //r_refdef.scene.worldmodel->TraceLine(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace2, clipstart, clipend, hitsupercontentsmask);
2525 cliptrace = CL_TraceLine(clipstart, clipend, r_shadow_bouncegrid_hitmodels.integer ? MOVE_HITMODEL : MOVE_NOMONSTERS, NULL, hitsupercontentsmask, true, false, NULL, true, true);
2526 //Collision_ClipLineToWorld(&cliptrace, cl.worldmodel, clipstart, clipend, hitsupercontentsmask);
2527 if (cliptrace.fraction >= 1.0f)
2529 r_refdef.stats.bouncegrid_hits++;
2530 if (bouncecount > 0)
2532 r_refdef.stats.bouncegrid_splats++;
2533 // figure out which texture pixel this is in
2534 texlerp[1][0] = ((cliptrace.endpos[0] - mins[0]) * ispacing[0]);
2535 texlerp[1][1] = ((cliptrace.endpos[1] - mins[1]) * ispacing[1]);
2536 texlerp[1][2] = ((cliptrace.endpos[2] - mins[2]) * ispacing[2]);
2537 tex[0] = (int)floor(texlerp[1][0]);
2538 tex[1] = (int)floor(texlerp[1][1]);
2539 tex[2] = (int)floor(texlerp[1][2]);
2540 if (tex[0] >= 1 && tex[1] >= 1 && tex[2] >= 1 && tex[0] < resolution[0] - 2 && tex[1] < resolution[1] - 2 && tex[2] < resolution[2] - 2)
2542 // it is within bounds...
2543 splatcolor[0] = shotcolor[2] * 255.0f;
2544 splatcolor[1] = shotcolor[1] * 255.0f;
2545 splatcolor[2] = shotcolor[0] * 255.0f;
2546 // calculate the lerp factors
2547 texlerp[1][0] -= tex[0];
2548 texlerp[1][1] -= tex[1];
2549 texlerp[1][2] -= tex[2];
2550 texlerp[0][0] = 1.0f - texlerp[1][0];
2551 texlerp[0][1] = 1.0f - texlerp[1][1];
2552 texlerp[0][2] = 1.0f - texlerp[1][2];
2553 // calculate individual pixel indexes and weights
2554 pixelindex[0] = (((tex[2] )*resolution[1]+tex[1] )*resolution[0]+tex[0] );pixelweight[0] = (texlerp[0][0]*texlerp[0][1]*texlerp[0][2]);
2555 pixelindex[1] = (((tex[2] )*resolution[1]+tex[1] )*resolution[0]+tex[0]+1);pixelweight[1] = (texlerp[1][0]*texlerp[0][1]*texlerp[0][2]);
2556 pixelindex[2] = (((tex[2] )*resolution[1]+tex[1]+1)*resolution[0]+tex[0] );pixelweight[2] = (texlerp[0][0]*texlerp[1][1]*texlerp[0][2]);
2557 pixelindex[3] = (((tex[2] )*resolution[1]+tex[1]+1)*resolution[0]+tex[0]+1);pixelweight[3] = (texlerp[1][0]*texlerp[1][1]*texlerp[0][2]);
2558 pixelindex[4] = (((tex[2]+1)*resolution[1]+tex[1] )*resolution[0]+tex[0] );pixelweight[4] = (texlerp[0][0]*texlerp[0][1]*texlerp[1][2]);
2559 pixelindex[5] = (((tex[2]+1)*resolution[1]+tex[1] )*resolution[0]+tex[0]+1);pixelweight[5] = (texlerp[1][0]*texlerp[0][1]*texlerp[1][2]);
2560 pixelindex[6] = (((tex[2]+1)*resolution[1]+tex[1]+1)*resolution[0]+tex[0] );pixelweight[6] = (texlerp[0][0]*texlerp[1][1]*texlerp[1][2]);
2561 pixelindex[7] = (((tex[2]+1)*resolution[1]+tex[1]+1)*resolution[0]+tex[0]+1);pixelweight[7] = (texlerp[1][0]*texlerp[1][1]*texlerp[1][2]);
2562 // update the 8 pixels...
2563 for (corner = 0;corner < 8;corner++)
2565 pixel = pixels + 4 * pixelindex[corner];
2566 highpixel = highpixels + 3 * pixelindex[corner];
2567 // add to the high precision pixel color
2568 highpixel[0] += (splatcolor[0]*pixelweight[corner]);
2569 highpixel[1] += (splatcolor[1]*pixelweight[corner]);
2570 highpixel[2] += (splatcolor[2]*pixelweight[corner]);
2571 // flag the low precision pixel as needing to be updated
2576 if (bouncecount >= maxbounce)
2578 // scale down shot color by bounce intensity and texture color (or 50% if no texture reported)
2579 // also clamp the resulting color to never add energy, even if the user requests extreme values
2580 if (cliptrace.hittexture && cliptrace.hittexture->currentskinframe)
2581 VectorCopy(cliptrace.hittexture->currentskinframe->avgcolor, surfcolor);
2583 VectorSet(surfcolor, 0.5f, 0.5f, 0.5f);
2584 VectorScale(surfcolor, r_shadow_bouncegrid_particlebounceintensity.value, surfcolor);
2585 surfcolor[0] = min(surfcolor[0], 1.0f);
2586 surfcolor[1] = min(surfcolor[1], 1.0f);
2587 surfcolor[2] = min(surfcolor[2], 1.0f);
2588 VectorMultiply(shotcolor, surfcolor, shotcolor);
2589 if (VectorLength2(baseshotcolor) == 0.0f)
2591 r_refdef.stats.bouncegrid_bounces++;
2592 if (r_shadow_bouncegrid_bounceanglediffuse.integer)
2594 // random direction, primarily along plane normal
2595 s = VectorDistance(cliptrace.endpos, clipend);
2596 if (r_shadow_bouncegrid_stablerandom.integer < 0)
2597 VectorRandom(clipend);
2599 VectorCheeseRandom(clipend);
2600 VectorMA(cliptrace.plane.normal, 0.95f, clipend, clipend);
2601 VectorNormalize(clipend);
2602 VectorScale(clipend, s, clipend);
2606 // reflect the remaining portion of the line across plane normal
2607 VectorSubtract(clipend, cliptrace.endpos, clipdiff);
2608 VectorReflect(clipdiff, 1.0, cliptrace.plane.normal, clipend);
2610 // calculate the new line start and end
2611 VectorCopy(cliptrace.endpos, clipstart);
2612 VectorAdd(clipstart, clipend, clipend);
2616 // generate pixels array from highpixels array
2617 // skip first and last columns, rows, and layers as these are blank
2618 // the pixel[3] value was written above, so we can use it to detect only pixels that need to be calculated
2619 for (z = 1;z < resolution[2]-1;z++)
2621 for (y = 1;y < resolution[1]-1;y++)
2623 for (x = 1, pixelindex[0] = (resolution[1]*z+y)*resolution[0]+x, pixel = pixels + 4*pixelindex[0], highpixel = highpixels + 3*pixelindex[0];x < resolution[0]-1;x++, pixel += 4, highpixel += 3)
2625 // only convert pixels that were hit by photons
2628 pixel[0] = (unsigned char)min(highpixel[0], 255);
2629 pixel[1] = (unsigned char)min(highpixel[1], 255);
2630 pixel[2] = (unsigned char)min(highpixel[2], 255);
2635 if (r_shadow_bouncegridtexture && r_shadow_bouncegridresolution[0] == resolution[0] && r_shadow_bouncegridresolution[1] == resolution[1] && r_shadow_bouncegridresolution[2] == resolution[2])
2636 R_UpdateTexture(r_shadow_bouncegridtexture, pixels, 0, 0, 0, resolution[0], resolution[1], resolution[2]);
2639 VectorCopy(resolution, r_shadow_bouncegridresolution);
2640 if (r_shadow_bouncegridtexture)
2641 R_FreeTexture(r_shadow_bouncegridtexture);
2642 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);
2644 r_shadow_bouncegridtime = realtime;
2647 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
2649 R_Shadow_RenderMode_Reset();
2650 GL_BlendFunc(GL_ONE, GL_ONE);
2651 GL_DepthRange(0, 1);
2652 GL_DepthTest(r_showshadowvolumes.integer < 2);
2653 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
2654 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2655 GL_CullFace(GL_NONE);
2656 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
2659 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
2661 R_Shadow_RenderMode_Reset();
2662 GL_BlendFunc(GL_ONE, GL_ONE);
2663 GL_DepthRange(0, 1);
2664 GL_DepthTest(r_showlighting.integer < 2);
2665 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2667 GL_DepthFunc(GL_EQUAL);
2668 R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2669 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2672 void R_Shadow_RenderMode_End(void)
2674 R_Shadow_RenderMode_Reset();
2675 R_Shadow_RenderMode_ActiveLight(NULL);
2677 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2678 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2681 int bboxedges[12][2] =
2700 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2702 if (!r_shadow_scissor.integer)
2704 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2705 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2706 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2707 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2710 if(R_ScissorForBBox(mins, maxs, r_shadow_lightscissor))
2711 return true; // invisible
2712 if(r_shadow_lightscissor[0] != r_refdef.view.viewport.x
2713 || r_shadow_lightscissor[1] != r_refdef.view.viewport.y
2714 || r_shadow_lightscissor[2] != r_refdef.view.viewport.width
2715 || r_shadow_lightscissor[3] != r_refdef.view.viewport.height)
2716 r_refdef.stats.lights_scissored++;
2720 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, const float *diffusecolor, const float *ambientcolor)
2723 const float *vertex3f;
2724 const float *normal3f;
2726 float dist, dot, distintensity, shadeintensity, v[3], n[3];
2727 switch (r_shadow_rendermode)
2729 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2730 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2731 if (VectorLength2(diffusecolor) > 0)
2733 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)
2735 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2736 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2737 if ((dot = DotProduct(n, v)) < 0)
2739 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2740 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
2743 VectorCopy(ambientcolor, color4f);
2744 if (r_refdef.fogenabled)
2747 f = RSurf_FogVertex(vertex3f);
2748 VectorScale(color4f, f, color4f);
2755 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
2757 VectorCopy(ambientcolor, color4f);
2758 if (r_refdef.fogenabled)
2761 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2762 f = RSurf_FogVertex(vertex3f);
2763 VectorScale(color4f + 4*i, f, color4f);
2769 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2770 if (VectorLength2(diffusecolor) > 0)
2772 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)
2774 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2775 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2777 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2778 if ((dot = DotProduct(n, v)) < 0)
2780 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2781 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2782 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2783 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2787 color4f[0] = ambientcolor[0] * distintensity;
2788 color4f[1] = ambientcolor[1] * distintensity;
2789 color4f[2] = ambientcolor[2] * distintensity;
2791 if (r_refdef.fogenabled)
2794 f = RSurf_FogVertex(vertex3f);
2795 VectorScale(color4f, f, color4f);
2799 VectorClear(color4f);
2805 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
2807 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2808 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2810 color4f[0] = ambientcolor[0] * distintensity;
2811 color4f[1] = ambientcolor[1] * distintensity;
2812 color4f[2] = ambientcolor[2] * distintensity;
2813 if (r_refdef.fogenabled)
2816 f = RSurf_FogVertex(vertex3f);
2817 VectorScale(color4f, f, color4f);
2821 VectorClear(color4f);
2826 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2827 if (VectorLength2(diffusecolor) > 0)
2829 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)
2831 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2832 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2834 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2835 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2836 if ((dot = DotProduct(n, v)) < 0)
2838 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2839 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2840 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2841 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2845 color4f[0] = ambientcolor[0] * distintensity;
2846 color4f[1] = ambientcolor[1] * distintensity;
2847 color4f[2] = ambientcolor[2] * distintensity;
2849 if (r_refdef.fogenabled)
2852 f = RSurf_FogVertex(vertex3f);
2853 VectorScale(color4f, f, color4f);
2857 VectorClear(color4f);
2863 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
2865 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2866 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2868 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2869 color4f[0] = ambientcolor[0] * distintensity;
2870 color4f[1] = ambientcolor[1] * distintensity;
2871 color4f[2] = ambientcolor[2] * distintensity;
2872 if (r_refdef.fogenabled)
2875 f = RSurf_FogVertex(vertex3f);
2876 VectorScale(color4f, f, color4f);
2880 VectorClear(color4f);
2890 static void R_Shadow_RenderLighting_VisibleLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
2892 // used to display how many times a surface is lit for level design purposes
2893 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
2894 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
2898 static void R_Shadow_RenderLighting_Light_GLSL(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale, float specularscale)
2900 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2901 R_SetupShader_Surface(lightcolor, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT, texturenumsurfaces, texturesurfacelist, NULL);
2902 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2903 GL_DepthFunc(GL_EQUAL);
2905 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2906 GL_DepthFunc(GL_LEQUAL);
2909 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
2916 int newnumtriangles;
2920 int maxtriangles = 4096;
2921 static int newelements[4096*3];
2922 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, diffusecolor2, ambientcolor2);
2923 for (renders = 0;renders < 4;renders++)
2928 newnumtriangles = 0;
2930 // due to low fillrate on the cards this vertex lighting path is
2931 // designed for, we manually cull all triangles that do not
2932 // contain a lit vertex
2933 // this builds batches of triangles from multiple surfaces and
2934 // renders them at once
2935 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
2937 if (VectorLength2(rsurface.passcolor4f + e[0] * 4) + VectorLength2(rsurface.passcolor4f + e[1] * 4) + VectorLength2(rsurface.passcolor4f + e[2] * 4) >= 0.01)
2939 if (newnumtriangles)
2941 newfirstvertex = min(newfirstvertex, e[0]);
2942 newlastvertex = max(newlastvertex, e[0]);
2946 newfirstvertex = e[0];
2947 newlastvertex = e[0];
2949 newfirstvertex = min(newfirstvertex, e[1]);
2950 newlastvertex = max(newlastvertex, e[1]);
2951 newfirstvertex = min(newfirstvertex, e[2]);
2952 newlastvertex = max(newlastvertex, e[2]);
2958 if (newnumtriangles >= maxtriangles)
2960 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
2961 newnumtriangles = 0;
2967 if (newnumtriangles >= 1)
2969 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
2972 // if we couldn't find any lit triangles, exit early
2975 // now reduce the intensity for the next overbright pass
2976 // we have to clamp to 0 here incase the drivers have improper
2977 // handling of negative colors
2978 // (some old drivers even have improper handling of >1 color)
2980 for (i = 0, c = rsurface.passcolor4f + 4 * firstvertex;i < numvertices;i++, c += 4)
2982 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
2984 c[0] = max(0, c[0] - 1);
2985 c[1] = max(0, c[1] - 1);
2986 c[2] = max(0, c[2] - 1);
2998 static void R_Shadow_RenderLighting_Light_Vertex(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale)
3000 // OpenGL 1.1 path (anything)
3001 float ambientcolorbase[3], diffusecolorbase[3];
3002 float ambientcolorpants[3], diffusecolorpants[3];
3003 float ambientcolorshirt[3], diffusecolorshirt[3];
3004 const float *surfacecolor = rsurface.texture->dlightcolor;
3005 const float *surfacepants = rsurface.colormap_pantscolor;
3006 const float *surfaceshirt = rsurface.colormap_shirtcolor;
3007 rtexture_t *basetexture = rsurface.texture->basetexture;
3008 rtexture_t *pantstexture = rsurface.texture->pantstexture;
3009 rtexture_t *shirttexture = rsurface.texture->shirttexture;
3010 qboolean dopants = pantstexture && VectorLength2(surfacepants) >= (1.0f / 1048576.0f);
3011 qboolean doshirt = shirttexture && VectorLength2(surfaceshirt) >= (1.0f / 1048576.0f);
3012 ambientscale *= 2 * r_refdef.view.colorscale;
3013 diffusescale *= 2 * r_refdef.view.colorscale;
3014 ambientcolorbase[0] = lightcolor[0] * ambientscale * surfacecolor[0];ambientcolorbase[1] = lightcolor[1] * ambientscale * surfacecolor[1];ambientcolorbase[2] = lightcolor[2] * ambientscale * surfacecolor[2];
3015 diffusecolorbase[0] = lightcolor[0] * diffusescale * surfacecolor[0];diffusecolorbase[1] = lightcolor[1] * diffusescale * surfacecolor[1];diffusecolorbase[2] = lightcolor[2] * diffusescale * surfacecolor[2];
3016 ambientcolorpants[0] = ambientcolorbase[0] * surfacepants[0];ambientcolorpants[1] = ambientcolorbase[1] * surfacepants[1];ambientcolorpants[2] = ambientcolorbase[2] * surfacepants[2];
3017 diffusecolorpants[0] = diffusecolorbase[0] * surfacepants[0];diffusecolorpants[1] = diffusecolorbase[1] * surfacepants[1];diffusecolorpants[2] = diffusecolorbase[2] * surfacepants[2];
3018 ambientcolorshirt[0] = ambientcolorbase[0] * surfaceshirt[0];ambientcolorshirt[1] = ambientcolorbase[1] * surfaceshirt[1];ambientcolorshirt[2] = ambientcolorbase[2] * surfaceshirt[2];
3019 diffusecolorshirt[0] = diffusecolorbase[0] * surfaceshirt[0];diffusecolorshirt[1] = diffusecolorbase[1] * surfaceshirt[1];diffusecolorshirt[2] = diffusecolorbase[2] * surfaceshirt[2];
3020 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | (diffusescale > 0 ? BATCHNEED_ARRAY_NORMAL : 0) | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
3021 rsurface.passcolor4f = (float *)R_FrameData_Alloc((rsurface.batchfirstvertex + rsurface.batchnumvertices) * sizeof(float[4]));
3022 R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3023 R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.passcolor4f, 0, 0);
3024 R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
3025 R_Mesh_TexBind(0, basetexture);
3026 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
3027 R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
3028 switch(r_shadow_rendermode)
3030 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
3031 R_Mesh_TexBind(1, r_shadow_attenuation3dtexture);
3032 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
3033 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
3034 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3036 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
3037 R_Mesh_TexBind(2, r_shadow_attenuation2dtexture);
3038 R_Mesh_TexMatrix(2, &rsurface.entitytoattenuationz);
3039 R_Mesh_TexCombine(2, GL_MODULATE, GL_MODULATE, 1, 1);
3040 R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3042 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
3043 R_Mesh_TexBind(1, r_shadow_attenuation2dtexture);
3044 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
3045 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
3046 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3048 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3053 //R_Mesh_TexBind(0, basetexture);
3054 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorbase, ambientcolorbase);
3057 R_Mesh_TexBind(0, pantstexture);
3058 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorpants, ambientcolorpants);
3062 R_Mesh_TexBind(0, shirttexture);
3063 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorshirt, ambientcolorshirt);
3067 extern cvar_t gl_lightmaps;
3068 void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
3070 float ambientscale, diffusescale, specularscale;
3072 float lightcolor[3];
3073 VectorCopy(rsurface.rtlight->currentcolor, lightcolor);
3074 ambientscale = rsurface.rtlight->ambientscale;
3075 diffusescale = rsurface.rtlight->diffusescale;
3076 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
3077 if (!r_shadow_usenormalmap.integer)
3079 ambientscale += 1.0f * diffusescale;
3083 if ((ambientscale + diffusescale) * VectorLength2(lightcolor) + specularscale * VectorLength2(lightcolor) < (1.0f / 1048576.0f))
3085 negated = (lightcolor[0] + lightcolor[1] + lightcolor[2] < 0) && vid.support.ext_blend_subtract;
3088 VectorNegate(lightcolor, lightcolor);
3089 switch(vid.renderpath)
3091 case RENDERPATH_GL11:
3092 case RENDERPATH_GL13:
3093 case RENDERPATH_GL20:
3094 case RENDERPATH_GLES2:
3095 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
3097 case RENDERPATH_D3D9:
3099 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_SUBTRACT);
3102 case RENDERPATH_D3D10:
3103 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3105 case RENDERPATH_D3D11:
3106 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3108 case RENDERPATH_SOFT:
3109 DPSOFTRAST_BlendSubtract(true);
3113 RSurf_SetupDepthAndCulling();
3114 switch (r_shadow_rendermode)
3116 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
3117 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
3118 R_Shadow_RenderLighting_VisibleLighting(texturenumsurfaces, texturesurfacelist);
3120 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
3121 R_Shadow_RenderLighting_Light_GLSL(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale, specularscale);
3123 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
3124 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
3125 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
3126 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3127 R_Shadow_RenderLighting_Light_Vertex(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale);
3130 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
3135 switch(vid.renderpath)
3137 case RENDERPATH_GL11:
3138 case RENDERPATH_GL13:
3139 case RENDERPATH_GL20:
3140 case RENDERPATH_GLES2:
3141 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
3143 case RENDERPATH_D3D9:
3145 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_ADD);
3148 case RENDERPATH_D3D10:
3149 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3151 case RENDERPATH_D3D11:
3152 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3154 case RENDERPATH_SOFT:
3155 DPSOFTRAST_BlendSubtract(false);
3161 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)
3163 matrix4x4_t tempmatrix = *matrix;
3164 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
3166 // if this light has been compiled before, free the associated data
3167 R_RTLight_Uncompile(rtlight);
3169 // clear it completely to avoid any lingering data
3170 memset(rtlight, 0, sizeof(*rtlight));
3172 // copy the properties
3173 rtlight->matrix_lighttoworld = tempmatrix;
3174 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
3175 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
3176 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
3177 VectorCopy(color, rtlight->color);
3178 rtlight->cubemapname[0] = 0;
3179 if (cubemapname && cubemapname[0])
3180 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
3181 rtlight->shadow = shadow;
3182 rtlight->corona = corona;
3183 rtlight->style = style;
3184 rtlight->isstatic = isstatic;
3185 rtlight->coronasizescale = coronasizescale;
3186 rtlight->ambientscale = ambientscale;
3187 rtlight->diffusescale = diffusescale;
3188 rtlight->specularscale = specularscale;
3189 rtlight->flags = flags;
3191 // compute derived data
3192 //rtlight->cullradius = rtlight->radius;
3193 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
3194 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3195 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3196 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3197 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3198 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3199 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3202 // compiles rtlight geometry
3203 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
3204 void R_RTLight_Compile(rtlight_t *rtlight)
3207 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
3208 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
3209 entity_render_t *ent = r_refdef.scene.worldentity;
3210 dp_model_t *model = r_refdef.scene.worldmodel;
3211 unsigned char *data;
3214 // compile the light
3215 rtlight->compiled = true;
3216 rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
3217 rtlight->static_numleafs = 0;
3218 rtlight->static_numleafpvsbytes = 0;
3219 rtlight->static_leaflist = NULL;
3220 rtlight->static_leafpvs = NULL;
3221 rtlight->static_numsurfaces = 0;
3222 rtlight->static_surfacelist = NULL;
3223 rtlight->static_shadowmap_receivers = 0x3F;
3224 rtlight->static_shadowmap_casters = 0x3F;
3225 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3226 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3227 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3228 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3229 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3230 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3232 if (model && model->GetLightInfo)
3234 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
3235 r_shadow_compilingrtlight = rtlight;
3236 R_FrameData_SetMark();
3237 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);
3238 R_FrameData_ReturnToMark();
3239 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
3240 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
3241 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3242 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
3243 rtlight->static_numsurfaces = numsurfaces;
3244 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
3245 rtlight->static_numleafs = numleafs;
3246 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
3247 rtlight->static_numleafpvsbytes = numleafpvsbytes;
3248 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
3249 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
3250 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
3251 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
3252 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3253 if (rtlight->static_numsurfaces)
3254 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3255 if (rtlight->static_numleafs)
3256 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3257 if (rtlight->static_numleafpvsbytes)
3258 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3259 if (rtlight->static_numshadowtrispvsbytes)
3260 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3261 if (rtlight->static_numlighttrispvsbytes)
3262 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3263 R_FrameData_SetMark();
3264 switch (rtlight->shadowmode)
3266 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
3267 if (model->CompileShadowMap && rtlight->shadow)
3268 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3271 if (model->CompileShadowVolume && rtlight->shadow)
3272 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3275 R_FrameData_ReturnToMark();
3276 // now we're done compiling the rtlight
3277 r_shadow_compilingrtlight = NULL;
3281 // use smallest available cullradius - box radius or light radius
3282 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3283 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3285 shadowzpasstris = 0;
3286 if (rtlight->static_meshchain_shadow_zpass)
3287 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
3288 shadowzpasstris += mesh->numtriangles;
3290 shadowzfailtris = 0;
3291 if (rtlight->static_meshchain_shadow_zfail)
3292 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
3293 shadowzfailtris += mesh->numtriangles;
3296 if (rtlight->static_numlighttrispvsbytes)
3297 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3298 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3302 if (rtlight->static_numlighttrispvsbytes)
3303 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3304 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3307 if (developer_extra.integer)
3308 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);
3311 void R_RTLight_Uncompile(rtlight_t *rtlight)
3313 if (rtlight->compiled)
3315 if (rtlight->static_meshchain_shadow_zpass)
3316 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
3317 rtlight->static_meshchain_shadow_zpass = NULL;
3318 if (rtlight->static_meshchain_shadow_zfail)
3319 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
3320 rtlight->static_meshchain_shadow_zfail = NULL;
3321 if (rtlight->static_meshchain_shadow_shadowmap)
3322 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
3323 rtlight->static_meshchain_shadow_shadowmap = NULL;
3324 // these allocations are grouped
3325 if (rtlight->static_surfacelist)
3326 Mem_Free(rtlight->static_surfacelist);
3327 rtlight->static_numleafs = 0;
3328 rtlight->static_numleafpvsbytes = 0;
3329 rtlight->static_leaflist = NULL;
3330 rtlight->static_leafpvs = NULL;
3331 rtlight->static_numsurfaces = 0;
3332 rtlight->static_surfacelist = NULL;
3333 rtlight->static_numshadowtrispvsbytes = 0;
3334 rtlight->static_shadowtrispvs = NULL;
3335 rtlight->static_numlighttrispvsbytes = 0;
3336 rtlight->static_lighttrispvs = NULL;
3337 rtlight->compiled = false;
3341 void R_Shadow_UncompileWorldLights(void)
3345 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3346 for (lightindex = 0;lightindex < range;lightindex++)
3348 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3351 R_RTLight_Uncompile(&light->rtlight);
3355 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3359 // reset the count of frustum planes
3360 // see rtlight->cached_frustumplanes definition for how much this array
3362 rtlight->cached_numfrustumplanes = 0;
3364 // haven't implemented a culling path for ortho rendering
3365 if (!r_refdef.view.useperspective)
3367 // check if the light is on screen and copy the 4 planes if it is
3368 for (i = 0;i < 4;i++)
3369 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3372 for (i = 0;i < 4;i++)
3373 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3378 // generate a deformed frustum that includes the light origin, this is
3379 // used to cull shadow casting surfaces that can not possibly cast a
3380 // shadow onto the visible light-receiving surfaces, which can be a
3383 // if the light origin is onscreen the result will be 4 planes exactly
3384 // if the light origin is offscreen on only one axis the result will
3385 // be exactly 5 planes (split-side case)
3386 // if the light origin is offscreen on two axes the result will be
3387 // exactly 4 planes (stretched corner case)
3388 for (i = 0;i < 4;i++)
3390 // quickly reject standard frustum planes that put the light
3391 // origin outside the frustum
3392 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3395 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3397 // if all the standard frustum planes were accepted, the light is onscreen
3398 // otherwise we need to generate some more planes below...
3399 if (rtlight->cached_numfrustumplanes < 4)
3401 // at least one of the stock frustum planes failed, so we need to
3402 // create one or two custom planes to enclose the light origin
3403 for (i = 0;i < 4;i++)
3405 // create a plane using the view origin and light origin, and a
3406 // single point from the frustum corner set
3407 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3408 VectorNormalize(plane.normal);
3409 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3410 // see if this plane is backwards and flip it if so
3411 for (j = 0;j < 4;j++)
3412 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3416 VectorNegate(plane.normal, plane.normal);
3418 // flipped plane, test again to see if it is now valid
3419 for (j = 0;j < 4;j++)
3420 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3422 // if the plane is still not valid, then it is dividing the
3423 // frustum and has to be rejected
3427 // we have created a valid plane, compute extra info
3428 PlaneClassify(&plane);
3430 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3432 // if we've found 5 frustum planes then we have constructed a
3433 // proper split-side case and do not need to keep searching for
3434 // planes to enclose the light origin
3435 if (rtlight->cached_numfrustumplanes == 5)
3443 for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
3445 plane = rtlight->cached_frustumplanes[i];
3446 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));
3451 // now add the light-space box planes if the light box is rotated, as any
3452 // caster outside the oriented light box is irrelevant (even if it passed
3453 // the worldspace light box, which is axial)
3454 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3456 for (i = 0;i < 6;i++)
3460 v[i >> 1] = (i & 1) ? -1 : 1;
3461 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3462 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3463 plane.dist = VectorNormalizeLength(plane.normal);
3464 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3465 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3471 // add the world-space reduced box planes
3472 for (i = 0;i < 6;i++)
3474 VectorClear(plane.normal);
3475 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3476 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
3477 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3486 // reduce all plane distances to tightly fit the rtlight cull box, which
3488 VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3489 VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3490 VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3491 VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3492 VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3493 VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3494 VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3495 VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3496 oldnum = rtlight->cached_numfrustumplanes;
3497 rtlight->cached_numfrustumplanes = 0;
3498 for (j = 0;j < oldnum;j++)
3500 // find the nearest point on the box to this plane
3501 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
3502 for (i = 1;i < 8;i++)
3504 dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
3505 if (bestdist > dist)
3508 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);
3509 // if the nearest point is near or behind the plane, we want this
3510 // plane, otherwise the plane is useless as it won't cull anything
3511 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
3513 PlaneClassify(&rtlight->cached_frustumplanes[j]);
3514 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
3521 void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
3525 RSurf_ActiveWorldEntity();
3527 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3530 GL_CullFace(GL_NONE);
3531 mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3532 for (;mesh;mesh = mesh->next)
3534 if (!mesh->sidetotals[r_shadow_shadowmapside])
3536 r_refdef.stats.lights_shadowtriangles += mesh->sidetotals[r_shadow_shadowmapside];
3537 if (mesh->vertex3fbuffer)
3538 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vertex3fbuffer);
3540 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer);
3541 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);
3545 else if (r_refdef.scene.worldentity->model)
3546 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);
3548 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3551 void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3553 qboolean zpass = false;
3556 int surfacelistindex;
3557 msurface_t *surface;
3559 // if triangle neighbors are disabled, shadowvolumes are disabled
3560 if (r_refdef.scene.worldmodel->brush.shadowmesh ? !r_refdef.scene.worldmodel->brush.shadowmesh->neighbor3i : !r_refdef.scene.worldmodel->surfmesh.data_neighbor3i)
3563 RSurf_ActiveWorldEntity();
3565 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3568 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
3570 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
3571 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
3573 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
3574 for (;mesh;mesh = mesh->next)
3576 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
3577 if (mesh->vertex3fbuffer)
3578 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vertex3fbuffer);
3580 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer);
3581 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
3583 // increment stencil if frontface is infront of depthbuffer
3584 GL_CullFace(r_refdef.view.cullface_back);
3585 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
3586 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);
3587 // decrement stencil if backface is infront of depthbuffer
3588 GL_CullFace(r_refdef.view.cullface_front);
3589 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
3591 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
3593 // decrement stencil if backface is behind depthbuffer
3594 GL_CullFace(r_refdef.view.cullface_front);
3595 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
3596 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3i_indexbuffer, mesh->element3i_bufferoffset, mesh->element3s, mesh->element3s_indexbuffer, mesh->element3s_bufferoffset);
3597 // increment stencil if frontface is behind depthbuffer
3598 GL_CullFace(r_refdef.view.cullface_back);
3599 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
3601 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);
3605 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh)
3607 // use the shadow trispvs calculated earlier by GetLightInfo to cull world triangles on this dynamic light
3608 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
3609 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
3611 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
3612 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
3613 if (CHECKPVSBIT(trispvs, t))
3614 shadowmarklist[numshadowmark++] = t;
3616 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);
3618 else if (numsurfaces)
3620 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);
3623 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3626 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3628 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3629 vec_t relativeshadowradius;
3630 RSurf_ActiveModelEntity(ent, false, false, false);
3631 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3632 // we need to re-init the shader for each entity because the matrix changed
3633 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3634 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3635 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3636 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3637 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3638 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3639 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3640 switch (r_shadow_rendermode)
3642 case R_SHADOW_RENDERMODE_SHADOWMAP2D:
3643 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
3646 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3649 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3652 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3654 // set up properties for rendering light onto this entity
3655 RSurf_ActiveModelEntity(ent, true, true, false);
3656 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3657 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3658 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3659 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3662 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
3664 if (!r_refdef.scene.worldmodel->DrawLight)
3667 // set up properties for rendering light onto this entity
3668 RSurf_ActiveWorldEntity();
3669 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3670 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3671 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3672 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3674 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
3676 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3679 void R_Shadow_DrawEntityLight(entity_render_t *ent)
3681 dp_model_t *model = ent->model;
3682 if (!model->DrawLight)
3685 R_Shadow_SetupEntityLight(ent);
3687 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3689 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3692 void R_Shadow_PrepareLight(rtlight_t *rtlight)
3696 int numleafs, numsurfaces;
3697 int *leaflist, *surfacelist;
3698 unsigned char *leafpvs;
3699 unsigned char *shadowtrispvs;
3700 unsigned char *lighttrispvs;
3701 //unsigned char *surfacesides;
3702 int numlightentities;
3703 int numlightentities_noselfshadow;
3704 int numshadowentities;
3705 int numshadowentities_noselfshadow;
3706 static entity_render_t *lightentities[MAX_EDICTS];
3707 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3708 static entity_render_t *shadowentities[MAX_EDICTS];
3709 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3712 rtlight->draw = false;
3714 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3715 // skip lights that are basically invisible (color 0 0 0)
3716 nolight = VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f);
3718 // loading is done before visibility checks because loading should happen
3719 // all at once at the start of a level, not when it stalls gameplay.
3720 // (especially important to benchmarks)
3722 if (rtlight->isstatic && !nolight && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
3724 if (rtlight->compiled)
3725 R_RTLight_Uncompile(rtlight);
3726 R_RTLight_Compile(rtlight);
3730 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
3732 // look up the light style value at this time
3733 f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3734 VectorScale(rtlight->color, f, rtlight->currentcolor);
3736 if (rtlight->selected)
3738 f = 2 + sin(realtime * M_PI * 4.0);
3739 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3743 // if lightstyle is currently off, don't draw the light
3744 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3747 // skip processing on corona-only lights
3751 // if the light box is offscreen, skip it
3752 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3755 VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
3756 VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
3758 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3760 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3762 // compiled light, world available and can receive realtime lighting
3763 // retrieve leaf information
3764 numleafs = rtlight->static_numleafs;
3765 leaflist = rtlight->static_leaflist;
3766 leafpvs = rtlight->static_leafpvs;
3767 numsurfaces = rtlight->static_numsurfaces;
3768 surfacelist = rtlight->static_surfacelist;
3769 //surfacesides = NULL;
3770 shadowtrispvs = rtlight->static_shadowtrispvs;
3771 lighttrispvs = rtlight->static_lighttrispvs;
3773 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3775 // dynamic light, world available and can receive realtime lighting
3776 // calculate lit surfaces and leafs
3777 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);
3778 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3779 leaflist = r_shadow_buffer_leaflist;
3780 leafpvs = r_shadow_buffer_leafpvs;
3781 surfacelist = r_shadow_buffer_surfacelist;
3782 //surfacesides = r_shadow_buffer_surfacesides;
3783 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3784 lighttrispvs = r_shadow_buffer_lighttrispvs;
3785 // if the reduced leaf bounds are offscreen, skip it
3786 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3797 //surfacesides = NULL;
3798 shadowtrispvs = NULL;
3799 lighttrispvs = NULL;
3801 // check if light is illuminating any visible leafs
3804 for (i = 0;i < numleafs;i++)
3805 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3811 // make a list of lit entities and shadow casting entities
3812 numlightentities = 0;
3813 numlightentities_noselfshadow = 0;
3814 numshadowentities = 0;
3815 numshadowentities_noselfshadow = 0;
3817 // add dynamic entities that are lit by the light
3818 for (i = 0;i < r_refdef.scene.numentities;i++)
3821 entity_render_t *ent = r_refdef.scene.entities[i];
3823 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3825 // skip the object entirely if it is not within the valid
3826 // shadow-casting region (which includes the lit region)
3827 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
3829 if (!(model = ent->model))
3831 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
3833 // this entity wants to receive light, is visible, and is
3834 // inside the light box
3835 // TODO: check if the surfaces in the model can receive light
3836 // so now check if it's in a leaf seen by the light
3837 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))
3839 if (ent->flags & RENDER_NOSELFSHADOW)
3840 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
3842 lightentities[numlightentities++] = ent;
3843 // since it is lit, it probably also casts a shadow...
3844 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3845 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3846 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3848 // note: exterior models without the RENDER_NOSELFSHADOW
3849 // flag still create a RENDER_NOSELFSHADOW shadow but
3850 // are lit normally, this means that they are
3851 // self-shadowing but do not shadow other
3852 // RENDER_NOSELFSHADOW entities such as the gun
3853 // (very weird, but keeps the player shadow off the gun)
3854 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3855 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3857 shadowentities[numshadowentities++] = ent;
3860 else if (ent->flags & RENDER_SHADOW)
3862 // this entity is not receiving light, but may still need to
3864 // TODO: check if the surfaces in the model can cast shadow
3865 // now check if it is in a leaf seen by the light
3866 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))
3868 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3869 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3870 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3872 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3873 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3875 shadowentities[numshadowentities++] = ent;
3880 // return if there's nothing at all to light
3881 if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
3884 // count this light in the r_speeds
3885 r_refdef.stats.lights++;
3887 // flag it as worth drawing later
3888 rtlight->draw = true;
3890 // cache all the animated entities that cast a shadow but are not visible
3891 for (i = 0;i < numshadowentities;i++)
3892 if (!shadowentities[i]->animcache_vertex3f)
3893 R_AnimCache_GetEntity(shadowentities[i], false, false);
3894 for (i = 0;i < numshadowentities_noselfshadow;i++)
3895 if (!shadowentities_noselfshadow[i]->animcache_vertex3f)
3896 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
3898 // allocate some temporary memory for rendering this light later in the frame
3899 // reusable buffers need to be copied, static data can be used as-is
3900 rtlight->cached_numlightentities = numlightentities;
3901 rtlight->cached_numlightentities_noselfshadow = numlightentities_noselfshadow;
3902 rtlight->cached_numshadowentities = numshadowentities;
3903 rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
3904 rtlight->cached_numsurfaces = numsurfaces;
3905 rtlight->cached_lightentities = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
3906 rtlight->cached_lightentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
3907 rtlight->cached_shadowentities = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
3908 rtlight->cached_shadowentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
3909 if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
3911 int numshadowtrispvsbytes = (((r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles) + 7) >> 3);
3912 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
3913 rtlight->cached_shadowtrispvs = (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
3914 rtlight->cached_lighttrispvs = (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
3915 rtlight->cached_surfacelist = (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
3919 // compiled light data
3920 rtlight->cached_shadowtrispvs = shadowtrispvs;
3921 rtlight->cached_lighttrispvs = lighttrispvs;
3922 rtlight->cached_surfacelist = surfacelist;
3926 void R_Shadow_DrawLight(rtlight_t *rtlight)
3930 unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
3931 int numlightentities;
3932 int numlightentities_noselfshadow;
3933 int numshadowentities;
3934 int numshadowentities_noselfshadow;
3935 entity_render_t **lightentities;
3936 entity_render_t **lightentities_noselfshadow;
3937 entity_render_t **shadowentities;
3938 entity_render_t **shadowentities_noselfshadow;
3940 static unsigned char entitysides[MAX_EDICTS];
3941 static unsigned char entitysides_noselfshadow[MAX_EDICTS];
3942 vec3_t nearestpoint;
3944 qboolean castshadows;
3947 // check if we cached this light this frame (meaning it is worth drawing)
3951 numlightentities = rtlight->cached_numlightentities;
3952 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
3953 numshadowentities = rtlight->cached_numshadowentities;
3954 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
3955 numsurfaces = rtlight->cached_numsurfaces;
3956 lightentities = rtlight->cached_lightentities;
3957 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
3958 shadowentities = rtlight->cached_shadowentities;
3959 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
3960 shadowtrispvs = rtlight->cached_shadowtrispvs;
3961 lighttrispvs = rtlight->cached_lighttrispvs;
3962 surfacelist = rtlight->cached_surfacelist;
3964 // set up a scissor rectangle for this light
3965 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3968 // don't let sound skip if going slow
3969 if (r_refdef.scene.extraupdate)
3972 // make this the active rtlight for rendering purposes
3973 R_Shadow_RenderMode_ActiveLight(rtlight);
3975 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
3977 // optionally draw visible shape of the shadow volumes
3978 // for performance analysis by level designers
3979 R_Shadow_RenderMode_VisibleShadowVolumes();
3981 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
3982 for (i = 0;i < numshadowentities;i++)
3983 R_Shadow_DrawEntityShadow(shadowentities[i]);
3984 for (i = 0;i < numshadowentities_noselfshadow;i++)
3985 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3986 R_Shadow_RenderMode_VisibleLighting(false, false);
3989 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
3991 // optionally draw the illuminated areas
3992 // for performance analysis by level designers
3993 R_Shadow_RenderMode_VisibleLighting(false, false);
3995 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3996 for (i = 0;i < numlightentities;i++)
3997 R_Shadow_DrawEntityLight(lightentities[i]);
3998 for (i = 0;i < numlightentities_noselfshadow;i++)
3999 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4002 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
4004 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
4005 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
4006 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
4007 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
4009 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance/rtlight->radius));
4010 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
4011 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
4013 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
4019 int receivermask = 0;
4020 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
4021 Matrix4x4_Abs(&radiustolight);
4023 r_shadow_shadowmaplod = 0;
4024 for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
4025 if ((r_shadow_shadowmapmaxsize >> i) > lodlinear)
4026 r_shadow_shadowmaplod = i;
4028 size = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
4030 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
4032 surfacesides = NULL;
4035 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
4037 castermask = rtlight->static_shadowmap_casters;
4038 receivermask = rtlight->static_shadowmap_receivers;
4042 surfacesides = r_shadow_buffer_surfacesides;
4043 for(i = 0;i < numsurfaces;i++)
4045 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
4046 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4047 castermask |= surfacesides[i];
4048 receivermask |= surfacesides[i];
4052 if (receivermask < 0x3F)
4054 for (i = 0;i < numlightentities;i++)
4055 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4056 if (receivermask < 0x3F)
4057 for(i = 0; i < numlightentities_noselfshadow;i++)
4058 receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4061 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
4065 for (i = 0;i < numshadowentities;i++)
4066 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
4067 for (i = 0;i < numshadowentities_noselfshadow;i++)
4068 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
4071 //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
4073 // render shadow casters into 6 sided depth texture
4074 for (side = 0;side < 6;side++) if (receivermask & (1 << side))
4076 R_Shadow_RenderMode_ShadowMap(side, receivermask, size);
4077 if (! (castermask & (1 << side))) continue;
4079 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
4080 for (i = 0;i < numshadowentities;i++) if (entitysides[i] & (1 << side))
4081 R_Shadow_DrawEntityShadow(shadowentities[i]);
4084 if (numlightentities_noselfshadow)
4086 // render lighting using the depth texture as shadowmap
4087 // draw lighting in the unmasked areas
4088 R_Shadow_RenderMode_Lighting(false, false, true);
4089 for (i = 0;i < numlightentities_noselfshadow;i++)
4090 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4093 // render shadow casters into 6 sided depth texture
4094 if (numshadowentities_noselfshadow)
4096 for (side = 0;side < 6;side++) if ((receivermask & castermask) & (1 << side))
4098 R_Shadow_RenderMode_ShadowMap(side, 0, size);
4099 for (i = 0;i < numshadowentities_noselfshadow;i++) if (entitysides_noselfshadow[i] & (1 << side))
4100 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
4104 // render lighting using the depth texture as shadowmap
4105 // draw lighting in the unmasked areas
4106 R_Shadow_RenderMode_Lighting(false, false, true);
4107 // draw lighting in the unmasked areas
4109 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4110 for (i = 0;i < numlightentities;i++)
4111 R_Shadow_DrawEntityLight(lightentities[i]);
4113 else if (castshadows && vid.stencil)
4115 // draw stencil shadow volumes to mask off pixels that are in shadow
4116 // so that they won't receive lighting
4117 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
4118 R_Shadow_ClearStencil();
4121 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
4122 for (i = 0;i < numshadowentities;i++)
4123 R_Shadow_DrawEntityShadow(shadowentities[i]);
4125 // draw lighting in the unmasked areas
4126 R_Shadow_RenderMode_Lighting(true, false, false);
4127 for (i = 0;i < numlightentities_noselfshadow;i++)
4128 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4130 for (i = 0;i < numshadowentities_noselfshadow;i++)
4131 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
4133 // draw lighting in the unmasked areas
4134 R_Shadow_RenderMode_Lighting(true, false, false);
4136 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4137 for (i = 0;i < numlightentities;i++)
4138 R_Shadow_DrawEntityLight(lightentities[i]);
4142 // draw lighting in the unmasked areas
4143 R_Shadow_RenderMode_Lighting(false, false, false);
4145 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4146 for (i = 0;i < numlightentities;i++)
4147 R_Shadow_DrawEntityLight(lightentities[i]);
4148 for (i = 0;i < numlightentities_noselfshadow;i++)
4149 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4152 if (r_shadow_usingdeferredprepass)
4154 // when rendering deferred lighting, we simply rasterize the box
4155 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
4156 R_Shadow_RenderMode_DrawDeferredLight(false, true);
4157 else if (castshadows && vid.stencil)
4158 R_Shadow_RenderMode_DrawDeferredLight(true, false);
4160 R_Shadow_RenderMode_DrawDeferredLight(false, false);
4164 static void R_Shadow_FreeDeferred(void)
4166 R_Mesh_DestroyFramebufferObject(r_shadow_prepassgeometryfbo);
4167 r_shadow_prepassgeometryfbo = 0;
4169 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusespecularfbo);
4170 r_shadow_prepasslightingdiffusespecularfbo = 0;
4172 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusefbo);
4173 r_shadow_prepasslightingdiffusefbo = 0;
4175 if (r_shadow_prepassgeometrydepthtexture)
4176 R_FreeTexture(r_shadow_prepassgeometrydepthtexture);
4177 r_shadow_prepassgeometrydepthtexture = NULL;
4179 if (r_shadow_prepassgeometrydepthcolortexture)
4180 R_FreeTexture(r_shadow_prepassgeometrydepthcolortexture);
4181 r_shadow_prepassgeometrydepthcolortexture = NULL;
4183 if (r_shadow_prepassgeometrynormalmaptexture)
4184 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
4185 r_shadow_prepassgeometrynormalmaptexture = NULL;
4187 if (r_shadow_prepasslightingdiffusetexture)
4188 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
4189 r_shadow_prepasslightingdiffusetexture = NULL;
4191 if (r_shadow_prepasslightingspeculartexture)
4192 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
4193 r_shadow_prepasslightingspeculartexture = NULL;
4196 void R_Shadow_DrawPrepass(void)
4204 entity_render_t *ent;
4205 float clearcolor[4];
4207 R_Mesh_ResetTextureState();
4209 GL_ColorMask(1,1,1,1);
4210 GL_BlendFunc(GL_ONE, GL_ZERO);
4213 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, r_shadow_prepassgeometrydepthcolortexture, NULL, NULL);
4214 Vector4Set(clearcolor, 0.5f,0.5f,0.5f,1.0f);
4215 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4216 if (r_timereport_active)
4217 R_TimeReport("prepasscleargeom");
4219 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
4220 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
4221 if (r_timereport_active)
4222 R_TimeReport("prepassworld");
4224 for (i = 0;i < r_refdef.scene.numentities;i++)
4226 if (!r_refdef.viewcache.entityvisible[i])
4228 ent = r_refdef.scene.entities[i];
4229 if (ent->model && ent->model->DrawPrepass != NULL)
4230 ent->model->DrawPrepass(ent);
4233 if (r_timereport_active)
4234 R_TimeReport("prepassmodels");
4236 GL_DepthMask(false);
4237 GL_ColorMask(1,1,1,1);
4240 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4241 Vector4Set(clearcolor, 0, 0, 0, 0);
4242 GL_Clear(GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
4243 if (r_timereport_active)
4244 R_TimeReport("prepassclearlit");
4246 R_Shadow_RenderMode_Begin();
4248 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4249 if (r_shadow_debuglight.integer >= 0)
4251 lightindex = r_shadow_debuglight.integer;
4252 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4253 if (light && (light->flags & flag) && light->rtlight.draw)
4254 R_Shadow_DrawLight(&light->rtlight);
4258 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4259 for (lightindex = 0;lightindex < range;lightindex++)
4261 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4262 if (light && (light->flags & flag) && light->rtlight.draw)
4263 R_Shadow_DrawLight(&light->rtlight);
4266 if (r_refdef.scene.rtdlight)
4267 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4268 if (r_refdef.scene.lights[lnum]->draw)
4269 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4271 R_Mesh_ResetRenderTargets();
4273 R_Shadow_RenderMode_End();
4275 if (r_timereport_active)
4276 R_TimeReport("prepasslights");
4279 void R_Shadow_DrawLightSprites(void);
4280 void R_Shadow_PrepareLights(void)
4290 if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4) ||
4291 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
4292 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20) ||
4293 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
4294 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
4295 r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
4296 R_Shadow_FreeShadowMaps();
4298 r_shadow_usingshadowmaportho = false;
4300 switch (vid.renderpath)
4302 case RENDERPATH_GL20:
4303 case RENDERPATH_D3D9:
4304 case RENDERPATH_D3D10:
4305 case RENDERPATH_D3D11:
4306 case RENDERPATH_SOFT:
4307 case RENDERPATH_GLES2:
4308 if (!r_shadow_deferred.integer || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_STENCIL || !vid.support.ext_framebuffer_object || vid.maxdrawbuffers < 2)
4310 r_shadow_usingdeferredprepass = false;
4311 if (r_shadow_prepass_width)
4312 R_Shadow_FreeDeferred();
4313 r_shadow_prepass_width = r_shadow_prepass_height = 0;
4317 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
4319 R_Shadow_FreeDeferred();
4321 r_shadow_usingdeferredprepass = true;
4322 r_shadow_prepass_width = vid.width;
4323 r_shadow_prepass_height = vid.height;
4324 r_shadow_prepassgeometrydepthtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "prepassgeometrydepthmap", vid.width, vid.height, 24, false);
4325 switch (vid.renderpath)
4327 case RENDERPATH_D3D9:
4328 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);
4333 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);
4334 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);
4335 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);
4337 // set up the geometry pass fbo (depth + normalmap)
4338 r_shadow_prepassgeometryfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4339 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, r_shadow_prepassgeometrydepthcolortexture, NULL, NULL);
4340 // render depth into one texture and normalmap into the other
4341 if (qglDrawBuffersARB)
4343 qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);CHECKGLERROR
4344 qglReadBuffer(GL_NONE);CHECKGLERROR
4345 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4346 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4348 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4349 Cvar_SetValueQuick(&r_shadow_deferred, 0);
4350 r_shadow_usingdeferredprepass = false;
4354 // set up the lighting pass fbo (diffuse + specular)
4355 r_shadow_prepasslightingdiffusespecularfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4356 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4357 // render diffuse into one texture and specular into another,
4358 // with depth and normalmap bound as textures,
4359 // with depth bound as attachment as well
4360 if (qglDrawBuffersARB)
4362 qglDrawBuffersARB(2, r_shadow_prepasslightingdrawbuffers);CHECKGLERROR
4363 qglReadBuffer(GL_NONE);CHECKGLERROR
4364 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4365 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4367 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4368 Cvar_SetValueQuick(&r_shadow_deferred, 0);
4369 r_shadow_usingdeferredprepass = false;
4373 // set up the lighting pass fbo (diffuse)
4374 r_shadow_prepasslightingdiffusefbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
4375 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
4376 // render diffuse into one texture,
4377 // with depth and normalmap bound as textures,
4378 // with depth bound as attachment as well
4379 if (qglDrawBuffersARB)
4381 qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);CHECKGLERROR
4382 qglReadBuffer(GL_NONE);CHECKGLERROR
4383 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4384 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4386 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4387 Cvar_SetValueQuick(&r_shadow_deferred, 0);
4388 r_shadow_usingdeferredprepass = false;
4393 case RENDERPATH_GL13:
4394 case RENDERPATH_GL11:
4395 r_shadow_usingdeferredprepass = false;
4399 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);
4401 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4402 if (r_shadow_debuglight.integer >= 0)
4404 lightindex = r_shadow_debuglight.integer;
4405 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4406 if (light && (light->flags & flag))
4407 R_Shadow_PrepareLight(&light->rtlight);
4411 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4412 for (lightindex = 0;lightindex < range;lightindex++)
4414 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4415 if (light && (light->flags & flag))
4416 R_Shadow_PrepareLight(&light->rtlight);
4419 if (r_refdef.scene.rtdlight)
4421 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4422 R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
4424 else if(gl_flashblend.integer)
4426 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4428 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
4429 f = (rtlight->style >= 0 ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4430 VectorScale(rtlight->color, f, rtlight->currentcolor);
4434 if (r_editlights.integer)
4435 R_Shadow_DrawLightSprites();
4437 R_Shadow_UpdateBounceGridTexture();
4440 void R_Shadow_DrawLights(void)
4448 R_Shadow_RenderMode_Begin();
4450 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4451 if (r_shadow_debuglight.integer >= 0)
4453 lightindex = r_shadow_debuglight.integer;
4454 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4455 if (light && (light->flags & flag))
4456 R_Shadow_DrawLight(&light->rtlight);
4460 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4461 for (lightindex = 0;lightindex < range;lightindex++)
4463 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4464 if (light && (light->flags & flag))
4465 R_Shadow_DrawLight(&light->rtlight);
4468 if (r_refdef.scene.rtdlight)
4469 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4470 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4472 R_Shadow_RenderMode_End();
4475 extern const float r_screenvertex3f[12];
4476 extern void R_SetupView(qboolean allowwaterclippingplane);
4477 extern void R_ResetViewRendering3D(void);
4478 extern void R_ResetViewRendering2D(void);
4479 extern cvar_t r_shadows;
4480 extern cvar_t r_shadows_darken;
4481 extern cvar_t r_shadows_drawafterrtlighting;
4482 extern cvar_t r_shadows_castfrombmodels;
4483 extern cvar_t r_shadows_throwdistance;
4484 extern cvar_t r_shadows_throwdirection;
4485 extern cvar_t r_shadows_focus;
4486 extern cvar_t r_shadows_shadowmapscale;
4488 void R_Shadow_PrepareModelShadows(void)
4491 float scale, size, radius, dot1, dot2;
4492 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
4493 entity_render_t *ent;
4495 if (!r_refdef.scene.numentities)
4498 switch (r_shadow_shadowmode)
4500 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4501 if (r_shadows.integer >= 2)
4504 case R_SHADOW_SHADOWMODE_STENCIL:
4505 for (i = 0;i < r_refdef.scene.numentities;i++)
4507 ent = r_refdef.scene.entities[i];
4508 if (!ent->animcache_vertex3f && ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4509 R_AnimCache_GetEntity(ent, false, false);
4516 size = 2*r_shadow_shadowmapmaxsize;
4517 scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
4518 radius = 0.5f * size / scale;
4520 Math_atov(r_shadows_throwdirection.string, shadowdir);
4521 VectorNormalize(shadowdir);
4522 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4523 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4524 if (fabs(dot1) <= fabs(dot2))
4525 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4527 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4528 VectorNormalize(shadowforward);
4529 CrossProduct(shadowdir, shadowforward, shadowright);
4530 Math_atov(r_shadows_focus.string, shadowfocus);
4531 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4532 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4533 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4534 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4535 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4537 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4539 shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4540 shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4541 shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4542 shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4543 shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4544 shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4546 for (i = 0;i < r_refdef.scene.numentities;i++)
4548 ent = r_refdef.scene.entities[i];
4549 if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
4551 // cast shadows from anything of the map (submodels are optional)
4552 if (!ent->animcache_vertex3f && ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4553 R_AnimCache_GetEntity(ent, false, false);
4557 void R_DrawModelShadowMaps(void)
4560 float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
4561 entity_render_t *ent;
4562 vec3_t relativelightorigin;
4563 vec3_t relativelightdirection, relativeforward, relativeright;
4564 vec3_t relativeshadowmins, relativeshadowmaxs;
4565 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
4567 matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
4568 r_viewport_t viewport;
4570 float clearcolor[4];
4572 if (!r_refdef.scene.numentities)
4575 switch (r_shadow_shadowmode)
4577 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4583 R_ResetViewRendering3D();
4584 R_Shadow_RenderMode_Begin();
4585 R_Shadow_RenderMode_ActiveLight(NULL);
4587 switch (r_shadow_shadowmode)
4589 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4590 if (!r_shadow_shadowmap2dtexture)
4591 R_Shadow_MakeShadowMap(0, r_shadow_shadowmapmaxsize);
4592 fbo = r_shadow_fbo2d;
4593 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
4594 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
4595 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
4601 size = 2*r_shadow_shadowmapmaxsize;
4602 scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
4603 radius = 0.5f / scale;
4604 nearclip = -r_shadows_throwdistance.value;
4605 farclip = r_shadows_throwdistance.value;
4606 bias = r_shadow_shadowmapping_bias.value * r_shadow_shadowmapping_nearclip.value / (2 * r_shadows_throwdistance.value) * (1024.0f / size);
4608 r_shadow_shadowmap_parameters[0] = size;
4609 r_shadow_shadowmap_parameters[1] = size;
4610 r_shadow_shadowmap_parameters[2] = 1.0;
4611 r_shadow_shadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
4613 Math_atov(r_shadows_throwdirection.string, shadowdir);
4614 VectorNormalize(shadowdir);
4615 Math_atov(r_shadows_focus.string, shadowfocus);
4616 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4617 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4618 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4619 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4620 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4621 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4622 if (fabs(dot1) <= fabs(dot2))
4623 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4625 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4626 VectorNormalize(shadowforward);
4627 VectorM(scale, shadowforward, &m[0]);
4628 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4630 m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
4631 CrossProduct(shadowdir, shadowforward, shadowright);
4632 VectorM(scale, shadowright, &m[4]);
4633 m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
4634 VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
4635 m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
4636 Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
4637 Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
4638 R_Viewport_InitOrtho(&viewport, &cameramatrix, 0, 0, size, size, 0, 0, 1, 1, 0, -1, NULL);
4640 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4642 R_Mesh_SetRenderTargets(fbo, r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
4643 R_SetupShader_DepthOrShadow();
4644 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
4647 R_SetViewport(&viewport);
4648 GL_Scissor(viewport.x, viewport.y, min(viewport.width + r_shadow_shadowmapborder, 2*r_shadow_shadowmapmaxsize), viewport.height + r_shadow_shadowmapborder);
4649 Vector4Set(clearcolor, 1,1,1,1);
4650 // in D3D9 we have to render to a color texture shadowmap
4651 // in GL we render directly to a depth texture only
4652 if (r_shadow_shadowmap2dtexture)
4653 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4655 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4656 // render into a slightly restricted region so that the borders of the
4657 // shadowmap area fade away, rather than streaking across everything
4658 // outside the usable area
4659 GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
4663 R_Mesh_ResetRenderTargets();
4664 R_SetupShader_ShowDepth();
4665 GL_ColorMask(1,1,1,1);
4666 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4669 for (i = 0;i < r_refdef.scene.numentities;i++)
4671 ent = r_refdef.scene.entities[i];
4673 // cast shadows from anything of the map (submodels are optional)
4674 if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4676 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4677 Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
4678 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4679 Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
4680 Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
4681 relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4682 relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4683 relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4684 relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4685 relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4686 relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4687 RSurf_ActiveModelEntity(ent, false, false, false);
4688 ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
4689 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4696 unsigned char *rawpixels = Z_Malloc(viewport.width*viewport.height*4);
4698 qglReadPixels(viewport.x, viewport.y, viewport.width, viewport.height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, rawpixels);
4700 Image_WriteTGABGRA("r_shadows_2.tga", viewport.width, viewport.height, rawpixels);
4701 Cvar_SetValueQuick(&r_test, 0);
4706 R_Shadow_RenderMode_End();
4708 Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
4709 Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
4710 Matrix4x4_CreateScale3(&scalematrix, size, -size, 1);
4711 Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
4712 Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
4713 Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
4715 switch (vid.renderpath)
4717 case RENDERPATH_GL11:
4718 case RENDERPATH_GL13:
4719 case RENDERPATH_GL20:
4720 case RENDERPATH_SOFT:
4721 case RENDERPATH_GLES2:
4723 case RENDERPATH_D3D9:
4724 case RENDERPATH_D3D10:
4725 case RENDERPATH_D3D11:
4726 #ifdef OPENGL_ORIENTATION
4727 r_shadow_shadowmapmatrix.m[0][0] *= -1.0f;
4728 r_shadow_shadowmapmatrix.m[0][1] *= -1.0f;
4729 r_shadow_shadowmapmatrix.m[0][2] *= -1.0f;
4730 r_shadow_shadowmapmatrix.m[0][3] *= -1.0f;
4732 r_shadow_shadowmapmatrix.m[0][0] *= -1.0f;
4733 r_shadow_shadowmapmatrix.m[1][0] *= -1.0f;
4734 r_shadow_shadowmapmatrix.m[2][0] *= -1.0f;
4735 r_shadow_shadowmapmatrix.m[3][0] *= -1.0f;
4740 r_shadow_usingshadowmaportho = true;
4741 switch (r_shadow_shadowmode)
4743 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4744 r_shadow_usingshadowmap2d = true;
4751 void R_DrawModelShadows(void)
4754 float relativethrowdistance;
4755 entity_render_t *ent;
4756 vec3_t relativelightorigin;
4757 vec3_t relativelightdirection;
4758 vec3_t relativeshadowmins, relativeshadowmaxs;
4759 vec3_t tmp, shadowdir;
4761 if (!r_refdef.scene.numentities || !vid.stencil || (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL && r_shadows.integer != 1))
4764 R_ResetViewRendering3D();
4765 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4766 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4767 R_Shadow_RenderMode_Begin();
4768 R_Shadow_RenderMode_ActiveLight(NULL);
4769 r_shadow_lightscissor[0] = r_refdef.view.x;
4770 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
4771 r_shadow_lightscissor[2] = r_refdef.view.width;
4772 r_shadow_lightscissor[3] = r_refdef.view.height;
4773 R_Shadow_RenderMode_StencilShadowVolumes(false);
4776 if (r_shadows.integer == 2)
4778 Math_atov(r_shadows_throwdirection.string, shadowdir);
4779 VectorNormalize(shadowdir);
4782 R_Shadow_ClearStencil();
4784 for (i = 0;i < r_refdef.scene.numentities;i++)
4786 ent = r_refdef.scene.entities[i];
4788 // cast shadows from anything of the map (submodels are optional)
4789 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4791 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4792 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
4793 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
4794 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
4795 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4798 if(ent->entitynumber != 0)
4800 if(ent->entitynumber >= MAX_EDICTS) // csqc entity
4802 // FIXME handle this
4803 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4807 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
4808 int entnum, entnum2, recursion;
4809 entnum = entnum2 = ent->entitynumber;
4810 for(recursion = 32; recursion > 0; --recursion)
4812 entnum2 = cl.entities[entnum].state_current.tagentity;
4813 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
4818 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
4820 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
4821 // transform into modelspace of OUR entity
4822 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
4823 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
4826 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4830 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4833 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
4834 RSurf_ActiveModelEntity(ent, false, false, false);
4835 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4836 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4840 // not really the right mode, but this will disable any silly stencil features
4841 R_Shadow_RenderMode_End();
4843 // set up ortho view for rendering this pass
4844 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4845 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4846 //GL_ScissorTest(true);
4847 //R_EntityMatrix(&identitymatrix);
4848 //R_Mesh_ResetTextureState();
4849 R_ResetViewRendering2D();
4851 // set up a darkening blend on shadowed areas
4852 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4853 //GL_DepthRange(0, 1);
4854 //GL_DepthTest(false);
4855 //GL_DepthMask(false);
4856 //GL_PolygonOffset(0, 0);CHECKGLERROR
4857 GL_Color(0, 0, 0, r_shadows_darken.value);
4858 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4859 //GL_DepthFunc(GL_ALWAYS);
4860 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_NOTEQUAL, 128, 255);
4862 // apply the blend to the shadowed areas
4863 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, NULL);
4864 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
4865 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4867 // restore the viewport
4868 R_SetViewport(&r_refdef.view.viewport);
4870 // restore other state to normal
4871 //R_Shadow_RenderMode_End();
4874 void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4877 vec3_t centerorigin;
4879 // if it's too close, skip it
4880 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
4882 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4885 if (usequery && r_numqueries + 2 <= r_maxqueries)
4887 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4888 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4889 // 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
4890 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4892 switch(vid.renderpath)
4894 case RENDERPATH_GL20:
4895 case RENDERPATH_GL13:
4896 case RENDERPATH_GL11:
4897 case RENDERPATH_GLES2:
4899 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use GL_DepthFunc instead
4900 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
4901 GL_DepthFunc(GL_ALWAYS);
4902 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4903 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL);
4904 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4905 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4906 GL_DepthFunc(GL_LEQUAL);
4907 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
4908 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4909 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL);
4910 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4911 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4914 case RENDERPATH_D3D9:
4915 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4917 case RENDERPATH_D3D10:
4918 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4920 case RENDERPATH_D3D11:
4921 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4923 case RENDERPATH_SOFT:
4924 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4928 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4931 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
4933 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4936 GLint allpixels = 0, visiblepixels = 0;
4937 // now we have to check the query result
4938 if (rtlight->corona_queryindex_visiblepixels)
4940 switch(vid.renderpath)
4942 case RENDERPATH_GL20:
4943 case RENDERPATH_GL13:
4944 case RENDERPATH_GL11:
4945 case RENDERPATH_GLES2:
4947 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
4948 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
4951 case RENDERPATH_D3D9:
4952 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4954 case RENDERPATH_D3D10:
4955 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4957 case RENDERPATH_D3D11:
4958 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4960 case RENDERPATH_SOFT:
4961 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4964 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
4965 if (visiblepixels < 1 || allpixels < 1)
4967 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
4968 cscale *= rtlight->corona_visibility;
4972 // FIXME: these traces should scan all render entities instead of cl.world
4973 if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false, true).fraction < 1)
4976 VectorScale(rtlight->currentcolor, cscale, color);
4977 if (VectorLength(color) > (1.0f / 256.0f))
4980 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
4983 VectorNegate(color, color);
4984 switch(vid.renderpath)
4986 case RENDERPATH_GL11:
4987 case RENDERPATH_GL13:
4988 case RENDERPATH_GL20:
4989 case RENDERPATH_GLES2:
4990 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
4992 case RENDERPATH_D3D9:
4994 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_SUBTRACT);
4997 case RENDERPATH_D3D10:
4998 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5000 case RENDERPATH_D3D11:
5001 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5003 case RENDERPATH_SOFT:
5004 DPSOFTRAST_BlendSubtract(true);
5008 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5009 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);
5010 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5013 switch(vid.renderpath)
5015 case RENDERPATH_GL11:
5016 case RENDERPATH_GL13:
5017 case RENDERPATH_GL20:
5018 case RENDERPATH_GLES2:
5019 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
5021 case RENDERPATH_D3D9:
5023 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_ADD);
5026 case RENDERPATH_D3D10:
5027 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5029 case RENDERPATH_D3D11:
5030 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5032 case RENDERPATH_SOFT:
5033 DPSOFTRAST_BlendSubtract(false);
5040 void R_Shadow_DrawCoronas(void)
5043 qboolean usequery = false;
5048 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
5050 if (r_waterstate.renderingscene)
5052 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
5053 R_EntityMatrix(&identitymatrix);
5055 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5057 // check occlusion of coronas
5058 // use GL_ARB_occlusion_query if available
5059 // otherwise use raytraces
5061 switch (vid.renderpath)
5063 case RENDERPATH_GL11:
5064 case RENDERPATH_GL13:
5065 case RENDERPATH_GL20:
5066 case RENDERPATH_GLES2:
5067 usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
5070 GL_ColorMask(0,0,0,0);
5071 if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
5072 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
5075 r_maxqueries = (range + r_refdef.scene.numlights) * 4;
5076 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
5078 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
5081 RSurf_ActiveWorldEntity();
5082 GL_BlendFunc(GL_ONE, GL_ZERO);
5083 GL_CullFace(GL_NONE);
5084 GL_DepthMask(false);
5085 GL_DepthRange(0, 1);
5086 GL_PolygonOffset(0, 0);
5088 R_Mesh_ResetTextureState();
5089 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
5092 case RENDERPATH_D3D9:
5094 //Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5096 case RENDERPATH_D3D10:
5097 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5099 case RENDERPATH_D3D11:
5100 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5102 case RENDERPATH_SOFT:
5104 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5107 for (lightindex = 0;lightindex < range;lightindex++)
5109 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5112 rtlight = &light->rtlight;
5113 rtlight->corona_visibility = 0;
5114 rtlight->corona_queryindex_visiblepixels = 0;
5115 rtlight->corona_queryindex_allpixels = 0;
5116 if (!(rtlight->flags & flag))
5118 if (rtlight->corona <= 0)
5120 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
5122 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
5124 for (i = 0;i < r_refdef.scene.numlights;i++)
5126 rtlight = r_refdef.scene.lights[i];
5127 rtlight->corona_visibility = 0;
5128 rtlight->corona_queryindex_visiblepixels = 0;
5129 rtlight->corona_queryindex_allpixels = 0;
5130 if (!(rtlight->flags & flag))
5132 if (rtlight->corona <= 0)
5134 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
5137 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5139 // now draw the coronas using the query data for intensity info
5140 for (lightindex = 0;lightindex < range;lightindex++)
5142 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5145 rtlight = &light->rtlight;
5146 if (rtlight->corona_visibility <= 0)
5148 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
5150 for (i = 0;i < r_refdef.scene.numlights;i++)
5152 rtlight = r_refdef.scene.lights[i];
5153 if (rtlight->corona_visibility <= 0)
5155 if (gl_flashblend.integer)
5156 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
5158 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
5164 dlight_t *R_Shadow_NewWorldLight(void)
5166 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
5169 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)
5172 // validate parameters
5173 if (style < 0 || style >= MAX_LIGHTSTYLES)
5175 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
5181 // copy to light properties
5182 VectorCopy(origin, light->origin);
5183 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
5184 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
5185 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
5187 light->color[0] = max(color[0], 0);
5188 light->color[1] = max(color[1], 0);
5189 light->color[2] = max(color[2], 0);
5191 light->color[0] = color[0];
5192 light->color[1] = color[1];
5193 light->color[2] = color[2];
5194 light->radius = max(radius, 0);
5195 light->style = style;
5196 light->shadow = shadowenable;
5197 light->corona = corona;
5198 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
5199 light->coronasizescale = coronasizescale;
5200 light->ambientscale = ambientscale;
5201 light->diffusescale = diffusescale;
5202 light->specularscale = specularscale;
5203 light->flags = flags;
5205 // update renderable light data
5206 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
5207 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);
5210 void R_Shadow_FreeWorldLight(dlight_t *light)
5212 if (r_shadow_selectedlight == light)
5213 r_shadow_selectedlight = NULL;
5214 R_RTLight_Uncompile(&light->rtlight);
5215 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
5218 void R_Shadow_ClearWorldLights(void)
5222 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5223 for (lightindex = 0;lightindex < range;lightindex++)
5225 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5227 R_Shadow_FreeWorldLight(light);
5229 r_shadow_selectedlight = NULL;
5232 void R_Shadow_SelectLight(dlight_t *light)
5234 if (r_shadow_selectedlight)
5235 r_shadow_selectedlight->selected = false;
5236 r_shadow_selectedlight = light;
5237 if (r_shadow_selectedlight)
5238 r_shadow_selectedlight->selected = true;
5241 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
5243 // this is never batched (there can be only one)
5245 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
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_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5250 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
5255 skinframe_t *skinframe;
5258 // this is never batched (due to the ent parameter changing every time)
5259 // so numsurfaces == 1 and surfacelist[0] == lightnumber
5260 const dlight_t *light = (dlight_t *)ent;
5263 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
5266 VectorScale(light->color, intensity, spritecolor);
5267 if (VectorLength(spritecolor) < 0.1732f)
5268 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
5269 if (VectorLength(spritecolor) > 1.0f)
5270 VectorNormalize(spritecolor);
5272 // draw light sprite
5273 if (light->cubemapname[0] && !light->shadow)
5274 skinframe = r_editlights_sprcubemapnoshadowlight;
5275 else if (light->cubemapname[0])
5276 skinframe = r_editlights_sprcubemaplight;
5277 else if (!light->shadow)
5278 skinframe = r_editlights_sprnoshadowlight;
5280 skinframe = r_editlights_sprlight;
5282 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);
5283 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5285 // draw selection sprite if light is selected
5286 if (light->selected)
5288 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
5289 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5290 // VorteX todo: add normalmode/realtime mode light overlay sprites?
5294 void R_Shadow_DrawLightSprites(void)
5298 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5299 for (lightindex = 0;lightindex < range;lightindex++)
5301 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5303 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
5305 if (!r_editlights_lockcursor)
5306 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
5309 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
5314 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
5315 if (lightindex >= range)
5317 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5320 rtlight = &light->rtlight;
5321 //if (!(rtlight->flags & flag))
5323 VectorCopy(rtlight->shadoworigin, origin);
5324 *radius = rtlight->radius;
5325 VectorCopy(rtlight->color, color);
5329 void R_Shadow_SelectLightInView(void)
5331 float bestrating, rating, temp[3];
5335 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5339 if (r_editlights_lockcursor)
5341 for (lightindex = 0;lightindex < range;lightindex++)
5343 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5346 VectorSubtract(light->origin, r_refdef.view.origin, temp);
5347 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
5350 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
5351 if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false, true).fraction == 1.0f)
5353 bestrating = rating;
5358 R_Shadow_SelectLight(best);
5361 void R_Shadow_LoadWorldLights(void)
5363 int n, a, style, shadow, flags;
5364 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
5365 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
5366 if (cl.worldmodel == NULL)
5368 Con_Print("No map loaded.\n");
5371 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
5372 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5382 for (;COM_Parse(t, true) && strcmp(
5383 if (COM_Parse(t, true))
5385 if (com_token[0] == '!')
5388 origin[0] = atof(com_token+1);
5391 origin[0] = atof(com_token);
5396 while (*s && *s != '\n' && *s != '\r')
5402 // check for modifier flags
5409 #if _MSC_VER >= 1400
5410 #define sscanf sscanf_s
5412 cubemapname[sizeof(cubemapname)-1] = 0;
5413 #if MAX_QPATH != 128
5414 #error update this code if MAX_QPATH changes
5416 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
5417 #if _MSC_VER >= 1400
5418 , sizeof(cubemapname)
5420 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
5423 flags = LIGHTFLAG_REALTIMEMODE;
5431 coronasizescale = 0.25f;
5433 VectorClear(angles);
5436 if (a < 9 || !strcmp(cubemapname, "\"\""))
5438 // remove quotes on cubemapname
5439 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
5442 namelen = strlen(cubemapname) - 2;
5443 memmove(cubemapname, cubemapname + 1, namelen);
5444 cubemapname[namelen] = '\0';
5448 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);
5451 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5459 Con_Printf("invalid rtlights file \"%s\"\n", name);
5460 Mem_Free(lightsstring);
5464 void R_Shadow_SaveWorldLights(void)
5468 size_t bufchars, bufmaxchars;
5470 char name[MAX_QPATH];
5471 char line[MAX_INPUTLINE];
5472 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
5473 // I hate lines which are 3 times my screen size :( --blub
5476 if (cl.worldmodel == NULL)
5478 Con_Print("No map loaded.\n");
5481 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
5482 bufchars = bufmaxchars = 0;
5484 for (lightindex = 0;lightindex < range;lightindex++)
5486 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5489 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
5490 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);
5491 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
5492 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]);
5494 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);
5495 if (bufchars + strlen(line) > bufmaxchars)
5497 bufmaxchars = bufchars + strlen(line) + 2048;
5499 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
5503 memcpy(buf, oldbuf, bufchars);
5509 memcpy(buf + bufchars, line, strlen(line));
5510 bufchars += strlen(line);
5514 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
5519 void R_Shadow_LoadLightsFile(void)
5522 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
5523 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
5524 if (cl.worldmodel == NULL)
5526 Con_Print("No map loaded.\n");
5529 dpsnprintf(name, sizeof(name), "%s.lights", cl.worldnamenoextension);
5530 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5538 while (*s && *s != '\n' && *s != '\r')
5544 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);
5548 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);
5551 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
5552 radius = bound(15, radius, 4096);
5553 VectorScale(color, (2.0f / (8388608.0f)), color);
5554 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5562 Con_Printf("invalid lights file \"%s\"\n", name);
5563 Mem_Free(lightsstring);
5567 // tyrlite/hmap2 light types in the delay field
5568 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
5570 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
5582 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
5583 char key[256], value[MAX_INPUTLINE];
5585 if (cl.worldmodel == NULL)
5587 Con_Print("No map loaded.\n");
5590 // try to load a .ent file first
5591 dpsnprintf(key, sizeof(key), "%s.ent", cl.worldnamenoextension);
5592 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
5593 // and if that is not found, fall back to the bsp file entity string
5595 data = cl.worldmodel->brush.entities;
5598 for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
5600 type = LIGHTTYPE_MINUSX;
5601 origin[0] = origin[1] = origin[2] = 0;
5602 originhack[0] = originhack[1] = originhack[2] = 0;
5603 angles[0] = angles[1] = angles[2] = 0;
5604 color[0] = color[1] = color[2] = 1;
5605 light[0] = light[1] = light[2] = 1;light[3] = 300;
5606 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
5616 if (!COM_ParseToken_Simple(&data, false, false))
5618 if (com_token[0] == '}')
5619 break; // end of entity
5620 if (com_token[0] == '_')
5621 strlcpy(key, com_token + 1, sizeof(key));
5623 strlcpy(key, com_token, sizeof(key));
5624 while (key[strlen(key)-1] == ' ') // remove trailing spaces
5625 key[strlen(key)-1] = 0;
5626 if (!COM_ParseToken_Simple(&data, false, false))
5628 strlcpy(value, com_token, sizeof(value));
5630 // now that we have the key pair worked out...
5631 if (!strcmp("light", key))
5633 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5637 light[0] = vec[0] * (1.0f / 256.0f);
5638 light[1] = vec[0] * (1.0f / 256.0f);
5639 light[2] = vec[0] * (1.0f / 256.0f);
5645 light[0] = vec[0] * (1.0f / 255.0f);
5646 light[1] = vec[1] * (1.0f / 255.0f);
5647 light[2] = vec[2] * (1.0f / 255.0f);
5651 else if (!strcmp("delay", key))
5653 else if (!strcmp("origin", key))
5654 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5655 else if (!strcmp("angle", key))
5656 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5657 else if (!strcmp("angles", key))
5658 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5659 else if (!strcmp("color", key))
5660 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5661 else if (!strcmp("wait", key))
5662 fadescale = atof(value);
5663 else if (!strcmp("classname", key))
5665 if (!strncmp(value, "light", 5))
5668 if (!strcmp(value, "light_fluoro"))
5673 overridecolor[0] = 1;
5674 overridecolor[1] = 1;
5675 overridecolor[2] = 1;
5677 if (!strcmp(value, "light_fluorospark"))
5682 overridecolor[0] = 1;
5683 overridecolor[1] = 1;
5684 overridecolor[2] = 1;
5686 if (!strcmp(value, "light_globe"))
5691 overridecolor[0] = 1;
5692 overridecolor[1] = 0.8;
5693 overridecolor[2] = 0.4;
5695 if (!strcmp(value, "light_flame_large_yellow"))
5700 overridecolor[0] = 1;
5701 overridecolor[1] = 0.5;
5702 overridecolor[2] = 0.1;
5704 if (!strcmp(value, "light_flame_small_yellow"))
5709 overridecolor[0] = 1;
5710 overridecolor[1] = 0.5;
5711 overridecolor[2] = 0.1;
5713 if (!strcmp(value, "light_torch_small_white"))
5718 overridecolor[0] = 1;
5719 overridecolor[1] = 0.5;
5720 overridecolor[2] = 0.1;
5722 if (!strcmp(value, "light_torch_small_walltorch"))
5727 overridecolor[0] = 1;
5728 overridecolor[1] = 0.5;
5729 overridecolor[2] = 0.1;
5733 else if (!strcmp("style", key))
5734 style = atoi(value);
5735 else if (!strcmp("skin", key))
5736 skin = (int)atof(value);
5737 else if (!strcmp("pflags", key))
5738 pflags = (int)atof(value);
5739 //else if (!strcmp("effects", key))
5740 // effects = (int)atof(value);
5741 else if (cl.worldmodel->type == mod_brushq3)
5743 if (!strcmp("scale", key))
5744 lightscale = atof(value);
5745 if (!strcmp("fade", key))
5746 fadescale = atof(value);
5751 if (lightscale <= 0)
5755 if (color[0] == color[1] && color[0] == color[2])
5757 color[0] *= overridecolor[0];
5758 color[1] *= overridecolor[1];
5759 color[2] *= overridecolor[2];
5761 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5762 color[0] = color[0] * light[0];
5763 color[1] = color[1] * light[1];
5764 color[2] = color[2] * light[2];
5767 case LIGHTTYPE_MINUSX:
5769 case LIGHTTYPE_RECIPX:
5771 VectorScale(color, (1.0f / 16.0f), color);
5773 case LIGHTTYPE_RECIPXX:
5775 VectorScale(color, (1.0f / 16.0f), color);
5778 case LIGHTTYPE_NONE:
5782 case LIGHTTYPE_MINUSXX:
5785 VectorAdd(origin, originhack, origin);
5787 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);
5790 Mem_Free(entfiledata);
5794 void R_Shadow_SetCursorLocationForView(void)
5797 vec3_t dest, endpos;
5799 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5800 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false, true);
5801 if (trace.fraction < 1)
5803 dist = trace.fraction * r_editlights_cursordistance.value;
5804 push = r_editlights_cursorpushback.value;
5808 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5809 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5813 VectorClear( endpos );
5815 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5816 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5817 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5820 void R_Shadow_UpdateWorldLightSelection(void)
5822 if (r_editlights.integer)
5824 R_Shadow_SetCursorLocationForView();
5825 R_Shadow_SelectLightInView();
5828 R_Shadow_SelectLight(NULL);
5831 void R_Shadow_EditLights_Clear_f(void)
5833 R_Shadow_ClearWorldLights();
5836 void R_Shadow_EditLights_Reload_f(void)
5840 strlcpy(r_shadow_mapname, cl.worldname, sizeof(r_shadow_mapname));
5841 R_Shadow_ClearWorldLights();
5842 R_Shadow_LoadWorldLights();
5843 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5845 R_Shadow_LoadLightsFile();
5846 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5847 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5851 void R_Shadow_EditLights_Save_f(void)
5855 R_Shadow_SaveWorldLights();
5858 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
5860 R_Shadow_ClearWorldLights();
5861 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5864 void R_Shadow_EditLights_ImportLightsFile_f(void)
5866 R_Shadow_ClearWorldLights();
5867 R_Shadow_LoadLightsFile();
5870 void R_Shadow_EditLights_Spawn_f(void)
5873 if (!r_editlights.integer)
5875 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5878 if (Cmd_Argc() != 1)
5880 Con_Print("r_editlights_spawn does not take parameters\n");
5883 color[0] = color[1] = color[2] = 1;
5884 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5887 void R_Shadow_EditLights_Edit_f(void)
5889 vec3_t origin, angles, color;
5890 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5891 int style, shadows, flags, normalmode, realtimemode;
5892 char cubemapname[MAX_INPUTLINE];
5893 if (!r_editlights.integer)
5895 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5898 if (!r_shadow_selectedlight)
5900 Con_Print("No selected light.\n");
5903 VectorCopy(r_shadow_selectedlight->origin, origin);
5904 VectorCopy(r_shadow_selectedlight->angles, angles);
5905 VectorCopy(r_shadow_selectedlight->color, color);
5906 radius = r_shadow_selectedlight->radius;
5907 style = r_shadow_selectedlight->style;
5908 if (r_shadow_selectedlight->cubemapname)
5909 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5912 shadows = r_shadow_selectedlight->shadow;
5913 corona = r_shadow_selectedlight->corona;
5914 coronasizescale = r_shadow_selectedlight->coronasizescale;
5915 ambientscale = r_shadow_selectedlight->ambientscale;
5916 diffusescale = r_shadow_selectedlight->diffusescale;
5917 specularscale = r_shadow_selectedlight->specularscale;
5918 flags = r_shadow_selectedlight->flags;
5919 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5920 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5921 if (!strcmp(Cmd_Argv(1), "origin"))
5923 if (Cmd_Argc() != 5)
5925 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5928 origin[0] = atof(Cmd_Argv(2));
5929 origin[1] = atof(Cmd_Argv(3));
5930 origin[2] = atof(Cmd_Argv(4));
5932 else if (!strcmp(Cmd_Argv(1), "originx"))
5934 if (Cmd_Argc() != 3)
5936 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5939 origin[0] = atof(Cmd_Argv(2));
5941 else if (!strcmp(Cmd_Argv(1), "originy"))
5943 if (Cmd_Argc() != 3)
5945 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5948 origin[1] = atof(Cmd_Argv(2));
5950 else if (!strcmp(Cmd_Argv(1), "originz"))
5952 if (Cmd_Argc() != 3)
5954 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5957 origin[2] = atof(Cmd_Argv(2));
5959 else if (!strcmp(Cmd_Argv(1), "move"))
5961 if (Cmd_Argc() != 5)
5963 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5966 origin[0] += atof(Cmd_Argv(2));
5967 origin[1] += atof(Cmd_Argv(3));
5968 origin[2] += atof(Cmd_Argv(4));
5970 else if (!strcmp(Cmd_Argv(1), "movex"))
5972 if (Cmd_Argc() != 3)
5974 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5977 origin[0] += atof(Cmd_Argv(2));
5979 else if (!strcmp(Cmd_Argv(1), "movey"))
5981 if (Cmd_Argc() != 3)
5983 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5986 origin[1] += atof(Cmd_Argv(2));
5988 else if (!strcmp(Cmd_Argv(1), "movez"))
5990 if (Cmd_Argc() != 3)
5992 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5995 origin[2] += atof(Cmd_Argv(2));
5997 else if (!strcmp(Cmd_Argv(1), "angles"))
5999 if (Cmd_Argc() != 5)
6001 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6004 angles[0] = atof(Cmd_Argv(2));
6005 angles[1] = atof(Cmd_Argv(3));
6006 angles[2] = atof(Cmd_Argv(4));
6008 else if (!strcmp(Cmd_Argv(1), "anglesx"))
6010 if (Cmd_Argc() != 3)
6012 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6015 angles[0] = atof(Cmd_Argv(2));
6017 else if (!strcmp(Cmd_Argv(1), "anglesy"))
6019 if (Cmd_Argc() != 3)
6021 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6024 angles[1] = atof(Cmd_Argv(2));
6026 else if (!strcmp(Cmd_Argv(1), "anglesz"))
6028 if (Cmd_Argc() != 3)
6030 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6033 angles[2] = atof(Cmd_Argv(2));
6035 else if (!strcmp(Cmd_Argv(1), "color"))
6037 if (Cmd_Argc() != 5)
6039 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
6042 color[0] = atof(Cmd_Argv(2));
6043 color[1] = atof(Cmd_Argv(3));
6044 color[2] = atof(Cmd_Argv(4));
6046 else if (!strcmp(Cmd_Argv(1), "radius"))
6048 if (Cmd_Argc() != 3)
6050 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6053 radius = atof(Cmd_Argv(2));
6055 else if (!strcmp(Cmd_Argv(1), "colorscale"))
6057 if (Cmd_Argc() == 3)
6059 double scale = atof(Cmd_Argv(2));
6066 if (Cmd_Argc() != 5)
6068 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
6071 color[0] *= atof(Cmd_Argv(2));
6072 color[1] *= atof(Cmd_Argv(3));
6073 color[2] *= atof(Cmd_Argv(4));
6076 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
6078 if (Cmd_Argc() != 3)
6080 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6083 radius *= atof(Cmd_Argv(2));
6085 else if (!strcmp(Cmd_Argv(1), "style"))
6087 if (Cmd_Argc() != 3)
6089 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6092 style = atoi(Cmd_Argv(2));
6094 else if (!strcmp(Cmd_Argv(1), "cubemap"))
6098 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6101 if (Cmd_Argc() == 3)
6102 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
6106 else if (!strcmp(Cmd_Argv(1), "shadows"))
6108 if (Cmd_Argc() != 3)
6110 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6113 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
6115 else if (!strcmp(Cmd_Argv(1), "corona"))
6117 if (Cmd_Argc() != 3)
6119 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6122 corona = atof(Cmd_Argv(2));
6124 else if (!strcmp(Cmd_Argv(1), "coronasize"))
6126 if (Cmd_Argc() != 3)
6128 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6131 coronasizescale = atof(Cmd_Argv(2));
6133 else if (!strcmp(Cmd_Argv(1), "ambient"))
6135 if (Cmd_Argc() != 3)
6137 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6140 ambientscale = atof(Cmd_Argv(2));
6142 else if (!strcmp(Cmd_Argv(1), "diffuse"))
6144 if (Cmd_Argc() != 3)
6146 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6149 diffusescale = atof(Cmd_Argv(2));
6151 else if (!strcmp(Cmd_Argv(1), "specular"))
6153 if (Cmd_Argc() != 3)
6155 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6158 specularscale = atof(Cmd_Argv(2));
6160 else if (!strcmp(Cmd_Argv(1), "normalmode"))
6162 if (Cmd_Argc() != 3)
6164 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6167 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
6169 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
6171 if (Cmd_Argc() != 3)
6173 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6176 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
6180 Con_Print("usage: r_editlights_edit [property] [value]\n");
6181 Con_Print("Selected light's properties:\n");
6182 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
6183 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
6184 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
6185 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
6186 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
6187 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
6188 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
6189 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
6190 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
6191 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
6192 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
6193 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
6194 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
6195 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
6198 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
6199 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
6202 void R_Shadow_EditLights_EditAll_f(void)
6205 dlight_t *light, *oldselected;
6208 if (!r_editlights.integer)
6210 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
6214 oldselected = r_shadow_selectedlight;
6215 // EditLights doesn't seem to have a "remove" command or something so:
6216 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6217 for (lightindex = 0;lightindex < range;lightindex++)
6219 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6222 R_Shadow_SelectLight(light);
6223 R_Shadow_EditLights_Edit_f();
6225 // return to old selected (to not mess editing once selection is locked)
6226 R_Shadow_SelectLight(oldselected);
6229 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
6231 int lightnumber, lightcount;
6232 size_t lightindex, range;
6236 if (!r_editlights.integer)
6238 x = vid_conwidth.value - 240;
6240 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
6243 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6244 for (lightindex = 0;lightindex < range;lightindex++)
6246 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6249 if (light == r_shadow_selectedlight)
6250 lightnumber = lightindex;
6253 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;
6254 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;
6256 if (r_shadow_selectedlight == NULL)
6258 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;
6259 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;
6260 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;
6261 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;
6262 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;
6263 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;
6264 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;
6265 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;
6266 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;
6267 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;
6268 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;
6269 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;
6270 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;
6271 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;
6272 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;
6275 void R_Shadow_EditLights_ToggleShadow_f(void)
6277 if (!r_editlights.integer)
6279 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6282 if (!r_shadow_selectedlight)
6284 Con_Print("No selected light.\n");
6287 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);
6290 void R_Shadow_EditLights_ToggleCorona_f(void)
6292 if (!r_editlights.integer)
6294 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6297 if (!r_shadow_selectedlight)
6299 Con_Print("No selected light.\n");
6302 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);
6305 void R_Shadow_EditLights_Remove_f(void)
6307 if (!r_editlights.integer)
6309 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
6312 if (!r_shadow_selectedlight)
6314 Con_Print("No selected light.\n");
6317 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
6318 r_shadow_selectedlight = NULL;
6321 void R_Shadow_EditLights_Help_f(void)
6324 "Documentation on r_editlights system:\n"
6326 "r_editlights : enable/disable editing mode\n"
6327 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
6328 "r_editlights_cursorpushback : push back cursor this far from surface\n"
6329 "r_editlights_cursorpushoff : push cursor off surface this far\n"
6330 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
6331 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
6333 "r_editlights_help : this help\n"
6334 "r_editlights_clear : remove all lights\n"
6335 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
6336 "r_editlights_lock : lock selection to current light, if already locked - unlock\n"
6337 "r_editlights_save : save to .rtlights file\n"
6338 "r_editlights_spawn : create a light with default settings\n"
6339 "r_editlights_edit command : edit selected light - more documentation below\n"
6340 "r_editlights_remove : remove selected light\n"
6341 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
6342 "r_editlights_importlightentitiesfrommap : reload light entities\n"
6343 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
6345 "origin x y z : set light location\n"
6346 "originx x: set x component of light location\n"
6347 "originy y: set y component of light location\n"
6348 "originz z: set z component of light location\n"
6349 "move x y z : adjust light location\n"
6350 "movex x: adjust x component of light location\n"
6351 "movey y: adjust y component of light location\n"
6352 "movez z: adjust z component of light location\n"
6353 "angles x y z : set light angles\n"
6354 "anglesx x: set x component of light angles\n"
6355 "anglesy y: set y component of light angles\n"
6356 "anglesz z: set z component of light angles\n"
6357 "color r g b : set color of light (can be brighter than 1 1 1)\n"
6358 "radius radius : set radius (size) of light\n"
6359 "colorscale grey : multiply color of light (1 does nothing)\n"
6360 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
6361 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
6362 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
6363 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
6364 "cubemap basename : set filter cubemap of light (not yet supported)\n"
6365 "shadows 1/0 : turn on/off shadows\n"
6366 "corona n : set corona intensity\n"
6367 "coronasize n : set corona size (0-1)\n"
6368 "ambient n : set ambient intensity (0-1)\n"
6369 "diffuse n : set diffuse intensity (0-1)\n"
6370 "specular n : set specular intensity (0-1)\n"
6371 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
6372 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
6373 "<nothing> : print light properties to console\n"
6377 void R_Shadow_EditLights_CopyInfo_f(void)
6379 if (!r_editlights.integer)
6381 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
6384 if (!r_shadow_selectedlight)
6386 Con_Print("No selected light.\n");
6389 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
6390 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
6391 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
6392 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
6393 if (r_shadow_selectedlight->cubemapname)
6394 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
6396 r_shadow_bufferlight.cubemapname[0] = 0;
6397 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
6398 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
6399 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
6400 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
6401 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
6402 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
6403 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
6406 void R_Shadow_EditLights_PasteInfo_f(void)
6408 if (!r_editlights.integer)
6410 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
6413 if (!r_shadow_selectedlight)
6415 Con_Print("No selected light.\n");
6418 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);
6421 void R_Shadow_EditLights_Lock_f(void)
6423 if (!r_editlights.integer)
6425 Con_Print("Cannot lock on light when not in editing mode. Set r_editlights to 1.\n");
6428 if (r_editlights_lockcursor)
6430 r_editlights_lockcursor = false;
6433 if (!r_shadow_selectedlight)
6435 Con_Print("No selected light to lock on.\n");
6438 r_editlights_lockcursor = true;
6441 void R_Shadow_EditLights_Init(void)
6443 Cvar_RegisterVariable(&r_editlights);
6444 Cvar_RegisterVariable(&r_editlights_cursordistance);
6445 Cvar_RegisterVariable(&r_editlights_cursorpushback);
6446 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
6447 Cvar_RegisterVariable(&r_editlights_cursorgrid);
6448 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
6449 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
6450 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
6451 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)");
6452 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
6453 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
6454 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
6455 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)");
6456 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
6457 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
6458 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
6459 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
6460 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
6461 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
6462 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)");
6463 Cmd_AddCommand("r_editlights_lock", R_Shadow_EditLights_Lock_f, "lock selection to current light, if already locked - unlock");
6469 =============================================================================
6473 =============================================================================
6476 void R_CompleteLightPoint(vec3_t ambient, vec3_t diffuse, vec3_t lightdir, const vec3_t p, const int flags)
6478 int i, numlights, flag;
6481 float relativepoint[3];
6490 if (r_fullbright.integer)
6492 VectorSet(ambient, 1, 1, 1);
6493 VectorClear(diffuse);
6494 VectorClear(lightdir);
6498 if (flags & LP_LIGHTMAP)
6500 VectorSet(ambient, r_refdef.scene.ambient, r_refdef.scene.ambient, r_refdef.scene.ambient);
6501 VectorClear(diffuse);
6502 VectorClear(lightdir);
6503 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
6504 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambient, diffuse, lightdir);
6508 memset(sample, 0, sizeof(sample));
6509 VectorSet(sample, r_refdef.scene.ambient, r_refdef.scene.ambient, r_refdef.scene.ambient);
6511 if ((flags & LP_LIGHTMAP) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
6514 VectorClear(tempambient);
6516 VectorClear(relativepoint);
6517 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, tempambient, color, relativepoint);
6518 VectorScale(tempambient, r_refdef.lightmapintensity, tempambient);
6519 VectorScale(color, r_refdef.lightmapintensity, color);
6520 VectorAdd(sample, tempambient, sample);
6521 VectorMA(sample , 0.5f , color, sample );
6522 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
6523 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
6524 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
6525 // calculate a weighted average light direction as well
6526 intensity = VectorLength(color);
6527 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
6530 if (flags & LP_RTWORLD)
6532 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
6533 numlights = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
6534 for (i = 0; i < numlights; i++)
6536 dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
6539 light = &dlight->rtlight;
6540 if (!(light->flags & flag))
6543 lightradius2 = light->radius * light->radius;
6544 VectorSubtract(light->shadoworigin, p, relativepoint);
6545 dist2 = VectorLength2(relativepoint);
6546 if (dist2 >= lightradius2)
6548 dist = sqrt(dist2) / light->radius;
6549 intensity = min(1.0f, (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) * r_shadow_lightintensityscale.value;
6550 if (intensity <= 0.0f)
6552 if (light->shadow && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false, true).fraction < 1)
6554 // scale down intensity to add to both ambient and diffuse
6555 //intensity *= 0.5f;
6556 VectorNormalize(relativepoint);
6557 VectorScale(light->currentcolor, intensity, color);
6558 VectorMA(sample , 0.5f , color, sample );
6559 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
6560 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
6561 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
6562 // calculate a weighted average light direction as well
6563 intensity *= VectorLength(color);
6564 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
6568 if (flags & LP_DYNLIGHT)
6571 for (i = 0;i < r_refdef.scene.numlights;i++)
6573 light = r_refdef.scene.lights[i];
6575 lightradius2 = light->radius * light->radius;
6576 VectorSubtract(light->shadoworigin, p, relativepoint);
6577 dist2 = VectorLength2(relativepoint);
6578 if (dist2 >= lightradius2)
6580 dist = sqrt(dist2) / light->radius;
6581 intensity = (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist) * r_shadow_lightintensityscale.value;
6582 if (intensity <= 0.0f)
6584 if (light->shadow && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false, true).fraction < 1)
6586 // scale down intensity to add to both ambient and diffuse
6587 //intensity *= 0.5f;
6588 VectorNormalize(relativepoint);
6589 VectorScale(light->currentcolor, intensity, color);
6590 VectorMA(sample , 0.5f , color, sample );
6591 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
6592 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
6593 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
6594 // calculate a weighted average light direction as well
6595 intensity *= VectorLength(color);
6596 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
6600 // calculate the direction we'll use to reduce the sample to a directional light source
6601 VectorCopy(sample + 12, dir);
6602 //VectorSet(dir, sample[3] + sample[4] + sample[5], sample[6] + sample[7] + sample[8], sample[9] + sample[10] + sample[11]);
6603 VectorNormalize(dir);
6604 // extract the diffuse color along the chosen direction and scale it
6605 diffuse[0] = (dir[0]*sample[3] + dir[1]*sample[6] + dir[2]*sample[ 9] + sample[ 0]);
6606 diffuse[1] = (dir[0]*sample[4] + dir[1]*sample[7] + dir[2]*sample[10] + sample[ 1]);
6607 diffuse[2] = (dir[0]*sample[5] + dir[1]*sample[8] + dir[2]*sample[11] + sample[ 2]);
6608 // subtract some of diffuse from ambient
6609 VectorMA(sample, -0.333f, diffuse, ambient);
6610 // store the normalized lightdir
6611 VectorCopy(dir, lightdir);