3 Terminology: Stencil Shadow Volume (sometimes called Stencil Shadows)
4 An extrusion of the lit faces, beginning at the original geometry and ending
5 further from the light source than the original geometry (presumably at least
6 as far as the light's radius, if the light has a radius at all), capped at
7 both front and back to avoid any problems (extrusion from dark faces also
8 works but has a different set of problems)
10 This is normally rendered using Carmack's Reverse technique, in which
11 backfaces behind zbuffer (zfail) increment the stencil, and frontfaces behind
12 zbuffer (zfail) decrement the stencil, the result is a stencil value of zero
13 where shadows did not intersect the visible geometry, suitable as a stencil
14 mask for rendering lighting everywhere but shadow.
16 In our case to hopefully avoid the Creative Labs patent, we draw the backfaces
17 as decrement and the frontfaces as increment, and we redefine the DepthFunc to
18 GL_LESS (the patent uses GL_GEQUAL) which causes zfail when behind surfaces
19 and zpass when infront (the patent draws where zpass with a GL_GEQUAL test),
20 additionally we clear stencil to 128 to avoid the need for the unclamped
21 incr/decr extension (not related to patent).
24 This algorithm may be covered by Creative's patent (US Patent #6384822),
25 however that patent is quite specific about increment on backfaces and
26 decrement on frontfaces where zpass with GL_GEQUAL depth test, which is
27 opposite this implementation and partially opposite Carmack's Reverse paper
28 (which uses GL_LESS, but increments on backfaces and decrements on frontfaces).
32 Terminology: Stencil Light Volume (sometimes called Light Volumes)
33 Similar to a Stencil Shadow Volume, but inverted; rather than containing the
34 areas in shadow it contains the areas in light, this can only be built
35 quickly for certain limited cases (such as portal visibility from a point),
36 but is quite useful for some effects (sunlight coming from sky polygons is
37 one possible example, translucent occluders is another example).
41 Terminology: Optimized Stencil Shadow Volume
42 A Stencil Shadow Volume that has been processed sufficiently to ensure it has
43 no duplicate coverage of areas (no need to shadow an area twice), often this
44 greatly improves performance but is an operation too costly to use on moving
45 lights (however completely optimal Stencil Light Volumes can be constructed
50 Terminology: Per Pixel Lighting (sometimes abbreviated PPL)
51 Per pixel evaluation of lighting equations, at a bare minimum this involves
52 DOT3 shading of diffuse lighting (per pixel dotproduct of negated incidence
53 vector and surface normal, using a texture of the surface bumps, called a
54 NormalMap) if supported by hardware; in our case there is support for cards
55 which are incapable of DOT3, the quality is quite poor however. Additionally
56 it is desirable to have specular evaluation per pixel, per vertex
57 normalization of specular halfangle vectors causes noticable distortion but
58 is unavoidable on hardware without GL_ARB_fragment_program or
59 GL_ARB_fragment_shader.
63 Terminology: Normalization CubeMap
64 A cubemap containing normalized dot3-encoded (vectors of length 1 or less
65 encoded as RGB colors) for any possible direction, this technique allows per
66 pixel calculation of incidence vector for per pixel lighting purposes, which
67 would not otherwise be possible per pixel without GL_ARB_fragment_program or
68 GL_ARB_fragment_shader.
72 Terminology: 2D+1D Attenuation Texturing
73 A very crude approximation of light attenuation with distance which results
74 in cylindrical light shapes which fade vertically as a streak (some games
75 such as Doom3 allow this to be rotated to be less noticable in specific
76 cases), the technique is simply modulating lighting by two 2D textures (which
77 can be the same) on different axes of projection (XY and Z, typically), this
78 is the second best technique available without 3D Attenuation Texturing,
79 GL_ARB_fragment_program or GL_ARB_fragment_shader technology.
83 Terminology: 2D+1D Inverse Attenuation Texturing
84 A clever method described in papers on the Abducted engine, this has a squared
85 distance texture (bright on the outside, black in the middle), which is used
86 twice using GL_ADD blending, the result of this is used in an inverse modulate
87 (GL_ONE_MINUS_DST_ALPHA, GL_ZERO) to implement the equation
88 lighting*=(1-((X*X+Y*Y)+(Z*Z))) which is spherical (unlike 2D+1D attenuation
93 Terminology: 3D Attenuation Texturing
94 A slightly crude approximation of light attenuation with distance, its flaws
95 are limited radius and resolution (performance tradeoffs).
99 Terminology: 3D Attenuation-Normalization Texturing
100 A 3D Attenuation Texture merged with a Normalization CubeMap, by making the
101 vectors shorter the lighting becomes darker, a very effective optimization of
102 diffuse lighting if 3D Attenuation Textures are already used.
106 Terminology: Light Cubemap Filtering
107 A technique for modeling non-uniform light distribution according to
108 direction, for example a lantern may use a cubemap to describe the light
109 emission pattern of the cage around the lantern (as well as soot buildup
110 discoloring the light in certain areas), often also used for softened grate
111 shadows and light shining through a stained glass window (done crudely by
112 texturing the lighting with a cubemap), another good example would be a disco
113 light. This technique is used heavily in many games (Doom3 does not support
118 Terminology: Light Projection Filtering
119 A technique for modeling shadowing of light passing through translucent
120 surfaces, allowing stained glass windows and other effects to be done more
121 elegantly than possible with Light Cubemap Filtering by applying an occluder
122 texture to the lighting combined with a stencil light volume to limit the lit
123 area, this technique is used by Doom3 for spotlights and flashlights, among
124 other things, this can also be used more generally to render light passing
125 through multiple translucent occluders in a scene (using a light volume to
126 describe the area beyond the occluder, and thus mask off rendering of all
131 Terminology: Doom3 Lighting
132 A combination of Stencil Shadow Volume, Per Pixel Lighting, Normalization
133 CubeMap, 2D+1D Attenuation Texturing, and Light Projection Filtering, as
134 demonstrated by the game Doom3.
137 #include "quakedef.h"
138 #include "r_shadow.h"
139 #include "cl_collision.h"
142 #include "dpsoftrast.h"
146 extern LPDIRECT3DDEVICE9 vid_d3d9dev;
149 static void R_Shadow_EditLights_Init(void);
151 typedef enum r_shadow_rendermode_e
153 R_SHADOW_RENDERMODE_NONE,
154 R_SHADOW_RENDERMODE_ZPASS_STENCIL,
155 R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL,
156 R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE,
157 R_SHADOW_RENDERMODE_ZFAIL_STENCIL,
158 R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL,
159 R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE,
160 R_SHADOW_RENDERMODE_LIGHT_VERTEX,
161 R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN,
162 R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN,
163 R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN,
164 R_SHADOW_RENDERMODE_LIGHT_GLSL,
165 R_SHADOW_RENDERMODE_VISIBLEVOLUMES,
166 R_SHADOW_RENDERMODE_VISIBLELIGHTING,
167 R_SHADOW_RENDERMODE_SHADOWMAP2D
169 r_shadow_rendermode_t;
171 typedef enum r_shadow_shadowmode_e
173 R_SHADOW_SHADOWMODE_STENCIL,
174 R_SHADOW_SHADOWMODE_SHADOWMAP2D
176 r_shadow_shadowmode_t;
178 r_shadow_rendermode_t r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
179 r_shadow_rendermode_t r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_NONE;
180 r_shadow_rendermode_t r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_NONE;
181 r_shadow_rendermode_t r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_NONE;
182 qboolean r_shadow_usingshadowmap2d;
183 qboolean r_shadow_usingshadowmaportho;
184 int r_shadow_shadowmapside;
185 float r_shadow_shadowmap_texturescale[2];
186 float r_shadow_shadowmap_parameters[4];
188 int r_shadow_drawbuffer;
189 int r_shadow_readbuffer;
191 int r_shadow_cullface_front, r_shadow_cullface_back;
192 GLuint r_shadow_fbo2d;
193 r_shadow_shadowmode_t r_shadow_shadowmode;
194 int r_shadow_shadowmapfilterquality;
195 int r_shadow_shadowmapdepthbits;
196 int r_shadow_shadowmapmaxsize;
197 qboolean r_shadow_shadowmapvsdct;
198 qboolean r_shadow_shadowmapsampler;
199 qboolean r_shadow_shadowmapshadowsampler;
200 int r_shadow_shadowmappcf;
201 int r_shadow_shadowmapborder;
202 matrix4x4_t r_shadow_shadowmapmatrix;
203 int r_shadow_lightscissor[4];
204 qboolean r_shadow_usingdeferredprepass;
205 qboolean r_shadow_shadowmapdepthtexture;
206 int maxshadowtriangles;
209 int maxshadowvertices;
210 float *shadowvertex3f;
220 unsigned char *shadowsides;
221 int *shadowsideslist;
228 int r_shadow_buffer_numleafpvsbytes;
229 unsigned char *r_shadow_buffer_visitingleafpvs;
230 unsigned char *r_shadow_buffer_leafpvs;
231 int *r_shadow_buffer_leaflist;
233 int r_shadow_buffer_numsurfacepvsbytes;
234 unsigned char *r_shadow_buffer_surfacepvs;
235 int *r_shadow_buffer_surfacelist;
236 unsigned char *r_shadow_buffer_surfacesides;
238 int r_shadow_buffer_numshadowtrispvsbytes;
239 unsigned char *r_shadow_buffer_shadowtrispvs;
240 int r_shadow_buffer_numlighttrispvsbytes;
241 unsigned char *r_shadow_buffer_lighttrispvs;
243 rtexturepool_t *r_shadow_texturepool;
244 rtexture_t *r_shadow_attenuationgradienttexture;
245 rtexture_t *r_shadow_attenuation2dtexture;
246 rtexture_t *r_shadow_attenuation3dtexture;
247 skinframe_t *r_shadow_lightcorona;
248 rtexture_t *r_shadow_shadowmap2ddepthbuffer;
249 rtexture_t *r_shadow_shadowmap2ddepthtexture;
250 rtexture_t *r_shadow_shadowmapvsdcttexture;
251 int r_shadow_shadowmapsize; // changes for each light based on distance
252 int r_shadow_shadowmaplod; // changes for each light based on distance
254 GLuint r_shadow_prepassgeometryfbo;
255 GLuint r_shadow_prepasslightingdiffusespecularfbo;
256 GLuint r_shadow_prepasslightingdiffusefbo;
257 int r_shadow_prepass_width;
258 int r_shadow_prepass_height;
259 rtexture_t *r_shadow_prepassgeometrydepthbuffer;
260 rtexture_t *r_shadow_prepassgeometrynormalmaptexture;
261 rtexture_t *r_shadow_prepasslightingdiffusetexture;
262 rtexture_t *r_shadow_prepasslightingspeculartexture;
264 // keep track of the provided framebuffer info
265 static int r_shadow_fb_fbo;
266 static rtexture_t *r_shadow_fb_depthtexture;
267 static rtexture_t *r_shadow_fb_colortexture;
269 // lights are reloaded when this changes
270 char r_shadow_mapname[MAX_QPATH];
272 // buffer for doing corona fading
273 unsigned int r_shadow_occlusion_buf = 0;
275 // used only for light filters (cubemaps)
276 rtexturepool_t *r_shadow_filters_texturepool;
278 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"};
279 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"};
280 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
281 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"};
282 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)"};
283 cvar_t r_shadow_usenormalmap = {CVAR_SAVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"};
284 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)"};
285 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"};
286 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
287 cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
288 cvar_t r_shadow_gloss2exponent = {0, "r_shadow_gloss2exponent", "32", "same as r_shadow_glossexponent but for forced gloss (gloss 2) surfaces"};
289 cvar_t r_shadow_glossexact = {0, "r_shadow_glossexact", "0", "use exact reflection math for gloss (slightly slower, but should look a tad better)"};
290 cvar_t r_shadow_lightattenuationdividebias = {0, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"};
291 cvar_t r_shadow_lightattenuationlinearscale = {0, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"};
292 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
293 cvar_t r_shadow_lightradiusscale = {0, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
294 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "0", "how far to cast shadows"};
295 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)"};
296 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
297 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
298 cvar_t r_shadow_realtime_dlight_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
299 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
300 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)"};
301 cvar_t r_shadow_realtime_world_importlightentitiesfrommap = {0, "r_shadow_realtime_world_importlightentitiesfrommap", "1", "load lights from .ent file or map entities at startup if no .rtlights or .lights file is present (if set to 2, always use the .ent or map entities)"};
302 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"};
303 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
304 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
305 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"};
306 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)"};
307 cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "1", "enables portal-based culling optimization during compilation (overrides compilesvbsp)"};
308 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)"};
309 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"};
310 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)"};
311 cvar_t r_shadow_shadowmapping_useshadowsampler = {CVAR_SAVE, "r_shadow_shadowmapping_useshadowsampler", "1", "whether to use sampler2DShadow if available"};
312 cvar_t r_shadow_shadowmapping_depthbits = {CVAR_SAVE, "r_shadow_shadowmapping_depthbits", "24", "requested minimum shadowmap texture depth bits"};
313 cvar_t r_shadow_shadowmapping_vsdct = {CVAR_SAVE, "r_shadow_shadowmapping_vsdct", "1", "enables use of virtual shadow depth cube texture"};
314 cvar_t r_shadow_shadowmapping_minsize = {CVAR_SAVE, "r_shadow_shadowmapping_minsize", "32", "shadowmap size limit"};
315 cvar_t r_shadow_shadowmapping_maxsize = {CVAR_SAVE, "r_shadow_shadowmapping_maxsize", "512", "shadowmap size limit"};
316 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"};
317 //cvar_t r_shadow_shadowmapping_lod_bias = {CVAR_SAVE, "r_shadow_shadowmapping_lod_bias", "16", "shadowmap size bias"};
318 //cvar_t r_shadow_shadowmapping_lod_scale = {CVAR_SAVE, "r_shadow_shadowmapping_lod_scale", "128", "shadowmap size scaling parameter"};
319 cvar_t r_shadow_shadowmapping_bordersize = {CVAR_SAVE, "r_shadow_shadowmapping_bordersize", "4", "shadowmap size bias for filtering"};
320 cvar_t r_shadow_shadowmapping_nearclip = {CVAR_SAVE, "r_shadow_shadowmapping_nearclip", "1", "shadowmap nearclip in world units"};
321 cvar_t r_shadow_shadowmapping_bias = {CVAR_SAVE, "r_shadow_shadowmapping_bias", "0.03", "shadowmap bias parameter (this is multiplied by nearclip * 1024 / lodsize)"};
322 cvar_t r_shadow_shadowmapping_polygonfactor = {CVAR_SAVE, "r_shadow_shadowmapping_polygonfactor", "2", "slope-dependent shadowmapping bias"};
323 cvar_t r_shadow_shadowmapping_polygonoffset = {CVAR_SAVE, "r_shadow_shadowmapping_polygonoffset", "0", "constant shadowmapping bias"};
324 cvar_t r_shadow_sortsurfaces = {0, "r_shadow_sortsurfaces", "1", "improve performance by sorting illuminated surfaces by texture"};
325 cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
326 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)"};
327 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)"};
328 cvar_t r_shadow_bouncegrid = {CVAR_SAVE, "r_shadow_bouncegrid", "0", "perform particle tracing for indirect lighting (Global Illumination / radiosity) using a 3D texture covering the scene, only active on levels with realtime lights active (r_shadow_realtime_world is usually required for these)"};
329 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"};
330 cvar_t r_shadow_bouncegrid_directionalshading = {CVAR_SAVE, "r_shadow_bouncegrid_directionalshading", "0", "use diffuse shading rather than ambient, 3D texture becomes 8x as many pixels to hold the additional data"};
331 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"};
332 cvar_t r_shadow_bouncegrid_hitmodels = {CVAR_SAVE, "r_shadow_bouncegrid_hitmodels", "0", "enables hitting character model geometry (SLOW)"};
333 cvar_t r_shadow_bouncegrid_includedirectlighting = {CVAR_SAVE, "r_shadow_bouncegrid_includedirectlighting", "0", "allows direct lighting to be recorded, not just indirect (gives an effect somewhat like r_shadow_realtime_world_lightmaps)"};
334 cvar_t r_shadow_bouncegrid_intensity = {CVAR_SAVE, "r_shadow_bouncegrid_intensity", "4", "overall brightness of bouncegrid texture"};
335 cvar_t r_shadow_bouncegrid_lightradiusscale = {CVAR_SAVE, "r_shadow_bouncegrid_lightradiusscale", "4", "particles stop at this fraction of light radius (can be more than 1)"};
336 cvar_t r_shadow_bouncegrid_maxbounce = {CVAR_SAVE, "r_shadow_bouncegrid_maxbounce", "2", "maximum number of bounces for a particle (minimum is 0)"};
337 cvar_t r_shadow_bouncegrid_particlebounceintensity = {CVAR_SAVE, "r_shadow_bouncegrid_particlebounceintensity", "1", "amount of energy carried over after each bounce, this is a multiplier of texture color and the result is clamped to 1 or less, to prevent adding energy on each bounce"};
338 cvar_t r_shadow_bouncegrid_particleintensity = {CVAR_SAVE, "r_shadow_bouncegrid_particleintensity", "1", "brightness of particles contributing to bouncegrid texture"};
339 cvar_t r_shadow_bouncegrid_photons = {CVAR_SAVE, "r_shadow_bouncegrid_photons", "2000", "total photons to shoot per update, divided proportionately between lights"};
340 cvar_t r_shadow_bouncegrid_spacing = {CVAR_SAVE, "r_shadow_bouncegrid_spacing", "64", "unit size of bouncegrid pixel"};
341 cvar_t r_shadow_bouncegrid_stablerandom = {CVAR_SAVE, "r_shadow_bouncegrid_stablerandom", "1", "make particle distribution consistent from frame to frame"};
342 cvar_t r_shadow_bouncegrid_static = {CVAR_SAVE, "r_shadow_bouncegrid_static", "1", "use static radiosity solution (high quality) rather than dynamic (splotchy)"};
343 cvar_t r_shadow_bouncegrid_static_directionalshading = {CVAR_SAVE, "r_shadow_bouncegrid_static_directionalshading", "1", "whether to use directionalshading when in static mode"};
344 cvar_t r_shadow_bouncegrid_static_lightradiusscale = {CVAR_SAVE, "r_shadow_bouncegrid_static_lightradiusscale", "10", "particles stop at this fraction of light radius (can be more than 1) when in static mode"};
345 cvar_t r_shadow_bouncegrid_static_maxbounce = {CVAR_SAVE, "r_shadow_bouncegrid_static_maxbounce", "5", "maximum number of bounces for a particle (minimum is 0) in static mode"};
346 cvar_t r_shadow_bouncegrid_static_photons = {CVAR_SAVE, "r_shadow_bouncegrid_static_photons", "25000", "photons value to use when in static mode"};
347 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"};
348 cvar_t r_shadow_bouncegrid_x = {CVAR_SAVE, "r_shadow_bouncegrid_x", "64", "maximum texture size of bouncegrid on X axis"};
349 cvar_t r_shadow_bouncegrid_y = {CVAR_SAVE, "r_shadow_bouncegrid_y", "64", "maximum texture size of bouncegrid on Y axis"};
350 cvar_t r_shadow_bouncegrid_z = {CVAR_SAVE, "r_shadow_bouncegrid_z", "32", "maximum texture size of bouncegrid on Z axis"};
351 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "0", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
352 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"};
353 cvar_t r_coronas_occlusionquery = {CVAR_SAVE, "r_coronas_occlusionquery", "0", "use GL_ARB_occlusion_query extension if supported (fades coronas according to visibility) - bad performance (synchronous rendering) - worse on multi-gpu!"};
354 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
355 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
356 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
357 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
358 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
359 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
360 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
361 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
362 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
363 cvar_t r_editlights_drawproperties = {0, "r_editlights_drawproperties", "1", "draw properties of currently selected light"};
364 cvar_t r_editlights_current_origin = {0, "r_editlights_current_origin", "0 0 0", "origin of selected light"};
365 cvar_t r_editlights_current_angles = {0, "r_editlights_current_angles", "0 0 0", "angles of selected light"};
366 cvar_t r_editlights_current_color = {0, "r_editlights_current_color", "1 1 1", "color of selected light"};
367 cvar_t r_editlights_current_radius = {0, "r_editlights_current_radius", "0", "radius of selected light"};
368 cvar_t r_editlights_current_corona = {0, "r_editlights_current_corona", "0", "corona intensity of selected light"};
369 cvar_t r_editlights_current_coronasize = {0, "r_editlights_current_coronasize", "0", "corona size of selected light"};
370 cvar_t r_editlights_current_style = {0, "r_editlights_current_style", "0", "style of selected light"};
371 cvar_t r_editlights_current_shadows = {0, "r_editlights_current_shadows", "0", "shadows flag of selected light"};
372 cvar_t r_editlights_current_cubemap = {0, "r_editlights_current_cubemap", "0", "cubemap of selected light"};
373 cvar_t r_editlights_current_ambient = {0, "r_editlights_current_ambient", "0", "ambient intensity of selected light"};
374 cvar_t r_editlights_current_diffuse = {0, "r_editlights_current_diffuse", "1", "diffuse intensity of selected light"};
375 cvar_t r_editlights_current_specular = {0, "r_editlights_current_specular", "1", "specular intensity of selected light"};
376 cvar_t r_editlights_current_normalmode = {0, "r_editlights_current_normalmode", "0", "normalmode flag of selected light"};
377 cvar_t r_editlights_current_realtimemode = {0, "r_editlights_current_realtimemode", "0", "realtimemode flag of selected light"};
380 typedef struct r_shadow_bouncegrid_settings_s
383 qboolean bounceanglediffuse;
384 qboolean directionalshading;
385 qboolean includedirectlighting;
386 float dlightparticlemultiplier;
388 float lightradiusscale;
390 float particlebounceintensity;
391 float particleintensity;
396 r_shadow_bouncegrid_settings_t;
398 r_shadow_bouncegrid_settings_t r_shadow_bouncegridsettings;
399 rtexture_t *r_shadow_bouncegridtexture;
400 matrix4x4_t r_shadow_bouncegridmatrix;
401 vec_t r_shadow_bouncegridintensity;
402 qboolean r_shadow_bouncegriddirectional;
403 static double r_shadow_bouncegridtime;
404 static int r_shadow_bouncegridresolution[3];
405 static int r_shadow_bouncegridnumpixels;
406 static unsigned char *r_shadow_bouncegridpixels;
407 static float *r_shadow_bouncegridhighpixels;
409 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
410 #define ATTENTABLESIZE 256
411 // 1D gradient, 2D circle and 3D sphere attenuation textures
412 #define ATTEN1DSIZE 32
413 #define ATTEN2DSIZE 64
414 #define ATTEN3DSIZE 32
416 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
417 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
418 static float r_shadow_attentable[ATTENTABLESIZE+1];
420 rtlight_t *r_shadow_compilingrtlight;
421 static memexpandablearray_t r_shadow_worldlightsarray;
422 dlight_t *r_shadow_selectedlight;
423 dlight_t r_shadow_bufferlight;
424 vec3_t r_editlights_cursorlocation;
425 qboolean r_editlights_lockcursor;
427 extern int con_vislines;
429 void R_Shadow_UncompileWorldLights(void);
430 void R_Shadow_ClearWorldLights(void);
431 void R_Shadow_SaveWorldLights(void);
432 void R_Shadow_LoadWorldLights(void);
433 void R_Shadow_LoadLightsFile(void);
434 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
435 void R_Shadow_EditLights_Reload_f(void);
436 void R_Shadow_ValidateCvars(void);
437 static void R_Shadow_MakeTextures(void);
439 #define EDLIGHTSPRSIZE 8
440 skinframe_t *r_editlights_sprcursor;
441 skinframe_t *r_editlights_sprlight;
442 skinframe_t *r_editlights_sprnoshadowlight;
443 skinframe_t *r_editlights_sprcubemaplight;
444 skinframe_t *r_editlights_sprcubemapnoshadowlight;
445 skinframe_t *r_editlights_sprselection;
447 static void R_Shadow_SetShadowMode(void)
449 r_shadow_shadowmapmaxsize = bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4);
450 r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20;
451 r_shadow_shadowmapfilterquality = r_shadow_shadowmapping_filterquality.integer;
452 r_shadow_shadowmapshadowsampler = r_shadow_shadowmapping_useshadowsampler.integer != 0;
453 r_shadow_shadowmapdepthbits = r_shadow_shadowmapping_depthbits.integer;
454 r_shadow_shadowmapborder = bound(0, r_shadow_shadowmapping_bordersize.integer, 16);
455 r_shadow_shadowmaplod = -1;
456 r_shadow_shadowmapsize = 0;
457 r_shadow_shadowmapsampler = false;
458 r_shadow_shadowmappcf = 0;
459 r_shadow_shadowmapdepthtexture = r_fb.usedepthtextures;
460 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
461 if ((r_shadow_shadowmapping.integer || r_shadow_deferred.integer) && vid.support.ext_framebuffer_object)
463 switch(vid.renderpath)
465 case RENDERPATH_GL20:
466 if(r_shadow_shadowmapfilterquality < 0)
468 if (!r_fb.usedepthtextures)
469 r_shadow_shadowmappcf = 1;
470 else if((strstr(gl_vendor, "NVIDIA") || strstr(gl_renderer, "Radeon HD")) && vid.support.arb_shadow && r_shadow_shadowmapshadowsampler)
472 r_shadow_shadowmapsampler = true;
473 r_shadow_shadowmappcf = 1;
475 else if(vid.support.amd_texture_texture4 || vid.support.arb_texture_gather)
476 r_shadow_shadowmappcf = 1;
477 else if((strstr(gl_vendor, "ATI") || strstr(gl_vendor, "Advanced Micro Devices")) && !strstr(gl_renderer, "Mesa") && !strstr(gl_version, "Mesa"))
478 r_shadow_shadowmappcf = 1;
480 r_shadow_shadowmapsampler = vid.support.arb_shadow && r_shadow_shadowmapshadowsampler;
484 r_shadow_shadowmapsampler = vid.support.arb_shadow && r_shadow_shadowmapshadowsampler;
485 switch (r_shadow_shadowmapfilterquality)
490 r_shadow_shadowmappcf = 1;
493 r_shadow_shadowmappcf = 1;
496 r_shadow_shadowmappcf = 2;
500 if (!r_fb.usedepthtextures)
501 r_shadow_shadowmapsampler = false;
502 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
504 case RENDERPATH_D3D9:
505 case RENDERPATH_D3D10:
506 case RENDERPATH_D3D11:
507 case RENDERPATH_SOFT:
508 r_shadow_shadowmapsampler = false;
509 r_shadow_shadowmappcf = 1;
510 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
512 case RENDERPATH_GL11:
513 case RENDERPATH_GL13:
514 case RENDERPATH_GLES1:
515 case RENDERPATH_GLES2:
520 if(R_CompileShader_CheckStaticParms())
524 qboolean R_Shadow_ShadowMappingEnabled(void)
526 switch (r_shadow_shadowmode)
528 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
535 static void R_Shadow_FreeShadowMaps(void)
537 R_Shadow_SetShadowMode();
539 R_Mesh_DestroyFramebufferObject(r_shadow_fbo2d);
543 if (r_shadow_shadowmap2ddepthtexture)
544 R_FreeTexture(r_shadow_shadowmap2ddepthtexture);
545 r_shadow_shadowmap2ddepthtexture = NULL;
547 if (r_shadow_shadowmap2ddepthbuffer)
548 R_FreeTexture(r_shadow_shadowmap2ddepthbuffer);
549 r_shadow_shadowmap2ddepthbuffer = NULL;
551 if (r_shadow_shadowmapvsdcttexture)
552 R_FreeTexture(r_shadow_shadowmapvsdcttexture);
553 r_shadow_shadowmapvsdcttexture = NULL;
556 static void r_shadow_start(void)
558 // allocate vertex processing arrays
559 r_shadow_bouncegridpixels = NULL;
560 r_shadow_bouncegridhighpixels = NULL;
561 r_shadow_bouncegridnumpixels = 0;
562 r_shadow_bouncegridtexture = NULL;
563 r_shadow_bouncegriddirectional = false;
564 r_shadow_attenuationgradienttexture = NULL;
565 r_shadow_attenuation2dtexture = NULL;
566 r_shadow_attenuation3dtexture = NULL;
567 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
568 r_shadow_shadowmap2ddepthtexture = NULL;
569 r_shadow_shadowmap2ddepthbuffer = NULL;
570 r_shadow_shadowmapvsdcttexture = NULL;
571 r_shadow_shadowmapmaxsize = 0;
572 r_shadow_shadowmapsize = 0;
573 r_shadow_shadowmaplod = 0;
574 r_shadow_shadowmapfilterquality = -1;
575 r_shadow_shadowmapdepthbits = 0;
576 r_shadow_shadowmapvsdct = false;
577 r_shadow_shadowmapsampler = false;
578 r_shadow_shadowmappcf = 0;
581 R_Shadow_FreeShadowMaps();
583 r_shadow_texturepool = NULL;
584 r_shadow_filters_texturepool = NULL;
585 R_Shadow_ValidateCvars();
586 R_Shadow_MakeTextures();
587 maxshadowtriangles = 0;
588 shadowelements = NULL;
589 maxshadowvertices = 0;
590 shadowvertex3f = NULL;
598 shadowmarklist = NULL;
603 shadowsideslist = NULL;
604 r_shadow_buffer_numleafpvsbytes = 0;
605 r_shadow_buffer_visitingleafpvs = NULL;
606 r_shadow_buffer_leafpvs = NULL;
607 r_shadow_buffer_leaflist = NULL;
608 r_shadow_buffer_numsurfacepvsbytes = 0;
609 r_shadow_buffer_surfacepvs = NULL;
610 r_shadow_buffer_surfacelist = NULL;
611 r_shadow_buffer_surfacesides = NULL;
612 r_shadow_buffer_numshadowtrispvsbytes = 0;
613 r_shadow_buffer_shadowtrispvs = NULL;
614 r_shadow_buffer_numlighttrispvsbytes = 0;
615 r_shadow_buffer_lighttrispvs = NULL;
617 r_shadow_usingdeferredprepass = false;
618 r_shadow_prepass_width = r_shadow_prepass_height = 0;
621 static void R_Shadow_FreeDeferred(void);
622 static void r_shadow_shutdown(void)
625 R_Shadow_UncompileWorldLights();
627 R_Shadow_FreeShadowMaps();
629 r_shadow_usingdeferredprepass = false;
630 if (r_shadow_prepass_width)
631 R_Shadow_FreeDeferred();
632 r_shadow_prepass_width = r_shadow_prepass_height = 0;
635 r_shadow_bouncegridtexture = NULL;
636 r_shadow_bouncegridpixels = NULL;
637 r_shadow_bouncegridhighpixels = NULL;
638 r_shadow_bouncegridnumpixels = 0;
639 r_shadow_bouncegriddirectional = false;
640 r_shadow_attenuationgradienttexture = NULL;
641 r_shadow_attenuation2dtexture = NULL;
642 r_shadow_attenuation3dtexture = NULL;
643 R_FreeTexturePool(&r_shadow_texturepool);
644 R_FreeTexturePool(&r_shadow_filters_texturepool);
645 maxshadowtriangles = 0;
647 Mem_Free(shadowelements);
648 shadowelements = NULL;
650 Mem_Free(shadowvertex3f);
651 shadowvertex3f = NULL;
654 Mem_Free(vertexupdate);
657 Mem_Free(vertexremap);
663 Mem_Free(shadowmark);
666 Mem_Free(shadowmarklist);
667 shadowmarklist = NULL;
672 Mem_Free(shadowsides);
675 Mem_Free(shadowsideslist);
676 shadowsideslist = NULL;
677 r_shadow_buffer_numleafpvsbytes = 0;
678 if (r_shadow_buffer_visitingleafpvs)
679 Mem_Free(r_shadow_buffer_visitingleafpvs);
680 r_shadow_buffer_visitingleafpvs = NULL;
681 if (r_shadow_buffer_leafpvs)
682 Mem_Free(r_shadow_buffer_leafpvs);
683 r_shadow_buffer_leafpvs = NULL;
684 if (r_shadow_buffer_leaflist)
685 Mem_Free(r_shadow_buffer_leaflist);
686 r_shadow_buffer_leaflist = NULL;
687 r_shadow_buffer_numsurfacepvsbytes = 0;
688 if (r_shadow_buffer_surfacepvs)
689 Mem_Free(r_shadow_buffer_surfacepvs);
690 r_shadow_buffer_surfacepvs = NULL;
691 if (r_shadow_buffer_surfacelist)
692 Mem_Free(r_shadow_buffer_surfacelist);
693 r_shadow_buffer_surfacelist = NULL;
694 if (r_shadow_buffer_surfacesides)
695 Mem_Free(r_shadow_buffer_surfacesides);
696 r_shadow_buffer_surfacesides = NULL;
697 r_shadow_buffer_numshadowtrispvsbytes = 0;
698 if (r_shadow_buffer_shadowtrispvs)
699 Mem_Free(r_shadow_buffer_shadowtrispvs);
700 r_shadow_buffer_numlighttrispvsbytes = 0;
701 if (r_shadow_buffer_lighttrispvs)
702 Mem_Free(r_shadow_buffer_lighttrispvs);
705 static void r_shadow_newmap(void)
707 if (r_shadow_bouncegridtexture) R_FreeTexture(r_shadow_bouncegridtexture);r_shadow_bouncegridtexture = NULL;
708 if (r_shadow_lightcorona) R_SkinFrame_MarkUsed(r_shadow_lightcorona);
709 if (r_editlights_sprcursor) R_SkinFrame_MarkUsed(r_editlights_sprcursor);
710 if (r_editlights_sprlight) R_SkinFrame_MarkUsed(r_editlights_sprlight);
711 if (r_editlights_sprnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprnoshadowlight);
712 if (r_editlights_sprcubemaplight) R_SkinFrame_MarkUsed(r_editlights_sprcubemaplight);
713 if (r_editlights_sprcubemapnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprcubemapnoshadowlight);
714 if (r_editlights_sprselection) R_SkinFrame_MarkUsed(r_editlights_sprselection);
715 if (strncmp(cl.worldname, r_shadow_mapname, sizeof(r_shadow_mapname)))
716 R_Shadow_EditLights_Reload_f();
719 void R_Shadow_Init(void)
721 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
722 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
723 Cvar_RegisterVariable(&r_shadow_usebihculling);
724 Cvar_RegisterVariable(&r_shadow_usenormalmap);
725 Cvar_RegisterVariable(&r_shadow_debuglight);
726 Cvar_RegisterVariable(&r_shadow_deferred);
727 Cvar_RegisterVariable(&r_shadow_gloss);
728 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
729 Cvar_RegisterVariable(&r_shadow_glossintensity);
730 Cvar_RegisterVariable(&r_shadow_glossexponent);
731 Cvar_RegisterVariable(&r_shadow_gloss2exponent);
732 Cvar_RegisterVariable(&r_shadow_glossexact);
733 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
734 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
735 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
736 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
737 Cvar_RegisterVariable(&r_shadow_projectdistance);
738 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
739 Cvar_RegisterVariable(&r_shadow_realtime_world_importlightentitiesfrommap);
740 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
741 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
742 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
743 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
744 Cvar_RegisterVariable(&r_shadow_realtime_world);
745 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
746 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
747 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
748 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
749 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
750 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
751 Cvar_RegisterVariable(&r_shadow_scissor);
752 Cvar_RegisterVariable(&r_shadow_shadowmapping);
753 Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
754 Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
755 Cvar_RegisterVariable(&r_shadow_shadowmapping_useshadowsampler);
756 Cvar_RegisterVariable(&r_shadow_shadowmapping_depthbits);
757 Cvar_RegisterVariable(&r_shadow_shadowmapping_precision);
758 Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
759 Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
760 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
761 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
762 Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
763 Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
764 Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
765 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonfactor);
766 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonoffset);
767 Cvar_RegisterVariable(&r_shadow_sortsurfaces);
768 Cvar_RegisterVariable(&r_shadow_polygonfactor);
769 Cvar_RegisterVariable(&r_shadow_polygonoffset);
770 Cvar_RegisterVariable(&r_shadow_texture3d);
771 Cvar_RegisterVariable(&r_shadow_bouncegrid);
772 Cvar_RegisterVariable(&r_shadow_bouncegrid_bounceanglediffuse);
773 Cvar_RegisterVariable(&r_shadow_bouncegrid_directionalshading);
774 Cvar_RegisterVariable(&r_shadow_bouncegrid_dlightparticlemultiplier);
775 Cvar_RegisterVariable(&r_shadow_bouncegrid_hitmodels);
776 Cvar_RegisterVariable(&r_shadow_bouncegrid_includedirectlighting);
777 Cvar_RegisterVariable(&r_shadow_bouncegrid_intensity);
778 Cvar_RegisterVariable(&r_shadow_bouncegrid_lightradiusscale);
779 Cvar_RegisterVariable(&r_shadow_bouncegrid_maxbounce);
780 Cvar_RegisterVariable(&r_shadow_bouncegrid_particlebounceintensity);
781 Cvar_RegisterVariable(&r_shadow_bouncegrid_particleintensity);
782 Cvar_RegisterVariable(&r_shadow_bouncegrid_photons);
783 Cvar_RegisterVariable(&r_shadow_bouncegrid_spacing);
784 Cvar_RegisterVariable(&r_shadow_bouncegrid_stablerandom);
785 Cvar_RegisterVariable(&r_shadow_bouncegrid_static);
786 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_directionalshading);
787 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_lightradiusscale);
788 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_maxbounce);
789 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_photons);
790 Cvar_RegisterVariable(&r_shadow_bouncegrid_updateinterval);
791 Cvar_RegisterVariable(&r_shadow_bouncegrid_x);
792 Cvar_RegisterVariable(&r_shadow_bouncegrid_y);
793 Cvar_RegisterVariable(&r_shadow_bouncegrid_z);
794 Cvar_RegisterVariable(&r_coronas);
795 Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
796 Cvar_RegisterVariable(&r_coronas_occlusionquery);
797 Cvar_RegisterVariable(&gl_flashblend);
798 Cvar_RegisterVariable(&gl_ext_separatestencil);
799 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
800 R_Shadow_EditLights_Init();
801 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
802 maxshadowtriangles = 0;
803 shadowelements = NULL;
804 maxshadowvertices = 0;
805 shadowvertex3f = NULL;
813 shadowmarklist = NULL;
818 shadowsideslist = NULL;
819 r_shadow_buffer_numleafpvsbytes = 0;
820 r_shadow_buffer_visitingleafpvs = NULL;
821 r_shadow_buffer_leafpvs = NULL;
822 r_shadow_buffer_leaflist = NULL;
823 r_shadow_buffer_numsurfacepvsbytes = 0;
824 r_shadow_buffer_surfacepvs = NULL;
825 r_shadow_buffer_surfacelist = NULL;
826 r_shadow_buffer_surfacesides = NULL;
827 r_shadow_buffer_shadowtrispvs = NULL;
828 r_shadow_buffer_lighttrispvs = NULL;
829 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap, NULL, NULL);
832 matrix4x4_t matrix_attenuationxyz =
835 {0.5, 0.0, 0.0, 0.5},
836 {0.0, 0.5, 0.0, 0.5},
837 {0.0, 0.0, 0.5, 0.5},
842 matrix4x4_t matrix_attenuationz =
845 {0.0, 0.0, 0.5, 0.5},
846 {0.0, 0.0, 0.0, 0.5},
847 {0.0, 0.0, 0.0, 0.5},
852 static void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles, int vertscale, int triscale)
854 numvertices = ((numvertices + 255) & ~255) * vertscale;
855 numtriangles = ((numtriangles + 255) & ~255) * triscale;
856 // make sure shadowelements is big enough for this volume
857 if (maxshadowtriangles < numtriangles)
859 maxshadowtriangles = numtriangles;
861 Mem_Free(shadowelements);
862 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[3]));
864 // make sure shadowvertex3f is big enough for this volume
865 if (maxshadowvertices < numvertices)
867 maxshadowvertices = numvertices;
869 Mem_Free(shadowvertex3f);
870 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[3]));
874 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
876 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
877 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
878 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
879 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
880 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
882 if (r_shadow_buffer_visitingleafpvs)
883 Mem_Free(r_shadow_buffer_visitingleafpvs);
884 if (r_shadow_buffer_leafpvs)
885 Mem_Free(r_shadow_buffer_leafpvs);
886 if (r_shadow_buffer_leaflist)
887 Mem_Free(r_shadow_buffer_leaflist);
888 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
889 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
890 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
891 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
893 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
895 if (r_shadow_buffer_surfacepvs)
896 Mem_Free(r_shadow_buffer_surfacepvs);
897 if (r_shadow_buffer_surfacelist)
898 Mem_Free(r_shadow_buffer_surfacelist);
899 if (r_shadow_buffer_surfacesides)
900 Mem_Free(r_shadow_buffer_surfacesides);
901 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
902 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
903 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
904 r_shadow_buffer_surfacesides = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
906 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
908 if (r_shadow_buffer_shadowtrispvs)
909 Mem_Free(r_shadow_buffer_shadowtrispvs);
910 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
911 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
913 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
915 if (r_shadow_buffer_lighttrispvs)
916 Mem_Free(r_shadow_buffer_lighttrispvs);
917 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
918 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
922 void R_Shadow_PrepareShadowMark(int numtris)
924 // make sure shadowmark is big enough for this volume
925 if (maxshadowmark < numtris)
927 maxshadowmark = numtris;
929 Mem_Free(shadowmark);
931 Mem_Free(shadowmarklist);
932 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
933 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
937 // if shadowmarkcount wrapped we clear the array and adjust accordingly
938 if (shadowmarkcount == 0)
941 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
946 void R_Shadow_PrepareShadowSides(int numtris)
948 if (maxshadowsides < numtris)
950 maxshadowsides = numtris;
952 Mem_Free(shadowsides);
954 Mem_Free(shadowsideslist);
955 shadowsides = (unsigned char *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsides));
956 shadowsideslist = (int *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsideslist));
961 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)
964 int outtriangles = 0, outvertices = 0;
967 float ratio, direction[3], projectvector[3];
969 if (projectdirection)
970 VectorScale(projectdirection, projectdistance, projectvector);
972 VectorClear(projectvector);
974 // create the vertices
975 if (projectdirection)
977 for (i = 0;i < numshadowmarktris;i++)
979 element = inelement3i + shadowmarktris[i] * 3;
980 for (j = 0;j < 3;j++)
982 if (vertexupdate[element[j]] != vertexupdatenum)
984 vertexupdate[element[j]] = vertexupdatenum;
985 vertexremap[element[j]] = outvertices;
986 vertex = invertex3f + element[j] * 3;
987 // project one copy of the vertex according to projectvector
988 VectorCopy(vertex, outvertex3f);
989 VectorAdd(vertex, projectvector, (outvertex3f + 3));
998 for (i = 0;i < numshadowmarktris;i++)
1000 element = inelement3i + shadowmarktris[i] * 3;
1001 for (j = 0;j < 3;j++)
1003 if (vertexupdate[element[j]] != vertexupdatenum)
1005 vertexupdate[element[j]] = vertexupdatenum;
1006 vertexremap[element[j]] = outvertices;
1007 vertex = invertex3f + element[j] * 3;
1008 // project one copy of the vertex to the sphere radius of the light
1009 // (FIXME: would projecting it to the light box be better?)
1010 VectorSubtract(vertex, projectorigin, direction);
1011 ratio = projectdistance / VectorLength(direction);
1012 VectorCopy(vertex, outvertex3f);
1013 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1021 if (r_shadow_frontsidecasting.integer)
1023 for (i = 0;i < numshadowmarktris;i++)
1025 int remappedelement[3];
1027 const int *neighbortriangle;
1029 markindex = shadowmarktris[i] * 3;
1030 element = inelement3i + markindex;
1031 neighbortriangle = inneighbor3i + markindex;
1032 // output the front and back triangles
1033 outelement3i[0] = vertexremap[element[0]];
1034 outelement3i[1] = vertexremap[element[1]];
1035 outelement3i[2] = vertexremap[element[2]];
1036 outelement3i[3] = vertexremap[element[2]] + 1;
1037 outelement3i[4] = vertexremap[element[1]] + 1;
1038 outelement3i[5] = vertexremap[element[0]] + 1;
1042 // output the sides (facing outward from this triangle)
1043 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
1045 remappedelement[0] = vertexremap[element[0]];
1046 remappedelement[1] = vertexremap[element[1]];
1047 outelement3i[0] = remappedelement[1];
1048 outelement3i[1] = remappedelement[0];
1049 outelement3i[2] = remappedelement[0] + 1;
1050 outelement3i[3] = remappedelement[1];
1051 outelement3i[4] = remappedelement[0] + 1;
1052 outelement3i[5] = remappedelement[1] + 1;
1057 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1059 remappedelement[1] = vertexremap[element[1]];
1060 remappedelement[2] = vertexremap[element[2]];
1061 outelement3i[0] = remappedelement[2];
1062 outelement3i[1] = remappedelement[1];
1063 outelement3i[2] = remappedelement[1] + 1;
1064 outelement3i[3] = remappedelement[2];
1065 outelement3i[4] = remappedelement[1] + 1;
1066 outelement3i[5] = remappedelement[2] + 1;
1071 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1073 remappedelement[0] = vertexremap[element[0]];
1074 remappedelement[2] = vertexremap[element[2]];
1075 outelement3i[0] = remappedelement[0];
1076 outelement3i[1] = remappedelement[2];
1077 outelement3i[2] = remappedelement[2] + 1;
1078 outelement3i[3] = remappedelement[0];
1079 outelement3i[4] = remappedelement[2] + 1;
1080 outelement3i[5] = remappedelement[0] + 1;
1089 for (i = 0;i < numshadowmarktris;i++)
1091 int remappedelement[3];
1093 const int *neighbortriangle;
1095 markindex = shadowmarktris[i] * 3;
1096 element = inelement3i + markindex;
1097 neighbortriangle = inneighbor3i + markindex;
1098 // output the front and back triangles
1099 outelement3i[0] = vertexremap[element[2]];
1100 outelement3i[1] = vertexremap[element[1]];
1101 outelement3i[2] = vertexremap[element[0]];
1102 outelement3i[3] = vertexremap[element[0]] + 1;
1103 outelement3i[4] = vertexremap[element[1]] + 1;
1104 outelement3i[5] = vertexremap[element[2]] + 1;
1108 // output the sides (facing outward from this triangle)
1109 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
1111 remappedelement[0] = vertexremap[element[0]];
1112 remappedelement[1] = vertexremap[element[1]];
1113 outelement3i[0] = remappedelement[0];
1114 outelement3i[1] = remappedelement[1];
1115 outelement3i[2] = remappedelement[1] + 1;
1116 outelement3i[3] = remappedelement[0];
1117 outelement3i[4] = remappedelement[1] + 1;
1118 outelement3i[5] = remappedelement[0] + 1;
1123 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1125 remappedelement[1] = vertexremap[element[1]];
1126 remappedelement[2] = vertexremap[element[2]];
1127 outelement3i[0] = remappedelement[1];
1128 outelement3i[1] = remappedelement[2];
1129 outelement3i[2] = remappedelement[2] + 1;
1130 outelement3i[3] = remappedelement[1];
1131 outelement3i[4] = remappedelement[2] + 1;
1132 outelement3i[5] = remappedelement[1] + 1;
1137 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1139 remappedelement[0] = vertexremap[element[0]];
1140 remappedelement[2] = vertexremap[element[2]];
1141 outelement3i[0] = remappedelement[2];
1142 outelement3i[1] = remappedelement[0];
1143 outelement3i[2] = remappedelement[0] + 1;
1144 outelement3i[3] = remappedelement[2];
1145 outelement3i[4] = remappedelement[0] + 1;
1146 outelement3i[5] = remappedelement[2] + 1;
1154 *outnumvertices = outvertices;
1155 return outtriangles;
1158 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)
1161 int outtriangles = 0, outvertices = 0;
1163 const float *vertex;
1164 float ratio, direction[3], projectvector[3];
1167 if (projectdirection)
1168 VectorScale(projectdirection, projectdistance, projectvector);
1170 VectorClear(projectvector);
1172 for (i = 0;i < numshadowmarktris;i++)
1174 int remappedelement[3];
1176 const int *neighbortriangle;
1178 markindex = shadowmarktris[i] * 3;
1179 neighbortriangle = inneighbor3i + markindex;
1180 side[0] = shadowmark[neighbortriangle[0]] == shadowmarkcount;
1181 side[1] = shadowmark[neighbortriangle[1]] == shadowmarkcount;
1182 side[2] = shadowmark[neighbortriangle[2]] == shadowmarkcount;
1183 if (side[0] + side[1] + side[2] == 0)
1187 element = inelement3i + markindex;
1189 // create the vertices
1190 for (j = 0;j < 3;j++)
1192 if (side[j] + side[j+1] == 0)
1195 if (vertexupdate[k] != vertexupdatenum)
1197 vertexupdate[k] = vertexupdatenum;
1198 vertexremap[k] = outvertices;
1199 vertex = invertex3f + k * 3;
1200 VectorCopy(vertex, outvertex3f);
1201 if (projectdirection)
1203 // project one copy of the vertex according to projectvector
1204 VectorAdd(vertex, projectvector, (outvertex3f + 3));
1208 // project one copy of the vertex to the sphere radius of the light
1209 // (FIXME: would projecting it to the light box be better?)
1210 VectorSubtract(vertex, projectorigin, direction);
1211 ratio = projectdistance / VectorLength(direction);
1212 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1219 // output the sides (facing outward from this triangle)
1222 remappedelement[0] = vertexremap[element[0]];
1223 remappedelement[1] = vertexremap[element[1]];
1224 outelement3i[0] = remappedelement[1];
1225 outelement3i[1] = remappedelement[0];
1226 outelement3i[2] = remappedelement[0] + 1;
1227 outelement3i[3] = remappedelement[1];
1228 outelement3i[4] = remappedelement[0] + 1;
1229 outelement3i[5] = remappedelement[1] + 1;
1236 remappedelement[1] = vertexremap[element[1]];
1237 remappedelement[2] = vertexremap[element[2]];
1238 outelement3i[0] = remappedelement[2];
1239 outelement3i[1] = remappedelement[1];
1240 outelement3i[2] = remappedelement[1] + 1;
1241 outelement3i[3] = remappedelement[2];
1242 outelement3i[4] = remappedelement[1] + 1;
1243 outelement3i[5] = remappedelement[2] + 1;
1250 remappedelement[0] = vertexremap[element[0]];
1251 remappedelement[2] = vertexremap[element[2]];
1252 outelement3i[0] = remappedelement[0];
1253 outelement3i[1] = remappedelement[2];
1254 outelement3i[2] = remappedelement[2] + 1;
1255 outelement3i[3] = remappedelement[0];
1256 outelement3i[4] = remappedelement[2] + 1;
1257 outelement3i[5] = remappedelement[0] + 1;
1264 *outnumvertices = outvertices;
1265 return outtriangles;
1268 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)
1274 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1276 tend = firsttriangle + numtris;
1277 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1279 // surface box entirely inside light box, no box cull
1280 if (projectdirection)
1282 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1284 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
1285 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1286 shadowmarklist[numshadowmark++] = t;
1291 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1292 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
1293 shadowmarklist[numshadowmark++] = t;
1298 // surface box not entirely inside light box, cull each triangle
1299 if (projectdirection)
1301 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1303 v[0] = invertex3f + e[0] * 3;
1304 v[1] = invertex3f + e[1] * 3;
1305 v[2] = invertex3f + e[2] * 3;
1306 TriangleNormal(v[0], v[1], v[2], normal);
1307 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1308 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1309 shadowmarklist[numshadowmark++] = t;
1314 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1316 v[0] = invertex3f + e[0] * 3;
1317 v[1] = invertex3f + e[1] * 3;
1318 v[2] = invertex3f + e[2] * 3;
1319 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1320 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1321 shadowmarklist[numshadowmark++] = t;
1327 static qboolean R_Shadow_UseZPass(vec3_t mins, vec3_t maxs)
1332 if (r_shadow_compilingrtlight || !r_shadow_frontsidecasting.integer || !r_shadow_usezpassifpossible.integer)
1334 // check if the shadow volume intersects the near plane
1336 // a ray between the eye and light origin may intersect the caster,
1337 // indicating that the shadow may touch the eye location, however we must
1338 // test the near plane (a polygon), not merely the eye location, so it is
1339 // easiest to enlarge the caster bounding shape slightly for this.
1345 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)
1347 int i, tris, outverts;
1348 if (projectdistance < 0.1)
1350 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
1353 if (!numverts || !nummarktris)
1355 // make sure shadowelements is big enough for this volume
1356 if (maxshadowtriangles < nummarktris*8 || maxshadowvertices < numverts*2)
1357 R_Shadow_ResizeShadowArrays(numverts, nummarktris, 2, 8);
1359 if (maxvertexupdate < numverts)
1361 maxvertexupdate = numverts;
1363 Mem_Free(vertexupdate);
1365 Mem_Free(vertexremap);
1366 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1367 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1368 vertexupdatenum = 0;
1371 if (vertexupdatenum == 0)
1373 vertexupdatenum = 1;
1374 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
1375 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
1378 for (i = 0;i < nummarktris;i++)
1379 shadowmark[marktris[i]] = shadowmarkcount;
1381 if (r_shadow_compilingrtlight)
1383 // if we're compiling an rtlight, capture the mesh
1384 //tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1385 //Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zpass, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1386 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1387 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zfail, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1389 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
1391 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1392 R_Mesh_PrepareVertices_Vertex3f(outverts, shadowvertex3f, NULL, 0);
1393 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1397 // decide which type of shadow to generate and set stencil mode
1398 R_Shadow_RenderMode_StencilShadowVolumes(R_Shadow_UseZPass(trismins, trismaxs));
1399 // generate the sides or a solid volume, depending on type
1400 if (r_shadow_rendermode >= R_SHADOW_RENDERMODE_ZPASS_STENCIL && r_shadow_rendermode <= R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE)
1401 tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1403 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1404 r_refdef.stats[r_stat_lights_dynamicshadowtriangles] += tris;
1405 r_refdef.stats[r_stat_lights_shadowtriangles] += tris;
1406 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
1408 // increment stencil if frontface is infront of depthbuffer
1409 GL_CullFace(r_refdef.view.cullface_front);
1410 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
1411 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1412 // decrement stencil if backface is infront of depthbuffer
1413 GL_CullFace(r_refdef.view.cullface_back);
1414 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
1416 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
1418 // decrement stencil if backface is behind depthbuffer
1419 GL_CullFace(r_refdef.view.cullface_front);
1420 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
1421 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1422 // increment stencil if frontface is behind depthbuffer
1423 GL_CullFace(r_refdef.view.cullface_back);
1424 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
1426 R_Mesh_PrepareVertices_Vertex3f(outverts, shadowvertex3f, NULL, 0);
1427 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1431 int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias)
1433 // p1, p2, p3 are in the cubemap's local coordinate system
1434 // bias = border/(size - border)
1437 float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1438 dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2),
1439 dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3);
1440 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1442 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1443 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1444 | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1445 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1447 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1448 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1449 | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1451 dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1452 dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2),
1453 dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3);
1454 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1456 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1457 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1458 | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1459 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1461 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1462 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1463 | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1465 dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1466 dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2),
1467 dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3);
1468 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1470 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1471 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1472 | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1473 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1475 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1476 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1477 | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1482 static int R_Shadow_CalcBBoxSideMask(const vec3_t mins, const vec3_t maxs, const matrix4x4_t *worldtolight, const matrix4x4_t *radiustolight, float bias)
1484 vec3_t center, radius, lightcenter, lightradius, pmin, pmax;
1485 float dp1, dn1, ap1, an1, dp2, dn2, ap2, an2;
1488 VectorSubtract(maxs, mins, radius);
1489 VectorScale(radius, 0.5f, radius);
1490 VectorAdd(mins, radius, center);
1491 Matrix4x4_Transform(worldtolight, center, lightcenter);
1492 Matrix4x4_Transform3x3(radiustolight, radius, lightradius);
1493 VectorSubtract(lightcenter, lightradius, pmin);
1494 VectorAdd(lightcenter, lightradius, pmax);
1496 dp1 = pmax[0] + pmax[1], dn1 = pmax[0] - pmin[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1497 dp2 = pmin[0] + pmin[1], dn2 = pmin[0] - pmax[1], ap2 = fabs(dp2), an2 = fabs(dn2);
1498 if(ap1 > bias*an1 && ap2 > bias*an2)
1500 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1501 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1502 if(an1 > bias*ap1 && an2 > bias*ap2)
1504 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1505 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1507 dp1 = pmax[1] + pmax[2], dn1 = pmax[1] - pmin[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1508 dp2 = pmin[1] + pmin[2], dn2 = pmin[1] - pmax[2], ap2 = fabs(dp2), an2 = fabs(dn2);
1509 if(ap1 > bias*an1 && ap2 > bias*an2)
1511 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1512 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1513 if(an1 > bias*ap1 && an2 > bias*ap2)
1515 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1516 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1518 dp1 = pmax[2] + pmax[0], dn1 = pmax[2] - pmin[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1519 dp2 = pmin[2] + pmin[0], dn2 = pmin[2] - pmax[0], ap2 = fabs(dp2), an2 = fabs(dn2);
1520 if(ap1 > bias*an1 && ap2 > bias*an2)
1522 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1523 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1524 if(an1 > bias*ap1 && an2 > bias*ap2)
1526 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1527 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1532 #define R_Shadow_CalcEntitySideMask(ent, worldtolight, radiustolight, bias) R_Shadow_CalcBBoxSideMask((ent)->mins, (ent)->maxs, worldtolight, radiustolight, bias)
1534 int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
1536 // p is in the cubemap's local coordinate system
1537 // bias = border/(size - border)
1538 float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn);
1539 float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn);
1540 float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn);
1542 if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
1543 if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
1544 if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
1545 if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
1546 if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
1547 if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
1551 static int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
1555 int sides = 0x3F, masks[6] = { 3<<4, 3<<4, 3<<0, 3<<0, 3<<2, 3<<2 };
1556 float scale = (size - 2*border)/size, len;
1557 float bias = border / (float)(size - border), dp, dn, ap, an;
1558 // check if cone enclosing side would cross frustum plane
1559 scale = 2 / (scale*scale + 2);
1560 Matrix4x4_OriginFromMatrix(&rtlight->matrix_lighttoworld, o);
1561 for (i = 0;i < 5;i++)
1563 if (PlaneDiff(o, &r_refdef.view.frustum[i]) > -0.03125)
1565 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[i].normal, n);
1566 len = scale*VectorLength2(n);
1567 if(n[0]*n[0] > len) sides &= n[0] < 0 ? ~(1<<0) : ~(2 << 0);
1568 if(n[1]*n[1] > len) sides &= n[1] < 0 ? ~(1<<2) : ~(2 << 2);
1569 if(n[2]*n[2] > len) sides &= n[2] < 0 ? ~(1<<4) : ~(2 << 4);
1571 if (PlaneDiff(o, &r_refdef.view.frustum[4]) >= r_refdef.farclip - r_refdef.nearclip + 0.03125)
1573 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[4].normal, n);
1574 len = scale*VectorLength2(n);
1575 if(n[0]*n[0] > len) sides &= n[0] >= 0 ? ~(1<<0) : ~(2 << 0);
1576 if(n[1]*n[1] > len) sides &= n[1] >= 0 ? ~(1<<2) : ~(2 << 2);
1577 if(n[2]*n[2] > len) sides &= n[2] >= 0 ? ~(1<<4) : ~(2 << 4);
1579 // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results
1580 // check if frustum corners/origin cross plane sides
1582 // infinite version, assumes frustum corners merely give direction and extend to infinite distance
1583 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.origin, p);
1584 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1585 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1586 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1587 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1588 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1589 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1590 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1591 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1592 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1593 for (i = 0;i < 4;i++)
1595 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.frustumcorner[i], n);
1596 VectorSubtract(n, p, n);
1597 dp = n[0] + n[1], dn = n[0] - n[1], ap = fabs(dp), an = fabs(dn);
1598 if(ap > 0) masks[0] |= dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2);
1599 if(an > 0) masks[1] |= dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2);
1600 dp = n[1] + n[2], dn = n[1] - n[2], ap = fabs(dp), an = fabs(dn);
1601 if(ap > 0) masks[2] |= dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4);
1602 if(an > 0) masks[3] |= dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4);
1603 dp = n[2] + n[0], dn = n[2] - n[0], ap = fabs(dp), an = fabs(dn);
1604 if(ap > 0) masks[4] |= dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0);
1605 if(an > 0) masks[5] |= dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0);
1608 // finite version, assumes corners are a finite distance from origin dependent on far plane
1609 for (i = 0;i < 5;i++)
1611 Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p);
1612 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1613 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1614 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1615 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1616 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1617 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1618 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1619 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1620 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1623 return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5];
1626 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)
1634 int mask, surfacemask = 0;
1635 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1637 bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
1638 tend = firsttriangle + numtris;
1639 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1641 // surface box entirely inside light box, no box cull
1642 if (projectdirection)
1644 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1646 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1647 TriangleNormal(v[0], v[1], v[2], normal);
1648 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1650 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1651 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1652 surfacemask |= mask;
1655 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;
1656 shadowsides[numshadowsides] = mask;
1657 shadowsideslist[numshadowsides++] = t;
1664 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1666 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1667 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]))
1669 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1670 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1671 surfacemask |= mask;
1674 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;
1675 shadowsides[numshadowsides] = mask;
1676 shadowsideslist[numshadowsides++] = t;
1684 // surface box not entirely inside light box, cull each triangle
1685 if (projectdirection)
1687 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1689 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1690 TriangleNormal(v[0], v[1], v[2], normal);
1691 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1692 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1694 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1695 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1696 surfacemask |= mask;
1699 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;
1700 shadowsides[numshadowsides] = mask;
1701 shadowsideslist[numshadowsides++] = t;
1708 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1710 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1711 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1712 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1714 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1715 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1716 surfacemask |= mask;
1719 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;
1720 shadowsides[numshadowsides] = mask;
1721 shadowsideslist[numshadowsides++] = t;
1730 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)
1732 int i, j, outtriangles = 0;
1733 int *outelement3i[6];
1734 if (!numverts || !numsidetris || !r_shadow_compilingrtlight)
1736 outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5];
1737 // make sure shadowelements is big enough for this mesh
1738 if (maxshadowtriangles < outtriangles)
1739 R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1);
1741 // compute the offset and size of the separate index lists for each cubemap side
1743 for (i = 0;i < 6;i++)
1745 outelement3i[i] = shadowelements + outtriangles * 3;
1746 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles;
1747 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i];
1748 outtriangles += sidetotals[i];
1751 // gather up the (sparse) triangles into separate index lists for each cubemap side
1752 for (i = 0;i < numsidetris;i++)
1754 const int *element = elements + sidetris[i] * 3;
1755 for (j = 0;j < 6;j++)
1757 if (sides[i] & (1 << j))
1759 outelement3i[j][0] = element[0];
1760 outelement3i[j][1] = element[1];
1761 outelement3i[j][2] = element[2];
1762 outelement3i[j] += 3;
1767 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, outtriangles, shadowelements);
1770 static void R_Shadow_MakeTextures_MakeCorona(void)
1774 unsigned char pixels[32][32][4];
1775 for (y = 0;y < 32;y++)
1777 dy = (y - 15.5f) * (1.0f / 16.0f);
1778 for (x = 0;x < 32;x++)
1780 dx = (x - 15.5f) * (1.0f / 16.0f);
1781 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1782 a = bound(0, a, 255);
1783 pixels[y][x][0] = a;
1784 pixels[y][x][1] = a;
1785 pixels[y][x][2] = a;
1786 pixels[y][x][3] = 255;
1789 r_shadow_lightcorona = R_SkinFrame_LoadInternalBGRA("lightcorona", TEXF_FORCELINEAR, &pixels[0][0][0], 32, 32, false);
1792 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1794 float dist = sqrt(x*x+y*y+z*z);
1795 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1796 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1797 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1800 static void R_Shadow_MakeTextures(void)
1803 float intensity, dist;
1805 R_Shadow_FreeShadowMaps();
1806 R_FreeTexturePool(&r_shadow_texturepool);
1807 r_shadow_texturepool = R_AllocTexturePool();
1808 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1809 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1810 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1811 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1812 for (x = 0;x <= ATTENTABLESIZE;x++)
1814 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1815 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1816 r_shadow_attentable[x] = bound(0, intensity, 1);
1818 // 1D gradient texture
1819 for (x = 0;x < ATTEN1DSIZE;x++)
1820 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1821 r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1822 // 2D circle texture
1823 for (y = 0;y < ATTEN2DSIZE;y++)
1824 for (x = 0;x < ATTEN2DSIZE;x++)
1825 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);
1826 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1827 // 3D sphere texture
1828 if (r_shadow_texture3d.integer && vid.support.ext_texture_3d)
1830 for (z = 0;z < ATTEN3DSIZE;z++)
1831 for (y = 0;y < ATTEN3DSIZE;y++)
1832 for (x = 0;x < ATTEN3DSIZE;x++)
1833 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));
1834 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);
1837 r_shadow_attenuation3dtexture = NULL;
1840 R_Shadow_MakeTextures_MakeCorona();
1842 // Editor light sprites
1843 r_editlights_sprcursor = R_SkinFrame_LoadInternal8bit("gfx/editlights/cursor", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1860 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1861 r_editlights_sprlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/light", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1878 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1879 r_editlights_sprnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/noshadow", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1896 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1897 r_editlights_sprcubemaplight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemaplight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1914 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1915 r_editlights_sprcubemapnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemapnoshadowlight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1932 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1933 r_editlights_sprselection = R_SkinFrame_LoadInternal8bit("gfx/editlights/selection", TEXF_ALPHA | TEXF_CLAMP, (unsigned char *)
1950 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1953 void R_Shadow_ValidateCvars(void)
1955 if (r_shadow_texture3d.integer && !vid.support.ext_texture_3d)
1956 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1957 if (gl_ext_separatestencil.integer && !vid.support.ati_separate_stencil)
1958 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
1959 if (gl_ext_stenciltwoside.integer && !vid.support.ext_stencil_two_side)
1960 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1963 void R_Shadow_RenderMode_Begin(void)
1969 R_Shadow_ValidateCvars();
1971 if (!r_shadow_attenuation2dtexture
1972 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1973 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1974 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1975 R_Shadow_MakeTextures();
1978 R_Mesh_ResetTextureState();
1979 GL_BlendFunc(GL_ONE, GL_ZERO);
1980 GL_DepthRange(0, 1);
1981 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1983 GL_DepthMask(false);
1984 GL_Color(0, 0, 0, 1);
1985 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1987 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1989 if (gl_ext_separatestencil.integer && vid.support.ati_separate_stencil)
1991 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
1992 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
1994 else if (gl_ext_stenciltwoside.integer && vid.support.ext_stencil_two_side)
1996 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
1997 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
2001 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
2002 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
2005 switch(vid.renderpath)
2007 case RENDERPATH_GL20:
2008 case RENDERPATH_D3D9:
2009 case RENDERPATH_D3D10:
2010 case RENDERPATH_D3D11:
2011 case RENDERPATH_SOFT:
2012 case RENDERPATH_GLES2:
2013 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
2015 case RENDERPATH_GL11:
2016 case RENDERPATH_GL13:
2017 case RENDERPATH_GLES1:
2018 if (r_textureunits.integer >= 2 && vid.texunits >= 2 && r_shadow_texture3d.integer && r_shadow_attenuation3dtexture)
2019 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN;
2020 else if (r_textureunits.integer >= 3 && vid.texunits >= 3)
2021 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN;
2022 else if (r_textureunits.integer >= 2 && vid.texunits >= 2)
2023 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN;
2025 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
2031 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
2032 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
2033 r_shadow_drawbuffer = drawbuffer;
2034 r_shadow_readbuffer = readbuffer;
2036 r_shadow_cullface_front = r_refdef.view.cullface_front;
2037 r_shadow_cullface_back = r_refdef.view.cullface_back;
2040 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
2042 rsurface.rtlight = rtlight;
2045 void R_Shadow_RenderMode_Reset(void)
2047 R_Mesh_ResetTextureState();
2048 R_Mesh_SetRenderTargets(r_shadow_fb_fbo, r_shadow_fb_depthtexture, r_shadow_fb_colortexture, NULL, NULL, NULL);
2049 R_SetViewport(&r_refdef.view.viewport);
2050 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
2051 GL_DepthRange(0, 1);
2053 GL_DepthMask(false);
2054 GL_DepthFunc(GL_LEQUAL);
2055 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
2056 r_refdef.view.cullface_front = r_shadow_cullface_front;
2057 r_refdef.view.cullface_back = r_shadow_cullface_back;
2058 GL_CullFace(r_refdef.view.cullface_back);
2059 GL_Color(1, 1, 1, 1);
2060 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
2061 GL_BlendFunc(GL_ONE, GL_ZERO);
2062 R_SetupShader_Generic_NoTexture(false, false);
2063 r_shadow_usingshadowmap2d = false;
2064 r_shadow_usingshadowmaportho = false;
2065 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
2068 void R_Shadow_ClearStencil(void)
2070 GL_Clear(GL_STENCIL_BUFFER_BIT, NULL, 1.0f, 128);
2071 r_refdef.stats[r_stat_lights_clears]++;
2074 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
2076 r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
2077 if (r_shadow_rendermode == mode)
2079 R_Shadow_RenderMode_Reset();
2080 GL_DepthFunc(GL_LESS);
2081 GL_ColorMask(0, 0, 0, 0);
2082 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2083 GL_CullFace(GL_NONE);
2084 R_SetupShader_DepthOrShadow(false, false, false); // FIXME test if we have a skeletal model?
2085 r_shadow_rendermode = mode;
2090 case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
2091 case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
2092 R_SetStencilSeparate(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, GL_ALWAYS, 128, 255);
2094 case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
2095 case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
2096 R_SetStencilSeparate(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, GL_ALWAYS, 128, 255);
2101 static void R_Shadow_MakeVSDCT(void)
2103 // maps to a 2x3 texture rectangle with normalized coordinates
2108 // stores abs(dir.xy), offset.xy/2.5
2109 unsigned char data[4*6] =
2111 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
2112 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
2113 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
2114 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
2115 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
2116 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
2118 r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
2121 static void R_Shadow_MakeShadowMap(int side, int size)
2123 switch (r_shadow_shadowmode)
2125 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2126 if (r_shadow_shadowmap2ddepthtexture) return;
2127 if (r_fb.usedepthtextures)
2129 r_shadow_shadowmap2ddepthtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "shadowmap", size*2, size*(vid.support.arb_texture_non_power_of_two ? 3 : 4), r_shadow_shadowmapdepthbits >= 24 ? (r_shadow_shadowmapsampler ? TEXTYPE_SHADOWMAP24_COMP : TEXTYPE_SHADOWMAP24_RAW) : (r_shadow_shadowmapsampler ? TEXTYPE_SHADOWMAP16_COMP : TEXTYPE_SHADOWMAP16_RAW), r_shadow_shadowmapsampler);
2130 r_shadow_shadowmap2ddepthbuffer = NULL;
2131 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
2135 r_shadow_shadowmap2ddepthtexture = R_LoadTexture2D(r_shadow_texturepool, "shadowmaprendertarget", size*2, size*(vid.support.arb_texture_non_power_of_two ? 3 : 4), NULL, TEXTYPE_COLORBUFFER, TEXF_RENDERTARGET | TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
2136 r_shadow_shadowmap2ddepthbuffer = R_LoadTextureRenderBuffer(r_shadow_texturepool, "shadowmap", size*2, size*(vid.support.arb_texture_non_power_of_two ? 3 : 4), r_shadow_shadowmapdepthbits >= 24 ? TEXTYPE_DEPTHBUFFER24 : TEXTYPE_DEPTHBUFFER16);
2137 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
2145 static void R_Shadow_RenderMode_ShadowMap(int side, int clear, int size)
2147 float nearclip, farclip, bias;
2148 r_viewport_t viewport;
2151 float clearcolor[4];
2152 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
2154 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
2155 r_shadow_shadowmap_parameters[1] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
2156 r_shadow_shadowmap_parameters[3] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
2157 r_shadow_shadowmapside = side;
2158 r_shadow_shadowmapsize = size;
2160 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2161 r_shadow_shadowmap_parameters[2] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2162 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
2163 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D) goto init_done;
2165 // complex unrolled cube approach (more flexible)
2166 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2167 R_Shadow_MakeVSDCT();
2168 if (!r_shadow_shadowmap2ddepthtexture)
2169 R_Shadow_MakeShadowMap(side, r_shadow_shadowmapmaxsize);
2170 fbo2d = r_shadow_fbo2d;
2171 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2ddepthtexture);
2172 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2ddepthtexture);
2173 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
2175 R_Mesh_ResetTextureState();
2176 R_Shadow_RenderMode_Reset();
2177 if (r_shadow_shadowmap2ddepthbuffer)
2178 R_Mesh_SetRenderTargets(fbo2d, r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
2180 R_Mesh_SetRenderTargets(fbo2d, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
2181 R_SetupShader_DepthOrShadow(true, r_shadow_shadowmap2ddepthbuffer != NULL, false); // FIXME test if we have a skeletal model?
2182 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
2187 R_SetViewport(&viewport);
2188 flipped = (side & 1) ^ (side >> 2);
2189 r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
2190 r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
2191 if (r_shadow_shadowmap2ddepthbuffer)
2193 // completely different meaning than in depthtexture approach
2194 r_shadow_shadowmap_parameters[1] = 0;
2195 r_shadow_shadowmap_parameters[3] = -bias;
2197 Vector4Set(clearcolor, 1,1,1,1);
2198 if (r_shadow_shadowmap2ddepthbuffer)
2199 GL_ColorMask(1,1,1,1);
2201 GL_ColorMask(0,0,0,0);
2202 switch(vid.renderpath)
2204 case RENDERPATH_GL11:
2205 case RENDERPATH_GL13:
2206 case RENDERPATH_GL20:
2207 case RENDERPATH_SOFT:
2208 case RENDERPATH_GLES1:
2209 case RENDERPATH_GLES2:
2210 GL_CullFace(r_refdef.view.cullface_back);
2211 // OpenGL lets us scissor larger than the viewport, so go ahead and clear all views at once
2212 if ((clear & ((2 << side) - 1)) == (1 << side)) // only clear if the side is the first in the mask
2214 // get tightest scissor rectangle that encloses all viewports in the clear mask
2215 int x1 = clear & 0x15 ? 0 : size;
2216 int x2 = clear & 0x2A ? 2 * size : size;
2217 int y1 = clear & 0x03 ? 0 : (clear & 0xC ? size : 2 * size);
2218 int y2 = clear & 0x30 ? 3 * size : (clear & 0xC ? 2 * size : size);
2219 GL_Scissor(x1, y1, x2 - x1, y2 - y1);
2222 if (r_shadow_shadowmap2ddepthbuffer)
2223 GL_Clear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
2225 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
2228 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2230 case RENDERPATH_D3D9:
2231 case RENDERPATH_D3D10:
2232 case RENDERPATH_D3D11:
2233 // we invert the cull mode because we flip the projection matrix
2234 // NOTE: this actually does nothing because the DrawShadowMap code sets it to doublesided...
2235 GL_CullFace(r_refdef.view.cullface_front);
2236 // D3D considers it an error to use a scissor larger than the viewport... clear just this view
2237 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2240 if (r_shadow_shadowmap2ddepthbuffer)
2241 GL_Clear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
2243 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
2249 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
2251 R_Mesh_ResetTextureState();
2254 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2255 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2256 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2257 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2259 R_Shadow_RenderMode_Reset();
2260 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2262 GL_DepthFunc(GL_EQUAL);
2263 // do global setup needed for the chosen lighting mode
2264 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2265 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2266 r_shadow_usingshadowmap2d = shadowmapping;
2267 r_shadow_rendermode = r_shadow_lightingrendermode;
2268 // only draw light where this geometry was already rendered AND the
2269 // stencil is 128 (values other than this mean shadow)
2271 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2273 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
2276 static const unsigned short bboxelements[36] =
2286 static const float bboxpoints[8][3] =
2298 void R_Shadow_RenderMode_DrawDeferredLight(qboolean stenciltest, qboolean shadowmapping)
2301 float vertex3f[8*3];
2302 const matrix4x4_t *matrix = &rsurface.rtlight->matrix_lighttoworld;
2303 // do global setup needed for the chosen lighting mode
2304 R_Shadow_RenderMode_Reset();
2305 r_shadow_rendermode = r_shadow_lightingrendermode;
2306 R_EntityMatrix(&identitymatrix);
2307 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2308 // only draw light where this geometry was already rendered AND the
2309 // stencil is 128 (values other than this mean shadow)
2310 R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2311 if (rsurface.rtlight->specularscale > 0 && r_shadow_gloss.integer > 0)
2312 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
2314 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
2316 r_shadow_usingshadowmap2d = shadowmapping;
2318 // render the lighting
2319 R_SetupShader_DeferredLight(rsurface.rtlight);
2320 for (i = 0;i < 8;i++)
2321 Matrix4x4_Transform(matrix, bboxpoints[i], vertex3f + i*3);
2322 GL_ColorMask(1,1,1,1);
2323 GL_DepthMask(false);
2324 GL_DepthRange(0, 1);
2325 GL_PolygonOffset(0, 0);
2327 GL_DepthFunc(GL_GREATER);
2328 GL_CullFace(r_refdef.view.cullface_back);
2329 R_Mesh_PrepareVertices_Vertex3f(8, vertex3f, NULL, 0);
2330 R_Mesh_Draw(0, 8, 0, 12, NULL, NULL, 0, bboxelements, NULL, 0);
2333 void R_Shadow_UpdateBounceGridTexture(void)
2335 #define MAXBOUNCEGRIDPARTICLESPERLIGHT 1048576
2337 int flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
2339 int hitsupercontentsmask;
2348 //trace_t cliptrace2;
2349 //trace_t cliptrace3;
2350 unsigned char *pixel;
2351 unsigned char *pixels;
2354 unsigned int lightindex;
2356 unsigned int range1;
2357 unsigned int range2;
2358 unsigned int seed = (unsigned int)(realtime * 1000.0f);
2360 vec3_t baseshotcolor;
2373 vec3_t cullmins, cullmaxs;
2376 vec_t lightintensity;
2377 vec_t photonscaling;
2378 vec_t photonresidual;
2380 float texlerp[2][3];
2381 float splatcolor[32];
2382 float pixelweight[8];
2394 r_shadow_bouncegrid_settings_t settings;
2395 qboolean enable = r_shadow_bouncegrid.integer != 0 && r_refdef.scene.worldmodel;
2396 qboolean allowdirectionalshading = false;
2397 switch(vid.renderpath)
2399 case RENDERPATH_GL20:
2400 allowdirectionalshading = true;
2401 if (!vid.support.ext_texture_3d)
2404 case RENDERPATH_GLES2:
2405 // for performance reasons, do not use directional shading on GLES devices
2406 if (!vid.support.ext_texture_3d)
2409 // these renderpaths do not currently have the code to display the bouncegrid, so disable it on them...
2410 case RENDERPATH_GL11:
2411 case RENDERPATH_GL13:
2412 case RENDERPATH_GLES1:
2413 case RENDERPATH_SOFT:
2414 case RENDERPATH_D3D9:
2415 case RENDERPATH_D3D10:
2416 case RENDERPATH_D3D11:
2420 r_shadow_bouncegridintensity = r_shadow_bouncegrid_intensity.value;
2422 // see if there are really any lights to render...
2423 if (enable && r_shadow_bouncegrid_static.integer)
2426 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
2427 for (lightindex = 0;lightindex < range;lightindex++)
2429 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2430 if (!light || !(light->flags & flag))
2432 rtlight = &light->rtlight;
2433 // when static, we skip styled lights because they tend to change...
2434 if (rtlight->style > 0)
2436 VectorScale(rtlight->color, (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale), lightcolor);
2437 if (!VectorLength2(lightcolor))
2446 if (r_shadow_bouncegridtexture)
2448 R_FreeTexture(r_shadow_bouncegridtexture);
2449 r_shadow_bouncegridtexture = NULL;
2451 if (r_shadow_bouncegridpixels)
2452 Mem_Free(r_shadow_bouncegridpixels);
2453 r_shadow_bouncegridpixels = NULL;
2454 if (r_shadow_bouncegridhighpixels)
2455 Mem_Free(r_shadow_bouncegridhighpixels);
2456 r_shadow_bouncegridhighpixels = NULL;
2457 r_shadow_bouncegridnumpixels = 0;
2458 r_shadow_bouncegriddirectional = false;
2462 // build up a complete collection of the desired settings, so that memcmp can be used to compare parameters
2463 memset(&settings, 0, sizeof(settings));
2464 settings.staticmode = r_shadow_bouncegrid_static.integer != 0;
2465 settings.bounceanglediffuse = r_shadow_bouncegrid_bounceanglediffuse.integer != 0;
2466 settings.directionalshading = (r_shadow_bouncegrid_static.integer != 0 ? r_shadow_bouncegrid_static_directionalshading.integer != 0 : r_shadow_bouncegrid_directionalshading.integer != 0) && allowdirectionalshading;
2467 settings.dlightparticlemultiplier = r_shadow_bouncegrid_dlightparticlemultiplier.value;
2468 settings.hitmodels = r_shadow_bouncegrid_hitmodels.integer != 0;
2469 settings.includedirectlighting = r_shadow_bouncegrid_includedirectlighting.integer != 0 || r_shadow_bouncegrid.integer == 2;
2470 settings.lightradiusscale = (r_shadow_bouncegrid_static.integer != 0 ? r_shadow_bouncegrid_static_lightradiusscale.value : r_shadow_bouncegrid_lightradiusscale.value);
2471 settings.maxbounce = (r_shadow_bouncegrid_static.integer != 0 ? r_shadow_bouncegrid_static_maxbounce.integer : r_shadow_bouncegrid_maxbounce.integer);
2472 settings.particlebounceintensity = r_shadow_bouncegrid_particlebounceintensity.value;
2473 settings.particleintensity = r_shadow_bouncegrid_particleintensity.value * 16384.0f * (settings.directionalshading ? 4.0f : 1.0f) / (r_shadow_bouncegrid_spacing.value * r_shadow_bouncegrid_spacing.value);
2474 settings.photons = r_shadow_bouncegrid_static.integer ? r_shadow_bouncegrid_static_photons.integer : r_shadow_bouncegrid_photons.integer;
2475 settings.spacing[0] = r_shadow_bouncegrid_spacing.value;
2476 settings.spacing[1] = r_shadow_bouncegrid_spacing.value;
2477 settings.spacing[2] = r_shadow_bouncegrid_spacing.value;
2478 settings.stablerandom = r_shadow_bouncegrid_stablerandom.integer;
2480 // bound the values for sanity
2481 settings.photons = bound(1, settings.photons, 1048576);
2482 settings.lightradiusscale = bound(0.0001f, settings.lightradiusscale, 1024.0f);
2483 settings.maxbounce = bound(0, settings.maxbounce, 16);
2484 settings.spacing[0] = bound(1, settings.spacing[0], 512);
2485 settings.spacing[1] = bound(1, settings.spacing[1], 512);
2486 settings.spacing[2] = bound(1, settings.spacing[2], 512);
2488 // get the spacing values
2489 spacing[0] = settings.spacing[0];
2490 spacing[1] = settings.spacing[1];
2491 spacing[2] = settings.spacing[2];
2492 ispacing[0] = 1.0f / spacing[0];
2493 ispacing[1] = 1.0f / spacing[1];
2494 ispacing[2] = 1.0f / spacing[2];
2496 // calculate texture size enclosing entire world bounds at the spacing
2497 VectorMA(r_refdef.scene.worldmodel->normalmins, -2.0f, spacing, mins);
2498 VectorMA(r_refdef.scene.worldmodel->normalmaxs, 2.0f, spacing, maxs);
2499 VectorSubtract(maxs, mins, size);
2500 // now we can calculate the resolution we want
2501 c[0] = (int)floor(size[0] / spacing[0] + 0.5f);
2502 c[1] = (int)floor(size[1] / spacing[1] + 0.5f);
2503 c[2] = (int)floor(size[2] / spacing[2] + 0.5f);
2504 // figure out the exact texture size (honoring power of 2 if required)
2505 c[0] = bound(4, c[0], (int)vid.maxtexturesize_3d);
2506 c[1] = bound(4, c[1], (int)vid.maxtexturesize_3d);
2507 c[2] = bound(4, c[2], (int)vid.maxtexturesize_3d);
2508 if (vid.support.arb_texture_non_power_of_two)
2510 resolution[0] = c[0];
2511 resolution[1] = c[1];
2512 resolution[2] = c[2];
2516 for (resolution[0] = 4;resolution[0] < c[0];resolution[0]*=2) ;
2517 for (resolution[1] = 4;resolution[1] < c[1];resolution[1]*=2) ;
2518 for (resolution[2] = 4;resolution[2] < c[2];resolution[2]*=2) ;
2520 size[0] = spacing[0] * resolution[0];
2521 size[1] = spacing[1] * resolution[1];
2522 size[2] = spacing[2] * resolution[2];
2524 // if dynamic we may or may not want to use the world bounds
2525 // if the dynamic size is smaller than the world bounds, use it instead
2526 if (!settings.staticmode && (r_shadow_bouncegrid_x.integer * r_shadow_bouncegrid_y.integer * r_shadow_bouncegrid_z.integer < resolution[0] * resolution[1] * resolution[2]))
2528 // we know the resolution we want
2529 c[0] = r_shadow_bouncegrid_x.integer;
2530 c[1] = r_shadow_bouncegrid_y.integer;
2531 c[2] = r_shadow_bouncegrid_z.integer;
2532 // now we can calculate the texture size (power of 2 if required)
2533 c[0] = bound(4, c[0], (int)vid.maxtexturesize_3d);
2534 c[1] = bound(4, c[1], (int)vid.maxtexturesize_3d);
2535 c[2] = bound(4, c[2], (int)vid.maxtexturesize_3d);
2536 if (vid.support.arb_texture_non_power_of_two)
2538 resolution[0] = c[0];
2539 resolution[1] = c[1];
2540 resolution[2] = c[2];
2544 for (resolution[0] = 4;resolution[0] < c[0];resolution[0]*=2) ;
2545 for (resolution[1] = 4;resolution[1] < c[1];resolution[1]*=2) ;
2546 for (resolution[2] = 4;resolution[2] < c[2];resolution[2]*=2) ;
2548 size[0] = spacing[0] * resolution[0];
2549 size[1] = spacing[1] * resolution[1];
2550 size[2] = spacing[2] * resolution[2];
2551 // center the rendering on the view
2552 mins[0] = floor(r_refdef.view.origin[0] * ispacing[0] + 0.5f) * spacing[0] - 0.5f * size[0];
2553 mins[1] = floor(r_refdef.view.origin[1] * ispacing[1] + 0.5f) * spacing[1] - 0.5f * size[1];
2554 mins[2] = floor(r_refdef.view.origin[2] * ispacing[2] + 0.5f) * spacing[2] - 0.5f * size[2];
2557 // recalculate the maxs in case the resolution was not satisfactory
2558 VectorAdd(mins, size, maxs);
2560 // if all the settings seem identical to the previous update, return
2561 if (r_shadow_bouncegridtexture && (settings.staticmode || realtime < r_shadow_bouncegridtime + r_shadow_bouncegrid_updateinterval.value) && !memcmp(&r_shadow_bouncegridsettings, &settings, sizeof(settings)))
2564 // store the new settings
2565 r_shadow_bouncegridsettings = settings;
2567 pixelbands = settings.directionalshading ? 8 : 1;
2568 pixelsperband = resolution[0]*resolution[1]*resolution[2];
2569 numpixels = pixelsperband*pixelbands;
2571 // we're going to update the bouncegrid, update the matrix...
2572 memset(m, 0, sizeof(m));
2573 m[0] = 1.0f / size[0];
2574 m[3] = -mins[0] * m[0];
2575 m[5] = 1.0f / size[1];
2576 m[7] = -mins[1] * m[5];
2577 m[10] = 1.0f / size[2];
2578 m[11] = -mins[2] * m[10];
2580 Matrix4x4_FromArrayFloatD3D(&r_shadow_bouncegridmatrix, m);
2581 // reallocate pixels for this update if needed...
2582 if (r_shadow_bouncegridnumpixels != numpixels || !r_shadow_bouncegridpixels || !r_shadow_bouncegridhighpixels)
2584 if (r_shadow_bouncegridtexture)
2586 R_FreeTexture(r_shadow_bouncegridtexture);
2587 r_shadow_bouncegridtexture = NULL;
2589 r_shadow_bouncegridpixels = (unsigned char *)Mem_Realloc(r_main_mempool, r_shadow_bouncegridpixels, numpixels * sizeof(unsigned char[4]));
2590 r_shadow_bouncegridhighpixels = (float *)Mem_Realloc(r_main_mempool, r_shadow_bouncegridhighpixels, numpixels * sizeof(float[4]));
2592 r_shadow_bouncegridnumpixels = numpixels;
2593 pixels = r_shadow_bouncegridpixels;
2594 highpixels = r_shadow_bouncegridhighpixels;
2595 x = pixelsperband*4;
2596 for (pixelband = 0;pixelband < pixelbands;pixelband++)
2599 memset(pixels + pixelband * x, 128, x);
2601 memset(pixels + pixelband * x, 0, x);
2603 memset(highpixels, 0, numpixels * sizeof(float[4]));
2604 // figure out what we want to interact with
2605 if (settings.hitmodels)
2606 hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY;// | SUPERCONTENTS_LIQUIDSMASK;
2608 hitsupercontentsmask = SUPERCONTENTS_SOLID;// | SUPERCONTENTS_LIQUIDSMASK;
2609 maxbounce = settings.maxbounce;
2610 // clear variables that produce warnings otherwise
2611 memset(splatcolor, 0, sizeof(splatcolor));
2612 // iterate world rtlights
2613 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
2614 range1 = settings.staticmode ? 0 : r_refdef.scene.numlights;
2615 range2 = range + range1;
2617 for (lightindex = 0;lightindex < range2;lightindex++)
2619 if (lightindex < range)
2621 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2624 rtlight = &light->rtlight;
2625 VectorClear(rtlight->photoncolor);
2626 rtlight->photons = 0;
2627 if (!(light->flags & flag))
2629 if (settings.staticmode)
2631 // when static, we skip styled lights because they tend to change...
2632 if (rtlight->style > 0 && r_shadow_bouncegrid.integer != 2)
2638 rtlight = r_refdef.scene.lights[lightindex - range];
2639 VectorClear(rtlight->photoncolor);
2640 rtlight->photons = 0;
2642 // draw only visible lights (major speedup)
2643 radius = rtlight->radius * settings.lightradiusscale;
2644 cullmins[0] = rtlight->shadoworigin[0] - radius;
2645 cullmins[1] = rtlight->shadoworigin[1] - radius;
2646 cullmins[2] = rtlight->shadoworigin[2] - radius;
2647 cullmaxs[0] = rtlight->shadoworigin[0] + radius;
2648 cullmaxs[1] = rtlight->shadoworigin[1] + radius;
2649 cullmaxs[2] = rtlight->shadoworigin[2] + radius;
2650 w = r_shadow_lightintensityscale.value * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2651 if (!settings.staticmode)
2653 if (R_CullBox(cullmins, cullmaxs))
2655 if (r_refdef.scene.worldmodel
2656 && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs
2657 && !r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, cullmins, cullmaxs))
2659 if (w * VectorLength2(rtlight->color) == 0.0f)
2662 // a light that does not emit any light before style is applied, can be
2663 // skipped entirely (it may just be a corona)
2664 if (rtlight->radius == 0.0f || VectorLength2(rtlight->color) == 0.0f)
2666 w *= ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1);
2667 VectorScale(rtlight->color, w, rtlight->photoncolor);
2668 //if (!VectorLength2(rtlight->photoncolor))
2670 // shoot particles from this light
2671 // use a calculation for the number of particles that will not
2672 // vary with lightstyle, otherwise we get randomized particle
2673 // distribution, the seeded random is only consistent for a
2674 // consistent number of particles on this light...
2675 s = rtlight->radius;
2676 lightintensity = VectorLength(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2677 if (lightindex >= range)
2678 lightintensity *= settings.dlightparticlemultiplier;
2679 rtlight->photons = bound(0.0f, lightintensity * s * s, MAXBOUNCEGRIDPARTICLESPERLIGHT);
2680 photoncount += rtlight->photons;
2681 // if the lightstyle happens to be off right now, we can skip actually
2682 // firing the photons, but we did have to count them in the total.
2683 if (VectorLength2(rtlight->photoncolor) == 0.0f)
2684 rtlight->photons = 0;
2686 photonscaling = (float)settings.photons / max(1, photoncount);
2687 photonresidual = 0.0f;
2688 for (lightindex = 0;lightindex < range2;lightindex++)
2690 if (lightindex < range)
2692 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2695 rtlight = &light->rtlight;
2698 rtlight = r_refdef.scene.lights[lightindex - range];
2699 // skip a light with no photons
2700 if (rtlight->photons == 0.0f)
2702 photonresidual += rtlight->photons * photonscaling;
2703 shootparticles = (int)floor(photonresidual);
2704 if (!shootparticles)
2706 photonresidual -= shootparticles;
2707 radius = rtlight->radius * settings.lightradiusscale;
2708 s = settings.particleintensity / shootparticles;
2709 VectorScale(rtlight->photoncolor, s, baseshotcolor);
2710 r_refdef.stats[r_stat_bouncegrid_lights]++;
2711 r_refdef.stats[r_stat_bouncegrid_particles] += shootparticles;
2712 for (shotparticles = 0;shotparticles < shootparticles;shotparticles++)
2714 if (settings.stablerandom > 0)
2715 seed = lightindex * 11937 + shotparticles;
2716 VectorCopy(baseshotcolor, shotcolor);
2717 VectorCopy(rtlight->shadoworigin, clipstart);
2718 if (settings.stablerandom < 0)
2719 VectorRandom(clipend);
2721 VectorCheeseRandom(clipend);
2722 VectorMA(clipstart, radius, clipend, clipend);
2723 for (bouncecount = 0;;bouncecount++)
2725 r_refdef.stats[r_stat_bouncegrid_traces]++;
2726 //r_refdef.scene.worldmodel->TraceLineAgainstSurfaces(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace, clipstart, clipend, hitsupercontentsmask);
2727 //r_refdef.scene.worldmodel->TraceLine(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace2, clipstart, clipend, hitsupercontentsmask);
2728 if (settings.staticmode)
2730 // static mode fires a LOT of rays but none of them are identical, so they are not cached
2731 cliptrace = CL_TraceLine(clipstart, clipend, settings.staticmode ? MOVE_WORLDONLY : (settings.hitmodels ? MOVE_HITMODEL : MOVE_NOMONSTERS), NULL, hitsupercontentsmask, collision_extendmovelength.value, true, false, NULL, true, true);
2735 // dynamic mode fires many rays and most will match the cache from the previous frame
2736 cliptrace = CL_Cache_TraceLineSurfaces(clipstart, clipend, settings.staticmode ? MOVE_WORLDONLY : (settings.hitmodels ? MOVE_HITMODEL : MOVE_NOMONSTERS), hitsupercontentsmask);
2738 if (bouncecount > 0 || settings.includedirectlighting)
2740 // calculate second order spherical harmonics values (average, slopeX, slopeY, slopeZ)
2741 // accumulate average shotcolor
2742 w = VectorLength(shotcolor);
2743 splatcolor[ 0] = shotcolor[0];
2744 splatcolor[ 1] = shotcolor[1];
2745 splatcolor[ 2] = shotcolor[2];
2746 splatcolor[ 3] = 0.0f;
2749 VectorSubtract(clipstart, cliptrace.endpos, clipdiff);
2750 VectorNormalize(clipdiff);
2751 // store bentnormal in case the shader has a use for it
2752 splatcolor[ 4] = clipdiff[0] * w;
2753 splatcolor[ 5] = clipdiff[1] * w;
2754 splatcolor[ 6] = clipdiff[2] * w;
2756 // accumulate directional contributions (+X, +Y, +Z, -X, -Y, -Z)
2757 splatcolor[ 8] = shotcolor[0] * max(0.0f, clipdiff[0]);
2758 splatcolor[ 9] = shotcolor[0] * max(0.0f, clipdiff[1]);
2759 splatcolor[10] = shotcolor[0] * max(0.0f, clipdiff[2]);
2760 splatcolor[11] = 0.0f;
2761 splatcolor[12] = shotcolor[1] * max(0.0f, clipdiff[0]);
2762 splatcolor[13] = shotcolor[1] * max(0.0f, clipdiff[1]);
2763 splatcolor[14] = shotcolor[1] * max(0.0f, clipdiff[2]);
2764 splatcolor[15] = 0.0f;
2765 splatcolor[16] = shotcolor[2] * max(0.0f, clipdiff[0]);
2766 splatcolor[17] = shotcolor[2] * max(0.0f, clipdiff[1]);
2767 splatcolor[18] = shotcolor[2] * max(0.0f, clipdiff[2]);
2768 splatcolor[19] = 0.0f;
2769 splatcolor[20] = shotcolor[0] * max(0.0f, -clipdiff[0]);
2770 splatcolor[21] = shotcolor[0] * max(0.0f, -clipdiff[1]);
2771 splatcolor[22] = shotcolor[0] * max(0.0f, -clipdiff[2]);
2772 splatcolor[23] = 0.0f;
2773 splatcolor[24] = shotcolor[1] * max(0.0f, -clipdiff[0]);
2774 splatcolor[25] = shotcolor[1] * max(0.0f, -clipdiff[1]);
2775 splatcolor[26] = shotcolor[1] * max(0.0f, -clipdiff[2]);
2776 splatcolor[27] = 0.0f;
2777 splatcolor[28] = shotcolor[2] * max(0.0f, -clipdiff[0]);
2778 splatcolor[29] = shotcolor[2] * max(0.0f, -clipdiff[1]);
2779 splatcolor[30] = shotcolor[2] * max(0.0f, -clipdiff[2]);
2780 splatcolor[31] = 0.0f;
2782 // calculate the number of steps we need to traverse this distance
2783 VectorSubtract(cliptrace.endpos, clipstart, stepdelta);
2784 numsteps = (int)(VectorLength(stepdelta) * ispacing[0]);
2785 numsteps = bound(1, numsteps, 1024);
2786 w = 1.0f / numsteps;
2787 VectorScale(stepdelta, w, stepdelta);
2788 VectorMA(clipstart, 0.5f, stepdelta, steppos);
2789 for (step = 0;step < numsteps;step++)
2791 r_refdef.stats[r_stat_bouncegrid_splats]++;
2792 // figure out which texture pixel this is in
2793 texlerp[1][0] = ((steppos[0] - mins[0]) * ispacing[0]) - 0.5f;
2794 texlerp[1][1] = ((steppos[1] - mins[1]) * ispacing[1]) - 0.5f;
2795 texlerp[1][2] = ((steppos[2] - mins[2]) * ispacing[2]) - 0.5f;
2796 tex[0] = (int)floor(texlerp[1][0]);
2797 tex[1] = (int)floor(texlerp[1][1]);
2798 tex[2] = (int)floor(texlerp[1][2]);
2799 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)
2801 // it is within bounds... do the real work now
2802 // calculate the lerp factors
2803 texlerp[1][0] -= tex[0];
2804 texlerp[1][1] -= tex[1];
2805 texlerp[1][2] -= tex[2];
2806 texlerp[0][0] = 1.0f - texlerp[1][0];
2807 texlerp[0][1] = 1.0f - texlerp[1][1];
2808 texlerp[0][2] = 1.0f - texlerp[1][2];
2809 // calculate individual pixel indexes and weights
2810 pixelindex[0] = (((tex[2] )*resolution[1]+tex[1] )*resolution[0]+tex[0] );pixelweight[0] = (texlerp[0][0]*texlerp[0][1]*texlerp[0][2]);
2811 pixelindex[1] = (((tex[2] )*resolution[1]+tex[1] )*resolution[0]+tex[0]+1);pixelweight[1] = (texlerp[1][0]*texlerp[0][1]*texlerp[0][2]);
2812 pixelindex[2] = (((tex[2] )*resolution[1]+tex[1]+1)*resolution[0]+tex[0] );pixelweight[2] = (texlerp[0][0]*texlerp[1][1]*texlerp[0][2]);
2813 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]);
2814 pixelindex[4] = (((tex[2]+1)*resolution[1]+tex[1] )*resolution[0]+tex[0] );pixelweight[4] = (texlerp[0][0]*texlerp[0][1]*texlerp[1][2]);
2815 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]);
2816 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]);
2817 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]);
2818 // update the 8 pixels...
2819 for (pixelband = 0;pixelband < pixelbands;pixelband++)
2821 for (corner = 0;corner < 8;corner++)
2823 // calculate address for pixel
2824 w = pixelweight[corner];
2825 pixel = pixels + 4 * pixelindex[corner] + pixelband * pixelsperband * 4;
2826 highpixel = highpixels + 4 * pixelindex[corner] + pixelband * pixelsperband * 4;
2827 // add to the high precision pixel color
2828 highpixel[0] += (splatcolor[pixelband*4+0]*w);
2829 highpixel[1] += (splatcolor[pixelband*4+1]*w);
2830 highpixel[2] += (splatcolor[pixelband*4+2]*w);
2831 highpixel[3] += (splatcolor[pixelband*4+3]*w);
2832 // flag the low precision pixel as needing to be updated
2834 // advance to next band of coefficients
2835 //pixel += pixelsperband*4;
2836 //highpixel += pixelsperband*4;
2840 VectorAdd(steppos, stepdelta, steppos);
2843 if (cliptrace.fraction >= 1.0f)
2845 r_refdef.stats[r_stat_bouncegrid_hits]++;
2846 if (bouncecount >= maxbounce)
2848 // scale down shot color by bounce intensity and texture color (or 50% if no texture reported)
2849 // also clamp the resulting color to never add energy, even if the user requests extreme values
2850 if (cliptrace.hittexture && cliptrace.hittexture->currentskinframe)
2851 VectorCopy(cliptrace.hittexture->currentskinframe->avgcolor, surfcolor);
2853 VectorSet(surfcolor, 0.5f, 0.5f, 0.5f);
2854 VectorScale(surfcolor, settings.particlebounceintensity, surfcolor);
2855 surfcolor[0] = min(surfcolor[0], 1.0f);
2856 surfcolor[1] = min(surfcolor[1], 1.0f);
2857 surfcolor[2] = min(surfcolor[2], 1.0f);
2858 VectorMultiply(shotcolor, surfcolor, shotcolor);
2859 if (VectorLength2(baseshotcolor) == 0.0f)
2861 r_refdef.stats[r_stat_bouncegrid_bounces]++;
2862 if (settings.bounceanglediffuse)
2864 // random direction, primarily along plane normal
2865 s = VectorDistance(cliptrace.endpos, clipend);
2866 if (settings.stablerandom < 0)
2867 VectorRandom(clipend);
2869 VectorCheeseRandom(clipend);
2870 VectorMA(cliptrace.plane.normal, 0.95f, clipend, clipend);
2871 VectorNormalize(clipend);
2872 VectorScale(clipend, s, clipend);
2876 // reflect the remaining portion of the line across plane normal
2877 VectorSubtract(clipend, cliptrace.endpos, clipdiff);
2878 VectorReflect(clipdiff, 1.0, cliptrace.plane.normal, clipend);
2880 // calculate the new line start and end
2881 VectorCopy(cliptrace.endpos, clipstart);
2882 VectorAdd(clipstart, clipend, clipend);
2886 // generate pixels array from highpixels array
2887 // skip first and last columns, rows, and layers as these are blank
2888 // the pixel[3] value was written above, so we can use it to detect only pixels that need to be calculated
2889 for (pixelband = 0;pixelband < pixelbands;pixelband++)
2891 for (z = 1;z < resolution[2]-1;z++)
2893 for (y = 1;y < resolution[1]-1;y++)
2895 for (x = 1, pixelindex[0] = ((pixelband*resolution[2]+z)*resolution[1]+y)*resolution[0]+x, pixel = pixels + 4*pixelindex[0], highpixel = highpixels + 4*pixelindex[0];x < resolution[0]-1;x++, pixel += 4, highpixel += 4)
2897 // only convert pixels that were hit by photons
2898 if (pixel[3] == 255)
2900 // normalize the bentnormal...
2903 VectorNormalize(highpixel);
2904 c[0] = (int)(highpixel[0]*128.0f+128.0f);
2905 c[1] = (int)(highpixel[1]*128.0f+128.0f);
2906 c[2] = (int)(highpixel[2]*128.0f+128.0f);
2907 c[3] = (int)(highpixel[3]*128.0f+128.0f);
2911 c[0] = (int)(highpixel[0]*256.0f);
2912 c[1] = (int)(highpixel[1]*256.0f);
2913 c[2] = (int)(highpixel[2]*256.0f);
2914 c[3] = (int)(highpixel[3]*256.0f);
2916 pixel[2] = (unsigned char)bound(0, c[0], 255);
2917 pixel[1] = (unsigned char)bound(0, c[1], 255);
2918 pixel[0] = (unsigned char)bound(0, c[2], 255);
2919 pixel[3] = (unsigned char)bound(0, c[3], 255);
2925 if (r_shadow_bouncegridtexture && r_shadow_bouncegridresolution[0] == resolution[0] && r_shadow_bouncegridresolution[1] == resolution[1] && r_shadow_bouncegridresolution[2] == resolution[2] && r_shadow_bouncegriddirectional == settings.directionalshading)
2926 R_UpdateTexture(r_shadow_bouncegridtexture, pixels, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
2929 VectorCopy(resolution, r_shadow_bouncegridresolution);
2930 r_shadow_bouncegriddirectional = settings.directionalshading;
2931 if (r_shadow_bouncegridtexture)
2932 R_FreeTexture(r_shadow_bouncegridtexture);
2933 r_shadow_bouncegridtexture = R_LoadTexture3D(r_shadow_texturepool, "bouncegrid", resolution[0], resolution[1], resolution[2]*pixelbands, pixels, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, 0, NULL);
2935 r_shadow_bouncegridtime = realtime;
2938 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
2940 R_Shadow_RenderMode_Reset();
2941 GL_BlendFunc(GL_ONE, GL_ONE);
2942 GL_DepthRange(0, 1);
2943 GL_DepthTest(r_showshadowvolumes.integer < 2);
2944 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
2945 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2946 GL_CullFace(GL_NONE);
2947 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
2950 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
2952 R_Shadow_RenderMode_Reset();
2953 GL_BlendFunc(GL_ONE, GL_ONE);
2954 GL_DepthRange(0, 1);
2955 GL_DepthTest(r_showlighting.integer < 2);
2956 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2958 GL_DepthFunc(GL_EQUAL);
2959 R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2960 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2963 void R_Shadow_RenderMode_End(void)
2965 R_Shadow_RenderMode_Reset();
2966 R_Shadow_RenderMode_ActiveLight(NULL);
2968 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2969 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2972 int bboxedges[12][2] =
2991 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2993 if (!r_shadow_scissor.integer || r_shadow_usingdeferredprepass || r_trippy.integer)
2995 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2996 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2997 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2998 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
3001 if(R_ScissorForBBox(mins, maxs, r_shadow_lightscissor))
3002 return true; // invisible
3003 if(r_shadow_lightscissor[0] != r_refdef.view.viewport.x
3004 || r_shadow_lightscissor[1] != r_refdef.view.viewport.y
3005 || r_shadow_lightscissor[2] != r_refdef.view.viewport.width
3006 || r_shadow_lightscissor[3] != r_refdef.view.viewport.height)
3007 r_refdef.stats[r_stat_lights_scissored]++;
3011 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, const float *diffusecolor, const float *ambientcolor)
3014 const float *vertex3f;
3015 const float *normal3f;
3017 float dist, dot, distintensity, shadeintensity, v[3], n[3];
3018 switch (r_shadow_rendermode)
3020 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
3021 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
3022 if (VectorLength2(diffusecolor) > 0)
3024 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)
3026 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3027 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
3028 if ((dot = DotProduct(n, v)) < 0)
3030 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
3031 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
3034 VectorCopy(ambientcolor, color4f);
3035 if (r_refdef.fogenabled)
3038 f = RSurf_FogVertex(vertex3f);
3039 VectorScale(color4f, f, color4f);
3046 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
3048 VectorCopy(ambientcolor, color4f);
3049 if (r_refdef.fogenabled)
3052 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3053 f = RSurf_FogVertex(vertex3f);
3054 VectorScale(color4f + 4*i, f, color4f);
3060 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
3061 if (VectorLength2(diffusecolor) > 0)
3063 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)
3065 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3066 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3068 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
3069 if ((dot = DotProduct(n, v)) < 0)
3071 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
3072 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
3073 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
3074 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
3078 color4f[0] = ambientcolor[0] * distintensity;
3079 color4f[1] = ambientcolor[1] * distintensity;
3080 color4f[2] = ambientcolor[2] * distintensity;
3082 if (r_refdef.fogenabled)
3085 f = RSurf_FogVertex(vertex3f);
3086 VectorScale(color4f, f, color4f);
3090 VectorClear(color4f);
3096 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
3098 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3099 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3101 color4f[0] = ambientcolor[0] * distintensity;
3102 color4f[1] = ambientcolor[1] * distintensity;
3103 color4f[2] = ambientcolor[2] * distintensity;
3104 if (r_refdef.fogenabled)
3107 f = RSurf_FogVertex(vertex3f);
3108 VectorScale(color4f, f, color4f);
3112 VectorClear(color4f);
3117 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3118 if (VectorLength2(diffusecolor) > 0)
3120 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)
3122 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3123 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3125 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
3126 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
3127 if ((dot = DotProduct(n, v)) < 0)
3129 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
3130 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
3131 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
3132 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
3136 color4f[0] = ambientcolor[0] * distintensity;
3137 color4f[1] = ambientcolor[1] * distintensity;
3138 color4f[2] = ambientcolor[2] * distintensity;
3140 if (r_refdef.fogenabled)
3143 f = RSurf_FogVertex(vertex3f);
3144 VectorScale(color4f, f, color4f);
3148 VectorClear(color4f);
3154 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
3156 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3157 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3159 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
3160 color4f[0] = ambientcolor[0] * distintensity;
3161 color4f[1] = ambientcolor[1] * distintensity;
3162 color4f[2] = ambientcolor[2] * distintensity;
3163 if (r_refdef.fogenabled)
3166 f = RSurf_FogVertex(vertex3f);
3167 VectorScale(color4f, f, color4f);
3171 VectorClear(color4f);
3181 static void R_Shadow_RenderLighting_VisibleLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
3183 // used to display how many times a surface is lit for level design purposes
3184 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
3185 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
3189 static void R_Shadow_RenderLighting_Light_GLSL(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale, float specularscale)
3191 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
3192 R_SetupShader_Surface(lightcolor, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT, texturenumsurfaces, texturesurfacelist, NULL, false);
3196 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
3203 int newnumtriangles;
3207 int maxtriangles = 1024;
3208 int newelements[1024*3];
3209 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, diffusecolor2, ambientcolor2);
3210 for (renders = 0;renders < 4;renders++)
3215 newnumtriangles = 0;
3217 // due to low fillrate on the cards this vertex lighting path is
3218 // designed for, we manually cull all triangles that do not
3219 // contain a lit vertex
3220 // this builds batches of triangles from multiple surfaces and
3221 // renders them at once
3222 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
3224 if (VectorLength2(rsurface.passcolor4f + e[0] * 4) + VectorLength2(rsurface.passcolor4f + e[1] * 4) + VectorLength2(rsurface.passcolor4f + e[2] * 4) >= 0.01)
3226 if (newnumtriangles)
3228 newfirstvertex = min(newfirstvertex, e[0]);
3229 newlastvertex = max(newlastvertex, e[0]);
3233 newfirstvertex = e[0];
3234 newlastvertex = e[0];
3236 newfirstvertex = min(newfirstvertex, e[1]);
3237 newlastvertex = max(newlastvertex, e[1]);
3238 newfirstvertex = min(newfirstvertex, e[2]);
3239 newlastvertex = max(newlastvertex, e[2]);
3245 if (newnumtriangles >= maxtriangles)
3247 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
3248 newnumtriangles = 0;
3254 if (newnumtriangles >= 1)
3256 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
3259 // if we couldn't find any lit triangles, exit early
3262 // now reduce the intensity for the next overbright pass
3263 // we have to clamp to 0 here incase the drivers have improper
3264 // handling of negative colors
3265 // (some old drivers even have improper handling of >1 color)
3267 for (i = 0, c = rsurface.passcolor4f + 4 * firstvertex;i < numvertices;i++, c += 4)
3269 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
3271 c[0] = max(0, c[0] - 1);
3272 c[1] = max(0, c[1] - 1);
3273 c[2] = max(0, c[2] - 1);
3285 static void R_Shadow_RenderLighting_Light_Vertex(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale)
3287 // OpenGL 1.1 path (anything)
3288 float ambientcolorbase[3], diffusecolorbase[3];
3289 float ambientcolorpants[3], diffusecolorpants[3];
3290 float ambientcolorshirt[3], diffusecolorshirt[3];
3291 const float *surfacecolor = rsurface.texture->dlightcolor;
3292 const float *surfacepants = rsurface.colormap_pantscolor;
3293 const float *surfaceshirt = rsurface.colormap_shirtcolor;
3294 rtexture_t *basetexture = rsurface.texture->basetexture;
3295 rtexture_t *pantstexture = rsurface.texture->pantstexture;
3296 rtexture_t *shirttexture = rsurface.texture->shirttexture;
3297 qboolean dopants = pantstexture && VectorLength2(surfacepants) >= (1.0f / 1048576.0f);
3298 qboolean doshirt = shirttexture && VectorLength2(surfaceshirt) >= (1.0f / 1048576.0f);
3299 ambientscale *= 2 * r_refdef.view.colorscale;
3300 diffusescale *= 2 * r_refdef.view.colorscale;
3301 ambientcolorbase[0] = lightcolor[0] * ambientscale * surfacecolor[0];ambientcolorbase[1] = lightcolor[1] * ambientscale * surfacecolor[1];ambientcolorbase[2] = lightcolor[2] * ambientscale * surfacecolor[2];
3302 diffusecolorbase[0] = lightcolor[0] * diffusescale * surfacecolor[0];diffusecolorbase[1] = lightcolor[1] * diffusescale * surfacecolor[1];diffusecolorbase[2] = lightcolor[2] * diffusescale * surfacecolor[2];
3303 ambientcolorpants[0] = ambientcolorbase[0] * surfacepants[0];ambientcolorpants[1] = ambientcolorbase[1] * surfacepants[1];ambientcolorpants[2] = ambientcolorbase[2] * surfacepants[2];
3304 diffusecolorpants[0] = diffusecolorbase[0] * surfacepants[0];diffusecolorpants[1] = diffusecolorbase[1] * surfacepants[1];diffusecolorpants[2] = diffusecolorbase[2] * surfacepants[2];
3305 ambientcolorshirt[0] = ambientcolorbase[0] * surfaceshirt[0];ambientcolorshirt[1] = ambientcolorbase[1] * surfaceshirt[1];ambientcolorshirt[2] = ambientcolorbase[2] * surfaceshirt[2];
3306 diffusecolorshirt[0] = diffusecolorbase[0] * surfaceshirt[0];diffusecolorshirt[1] = diffusecolorbase[1] * surfaceshirt[1];diffusecolorshirt[2] = diffusecolorbase[2] * surfaceshirt[2];
3307 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | (diffusescale > 0 ? BATCHNEED_ARRAY_NORMAL : 0) | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
3308 rsurface.passcolor4f = (float *)R_FrameData_Alloc((rsurface.batchfirstvertex + rsurface.batchnumvertices) * sizeof(float[4]));
3309 R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3310 R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.passcolor4f, 0, 0);
3311 R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
3312 R_Mesh_TexBind(0, basetexture);
3313 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
3314 R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
3315 switch(r_shadow_rendermode)
3317 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
3318 R_Mesh_TexBind(1, r_shadow_attenuation3dtexture);
3319 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
3320 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
3321 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3323 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
3324 R_Mesh_TexBind(2, r_shadow_attenuation2dtexture);
3325 R_Mesh_TexMatrix(2, &rsurface.entitytoattenuationz);
3326 R_Mesh_TexCombine(2, GL_MODULATE, GL_MODULATE, 1, 1);
3327 R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3329 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
3330 R_Mesh_TexBind(1, r_shadow_attenuation2dtexture);
3331 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
3332 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
3333 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3335 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3340 //R_Mesh_TexBind(0, basetexture);
3341 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorbase, ambientcolorbase);
3344 R_Mesh_TexBind(0, pantstexture);
3345 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorpants, ambientcolorpants);
3349 R_Mesh_TexBind(0, shirttexture);
3350 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorshirt, ambientcolorshirt);
3354 extern cvar_t gl_lightmaps;
3355 void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
3357 float ambientscale, diffusescale, specularscale;
3359 float lightcolor[3];
3360 VectorCopy(rsurface.rtlight->currentcolor, lightcolor);
3361 ambientscale = rsurface.rtlight->ambientscale + rsurface.texture->rtlightambient;
3362 diffusescale = rsurface.rtlight->diffusescale * max(0, 1.0 - rsurface.texture->rtlightambient);
3363 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
3364 if (!r_shadow_usenormalmap.integer)
3366 ambientscale += 1.0f * diffusescale;
3370 if ((ambientscale + diffusescale) * VectorLength2(lightcolor) + specularscale * VectorLength2(lightcolor) < (1.0f / 1048576.0f))
3372 negated = (lightcolor[0] + lightcolor[1] + lightcolor[2] < 0) && vid.support.ext_blend_subtract;
3375 VectorNegate(lightcolor, lightcolor);
3376 GL_BlendEquationSubtract(true);
3378 RSurf_SetupDepthAndCulling();
3379 switch (r_shadow_rendermode)
3381 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
3382 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
3383 R_Shadow_RenderLighting_VisibleLighting(texturenumsurfaces, texturesurfacelist);
3385 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
3386 R_Shadow_RenderLighting_Light_GLSL(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale, specularscale);
3388 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
3389 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
3390 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
3391 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3392 R_Shadow_RenderLighting_Light_Vertex(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale);
3395 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
3399 GL_BlendEquationSubtract(false);
3402 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)
3404 matrix4x4_t tempmatrix = *matrix;
3405 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
3407 // if this light has been compiled before, free the associated data
3408 R_RTLight_Uncompile(rtlight);
3410 // clear it completely to avoid any lingering data
3411 memset(rtlight, 0, sizeof(*rtlight));
3413 // copy the properties
3414 rtlight->matrix_lighttoworld = tempmatrix;
3415 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
3416 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
3417 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
3418 VectorCopy(color, rtlight->color);
3419 rtlight->cubemapname[0] = 0;
3420 if (cubemapname && cubemapname[0])
3421 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
3422 rtlight->shadow = shadow;
3423 rtlight->corona = corona;
3424 rtlight->style = style;
3425 rtlight->isstatic = isstatic;
3426 rtlight->coronasizescale = coronasizescale;
3427 rtlight->ambientscale = ambientscale;
3428 rtlight->diffusescale = diffusescale;
3429 rtlight->specularscale = specularscale;
3430 rtlight->flags = flags;
3432 // compute derived data
3433 //rtlight->cullradius = rtlight->radius;
3434 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
3435 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3436 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3437 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3438 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3439 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3440 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3443 // compiles rtlight geometry
3444 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
3445 void R_RTLight_Compile(rtlight_t *rtlight)
3448 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
3449 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
3450 entity_render_t *ent = r_refdef.scene.worldentity;
3451 dp_model_t *model = r_refdef.scene.worldmodel;
3452 unsigned char *data;
3455 // compile the light
3456 rtlight->compiled = true;
3457 rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
3458 rtlight->static_numleafs = 0;
3459 rtlight->static_numleafpvsbytes = 0;
3460 rtlight->static_leaflist = NULL;
3461 rtlight->static_leafpvs = NULL;
3462 rtlight->static_numsurfaces = 0;
3463 rtlight->static_surfacelist = NULL;
3464 rtlight->static_shadowmap_receivers = 0x3F;
3465 rtlight->static_shadowmap_casters = 0x3F;
3466 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3467 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3468 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3469 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3470 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3471 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3473 if (model && model->GetLightInfo)
3475 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
3476 r_shadow_compilingrtlight = rtlight;
3477 R_FrameData_SetMark();
3478 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);
3479 R_FrameData_ReturnToMark();
3480 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
3481 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
3482 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3483 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
3484 rtlight->static_numsurfaces = numsurfaces;
3485 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
3486 rtlight->static_numleafs = numleafs;
3487 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
3488 rtlight->static_numleafpvsbytes = numleafpvsbytes;
3489 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
3490 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
3491 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
3492 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
3493 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3494 if (rtlight->static_numsurfaces)
3495 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3496 if (rtlight->static_numleafs)
3497 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3498 if (rtlight->static_numleafpvsbytes)
3499 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3500 if (rtlight->static_numshadowtrispvsbytes)
3501 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3502 if (rtlight->static_numlighttrispvsbytes)
3503 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3504 R_FrameData_SetMark();
3505 switch (rtlight->shadowmode)
3507 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
3508 if (model->CompileShadowMap && rtlight->shadow)
3509 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3512 if (model->CompileShadowVolume && rtlight->shadow)
3513 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3516 R_FrameData_ReturnToMark();
3517 // now we're done compiling the rtlight
3518 r_shadow_compilingrtlight = NULL;
3522 // use smallest available cullradius - box radius or light radius
3523 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3524 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3526 shadowzpasstris = 0;
3527 if (rtlight->static_meshchain_shadow_zpass)
3528 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
3529 shadowzpasstris += mesh->numtriangles;
3531 shadowzfailtris = 0;
3532 if (rtlight->static_meshchain_shadow_zfail)
3533 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
3534 shadowzfailtris += mesh->numtriangles;
3537 if (rtlight->static_numlighttrispvsbytes)
3538 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3539 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3543 if (rtlight->static_numshadowtrispvsbytes)
3544 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3545 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3548 if (developer_extra.integer)
3549 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);
3552 void R_RTLight_Uncompile(rtlight_t *rtlight)
3554 if (rtlight->compiled)
3556 if (rtlight->static_meshchain_shadow_zpass)
3557 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
3558 rtlight->static_meshchain_shadow_zpass = NULL;
3559 if (rtlight->static_meshchain_shadow_zfail)
3560 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
3561 rtlight->static_meshchain_shadow_zfail = NULL;
3562 if (rtlight->static_meshchain_shadow_shadowmap)
3563 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
3564 rtlight->static_meshchain_shadow_shadowmap = NULL;
3565 // these allocations are grouped
3566 if (rtlight->static_surfacelist)
3567 Mem_Free(rtlight->static_surfacelist);
3568 rtlight->static_numleafs = 0;
3569 rtlight->static_numleafpvsbytes = 0;
3570 rtlight->static_leaflist = NULL;
3571 rtlight->static_leafpvs = NULL;
3572 rtlight->static_numsurfaces = 0;
3573 rtlight->static_surfacelist = NULL;
3574 rtlight->static_numshadowtrispvsbytes = 0;
3575 rtlight->static_shadowtrispvs = NULL;
3576 rtlight->static_numlighttrispvsbytes = 0;
3577 rtlight->static_lighttrispvs = NULL;
3578 rtlight->compiled = false;
3582 void R_Shadow_UncompileWorldLights(void)
3586 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3587 for (lightindex = 0;lightindex < range;lightindex++)
3589 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3592 R_RTLight_Uncompile(&light->rtlight);
3596 static void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3600 // reset the count of frustum planes
3601 // see rtlight->cached_frustumplanes definition for how much this array
3603 rtlight->cached_numfrustumplanes = 0;
3605 if (r_trippy.integer)
3608 // haven't implemented a culling path for ortho rendering
3609 if (!r_refdef.view.useperspective)
3611 // check if the light is on screen and copy the 4 planes if it is
3612 for (i = 0;i < 4;i++)
3613 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3616 for (i = 0;i < 4;i++)
3617 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3622 // generate a deformed frustum that includes the light origin, this is
3623 // used to cull shadow casting surfaces that can not possibly cast a
3624 // shadow onto the visible light-receiving surfaces, which can be a
3627 // if the light origin is onscreen the result will be 4 planes exactly
3628 // if the light origin is offscreen on only one axis the result will
3629 // be exactly 5 planes (split-side case)
3630 // if the light origin is offscreen on two axes the result will be
3631 // exactly 4 planes (stretched corner case)
3632 for (i = 0;i < 4;i++)
3634 // quickly reject standard frustum planes that put the light
3635 // origin outside the frustum
3636 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3639 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3641 // if all the standard frustum planes were accepted, the light is onscreen
3642 // otherwise we need to generate some more planes below...
3643 if (rtlight->cached_numfrustumplanes < 4)
3645 // at least one of the stock frustum planes failed, so we need to
3646 // create one or two custom planes to enclose the light origin
3647 for (i = 0;i < 4;i++)
3649 // create a plane using the view origin and light origin, and a
3650 // single point from the frustum corner set
3651 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3652 VectorNormalize(plane.normal);
3653 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3654 // see if this plane is backwards and flip it if so
3655 for (j = 0;j < 4;j++)
3656 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3660 VectorNegate(plane.normal, plane.normal);
3662 // flipped plane, test again to see if it is now valid
3663 for (j = 0;j < 4;j++)
3664 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3666 // if the plane is still not valid, then it is dividing the
3667 // frustum and has to be rejected
3671 // we have created a valid plane, compute extra info
3672 PlaneClassify(&plane);
3674 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3676 // if we've found 5 frustum planes then we have constructed a
3677 // proper split-side case and do not need to keep searching for
3678 // planes to enclose the light origin
3679 if (rtlight->cached_numfrustumplanes == 5)
3687 for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
3689 plane = rtlight->cached_frustumplanes[i];
3690 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));
3695 // now add the light-space box planes if the light box is rotated, as any
3696 // caster outside the oriented light box is irrelevant (even if it passed
3697 // the worldspace light box, which is axial)
3698 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3700 for (i = 0;i < 6;i++)
3704 v[i >> 1] = (i & 1) ? -1 : 1;
3705 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3706 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3707 plane.dist = VectorNormalizeLength(plane.normal);
3708 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3709 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3715 // add the world-space reduced box planes
3716 for (i = 0;i < 6;i++)
3718 VectorClear(plane.normal);
3719 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3720 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
3721 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3730 // reduce all plane distances to tightly fit the rtlight cull box, which
3732 VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3733 VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3734 VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3735 VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3736 VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3737 VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3738 VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3739 VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3740 oldnum = rtlight->cached_numfrustumplanes;
3741 rtlight->cached_numfrustumplanes = 0;
3742 for (j = 0;j < oldnum;j++)
3744 // find the nearest point on the box to this plane
3745 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
3746 for (i = 1;i < 8;i++)
3748 dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
3749 if (bestdist > dist)
3752 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);
3753 // if the nearest point is near or behind the plane, we want this
3754 // plane, otherwise the plane is useless as it won't cull anything
3755 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
3757 PlaneClassify(&rtlight->cached_frustumplanes[j]);
3758 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
3765 static void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
3769 RSurf_ActiveWorldEntity();
3771 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3774 GL_CullFace(GL_NONE);
3775 mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3776 for (;mesh;mesh = mesh->next)
3778 if (!mesh->sidetotals[r_shadow_shadowmapside])
3780 r_refdef.stats[r_stat_lights_shadowtriangles] += mesh->sidetotals[r_shadow_shadowmapside];
3781 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer, mesh->vbooffset_vertex3f);
3782 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);
3786 else if (r_refdef.scene.worldentity->model)
3787 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);
3789 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3792 static void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3794 qboolean zpass = false;
3797 int surfacelistindex;
3798 msurface_t *surface;
3800 // if triangle neighbors are disabled, shadowvolumes are disabled
3801 if (r_refdef.scene.worldmodel->brush.shadowmesh ? !r_refdef.scene.worldmodel->brush.shadowmesh->neighbor3i : !r_refdef.scene.worldmodel->surfmesh.data_neighbor3i)
3804 RSurf_ActiveWorldEntity();
3806 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3809 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
3811 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
3812 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
3814 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
3815 for (;mesh;mesh = mesh->next)
3817 r_refdef.stats[r_stat_lights_shadowtriangles] += mesh->numtriangles;
3818 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer, mesh->vbooffset_vertex3f);
3819 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
3821 // increment stencil if frontface is infront of depthbuffer
3822 GL_CullFace(r_refdef.view.cullface_back);
3823 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
3824 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);
3825 // decrement stencil if backface is infront of depthbuffer
3826 GL_CullFace(r_refdef.view.cullface_front);
3827 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
3829 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
3831 // decrement stencil if backface is behind depthbuffer
3832 GL_CullFace(r_refdef.view.cullface_front);
3833 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
3834 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);
3835 // increment stencil if frontface is behind depthbuffer
3836 GL_CullFace(r_refdef.view.cullface_back);
3837 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
3839 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);
3843 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh)
3845 // use the shadow trispvs calculated earlier by GetLightInfo to cull world triangles on this dynamic light
3846 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
3847 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
3849 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
3850 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
3851 if (CHECKPVSBIT(trispvs, t))
3852 shadowmarklist[numshadowmark++] = t;
3854 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);
3856 else if (numsurfaces)
3858 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);
3861 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3864 static void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3866 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3867 vec_t relativeshadowradius;
3868 RSurf_ActiveModelEntity(ent, false, false, false);
3869 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3870 // we need to re-init the shader for each entity because the matrix changed
3871 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3872 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3873 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3874 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3875 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3876 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3877 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3878 switch (r_shadow_rendermode)
3880 case R_SHADOW_RENDERMODE_SHADOWMAP2D:
3881 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
3884 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3887 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3890 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3892 // set up properties for rendering light onto this entity
3893 RSurf_ActiveModelEntity(ent, true, true, false);
3894 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3895 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3896 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3897 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3900 static void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
3902 if (!r_refdef.scene.worldmodel->DrawLight)
3905 // set up properties for rendering light onto this entity
3906 RSurf_ActiveWorldEntity();
3907 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3908 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3909 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3910 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3912 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
3914 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3917 static void R_Shadow_DrawEntityLight(entity_render_t *ent)
3919 dp_model_t *model = ent->model;
3920 if (!model->DrawLight)
3923 R_Shadow_SetupEntityLight(ent);
3925 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3927 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3930 static void R_Shadow_PrepareLight(rtlight_t *rtlight)
3934 int numleafs, numsurfaces;
3935 int *leaflist, *surfacelist;
3936 unsigned char *leafpvs;
3937 unsigned char *shadowtrispvs;
3938 unsigned char *lighttrispvs;
3939 //unsigned char *surfacesides;
3940 int numlightentities;
3941 int numlightentities_noselfshadow;
3942 int numshadowentities;
3943 int numshadowentities_noselfshadow;
3944 static entity_render_t *lightentities[MAX_EDICTS];
3945 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3946 static entity_render_t *shadowentities[MAX_EDICTS];
3947 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3949 qboolean castshadows;
3951 rtlight->draw = false;
3952 rtlight->cached_numlightentities = 0;
3953 rtlight->cached_numlightentities_noselfshadow = 0;
3954 rtlight->cached_numshadowentities = 0;
3955 rtlight->cached_numshadowentities_noselfshadow = 0;
3956 rtlight->cached_numsurfaces = 0;
3957 rtlight->cached_lightentities = NULL;
3958 rtlight->cached_lightentities_noselfshadow = NULL;
3959 rtlight->cached_shadowentities = NULL;
3960 rtlight->cached_shadowentities_noselfshadow = NULL;
3961 rtlight->cached_shadowtrispvs = NULL;
3962 rtlight->cached_lighttrispvs = NULL;
3963 rtlight->cached_surfacelist = NULL;
3965 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3966 // skip lights that are basically invisible (color 0 0 0)
3967 nolight = VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f);
3969 // loading is done before visibility checks because loading should happen
3970 // all at once at the start of a level, not when it stalls gameplay.
3971 // (especially important to benchmarks)
3973 if (rtlight->isstatic && !nolight && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
3975 if (rtlight->compiled)
3976 R_RTLight_Uncompile(rtlight);
3977 R_RTLight_Compile(rtlight);
3981 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
3983 // look up the light style value at this time
3984 f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3985 VectorScale(rtlight->color, f, rtlight->currentcolor);
3987 if (rtlight->selected)
3989 f = 2 + sin(realtime * M_PI * 4.0);
3990 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3994 // if lightstyle is currently off, don't draw the light
3995 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3998 // skip processing on corona-only lights
4002 // if the light box is offscreen, skip it
4003 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
4006 VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
4007 VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
4009 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
4011 // don't allow lights to be drawn if using r_shadow_bouncegrid 2, except if we're using static bouncegrid where dynamic lights still need to draw
4012 if (r_shadow_bouncegrid.integer == 2 && (rtlight->isstatic || !r_shadow_bouncegrid_static.integer))
4015 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
4017 // compiled light, world available and can receive realtime lighting
4018 // retrieve leaf information
4019 numleafs = rtlight->static_numleafs;
4020 leaflist = rtlight->static_leaflist;
4021 leafpvs = rtlight->static_leafpvs;
4022 numsurfaces = rtlight->static_numsurfaces;
4023 surfacelist = rtlight->static_surfacelist;
4024 //surfacesides = NULL;
4025 shadowtrispvs = rtlight->static_shadowtrispvs;
4026 lighttrispvs = rtlight->static_lighttrispvs;
4028 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
4030 // dynamic light, world available and can receive realtime lighting
4031 // calculate lit surfaces and leafs
4032 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);
4033 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
4034 leaflist = r_shadow_buffer_leaflist;
4035 leafpvs = r_shadow_buffer_leafpvs;
4036 surfacelist = r_shadow_buffer_surfacelist;
4037 //surfacesides = r_shadow_buffer_surfacesides;
4038 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
4039 lighttrispvs = r_shadow_buffer_lighttrispvs;
4040 // if the reduced leaf bounds are offscreen, skip it
4041 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4052 //surfacesides = NULL;
4053 shadowtrispvs = NULL;
4054 lighttrispvs = NULL;
4056 // check if light is illuminating any visible leafs
4059 for (i = 0;i < numleafs;i++)
4060 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
4066 // make a list of lit entities and shadow casting entities
4067 numlightentities = 0;
4068 numlightentities_noselfshadow = 0;
4069 numshadowentities = 0;
4070 numshadowentities_noselfshadow = 0;
4072 // add dynamic entities that are lit by the light
4073 for (i = 0;i < r_refdef.scene.numentities;i++)
4076 entity_render_t *ent = r_refdef.scene.entities[i];
4078 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4080 // skip the object entirely if it is not within the valid
4081 // shadow-casting region (which includes the lit region)
4082 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
4084 if (!(model = ent->model))
4086 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
4088 // this entity wants to receive light, is visible, and is
4089 // inside the light box
4090 // TODO: check if the surfaces in the model can receive light
4091 // so now check if it's in a leaf seen by the light
4092 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))
4094 if (ent->flags & RENDER_NOSELFSHADOW)
4095 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
4097 lightentities[numlightentities++] = ent;
4098 // since it is lit, it probably also casts a shadow...
4099 // about the VectorDistance2 - light emitting entities should not cast their own shadow
4100 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
4101 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
4103 // note: exterior models without the RENDER_NOSELFSHADOW
4104 // flag still create a RENDER_NOSELFSHADOW shadow but
4105 // are lit normally, this means that they are
4106 // self-shadowing but do not shadow other
4107 // RENDER_NOSELFSHADOW entities such as the gun
4108 // (very weird, but keeps the player shadow off the gun)
4109 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
4110 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
4112 shadowentities[numshadowentities++] = ent;
4115 else if (ent->flags & RENDER_SHADOW)
4117 // this entity is not receiving light, but may still need to
4119 // TODO: check if the surfaces in the model can cast shadow
4120 // now check if it is in a leaf seen by the light
4121 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))
4123 // about the VectorDistance2 - light emitting entities should not cast their own shadow
4124 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
4125 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
4127 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
4128 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
4130 shadowentities[numshadowentities++] = ent;
4135 // return if there's nothing at all to light
4136 if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
4139 // count this light in the r_speeds
4140 r_refdef.stats[r_stat_lights]++;
4142 // flag it as worth drawing later
4143 rtlight->draw = true;
4145 // if we have shadows disabled, don't count the shadow entities, this way we don't do the R_AnimCache_GetEntity on each one
4146 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
4148 numshadowentities = numshadowentities_noselfshadow = 0;
4150 // cache all the animated entities that cast a shadow but are not visible
4151 for (i = 0;i < numshadowentities;i++)
4152 R_AnimCache_GetEntity(shadowentities[i], false, false);
4153 for (i = 0;i < numshadowentities_noselfshadow;i++)
4154 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
4156 // allocate some temporary memory for rendering this light later in the frame
4157 // reusable buffers need to be copied, static data can be used as-is
4158 rtlight->cached_numlightentities = numlightentities;
4159 rtlight->cached_numlightentities_noselfshadow = numlightentities_noselfshadow;
4160 rtlight->cached_numshadowentities = numshadowentities;
4161 rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
4162 rtlight->cached_numsurfaces = numsurfaces;
4163 rtlight->cached_lightentities = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
4164 rtlight->cached_lightentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
4165 rtlight->cached_shadowentities = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
4166 rtlight->cached_shadowentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
4167 if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
4169 int numshadowtrispvsbytes = (((r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles) + 7) >> 3);
4170 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
4171 rtlight->cached_shadowtrispvs = (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
4172 rtlight->cached_lighttrispvs = (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
4173 rtlight->cached_surfacelist = (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
4177 // compiled light data
4178 rtlight->cached_shadowtrispvs = shadowtrispvs;
4179 rtlight->cached_lighttrispvs = lighttrispvs;
4180 rtlight->cached_surfacelist = surfacelist;
4184 static void R_Shadow_DrawLight(rtlight_t *rtlight)
4188 unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
4189 int numlightentities;
4190 int numlightentities_noselfshadow;
4191 int numshadowentities;
4192 int numshadowentities_noselfshadow;
4193 entity_render_t **lightentities;
4194 entity_render_t **lightentities_noselfshadow;
4195 entity_render_t **shadowentities;
4196 entity_render_t **shadowentities_noselfshadow;
4198 static unsigned char entitysides[MAX_EDICTS];
4199 static unsigned char entitysides_noselfshadow[MAX_EDICTS];
4200 vec3_t nearestpoint;
4202 qboolean castshadows;
4205 // check if we cached this light this frame (meaning it is worth drawing)
4209 numlightentities = rtlight->cached_numlightentities;
4210 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
4211 numshadowentities = rtlight->cached_numshadowentities;
4212 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
4213 numsurfaces = rtlight->cached_numsurfaces;
4214 lightentities = rtlight->cached_lightentities;
4215 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
4216 shadowentities = rtlight->cached_shadowentities;
4217 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
4218 shadowtrispvs = rtlight->cached_shadowtrispvs;
4219 lighttrispvs = rtlight->cached_lighttrispvs;
4220 surfacelist = rtlight->cached_surfacelist;
4222 // set up a scissor rectangle for this light
4223 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4226 // don't let sound skip if going slow
4227 if (r_refdef.scene.extraupdate)
4230 // make this the active rtlight for rendering purposes
4231 R_Shadow_RenderMode_ActiveLight(rtlight);
4233 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
4235 // optionally draw visible shape of the shadow volumes
4236 // for performance analysis by level designers
4237 R_Shadow_RenderMode_VisibleShadowVolumes();
4239 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
4240 for (i = 0;i < numshadowentities;i++)
4241 R_Shadow_DrawEntityShadow(shadowentities[i]);
4242 for (i = 0;i < numshadowentities_noselfshadow;i++)
4243 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
4244 R_Shadow_RenderMode_VisibleLighting(false, false);
4247 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
4249 // optionally draw the illuminated areas
4250 // for performance analysis by level designers
4251 R_Shadow_RenderMode_VisibleLighting(false, false);
4253 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4254 for (i = 0;i < numlightentities;i++)
4255 R_Shadow_DrawEntityLight(lightentities[i]);
4256 for (i = 0;i < numlightentities_noselfshadow;i++)
4257 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4260 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
4262 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
4263 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
4264 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
4265 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
4267 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance/rtlight->radius));
4268 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
4269 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
4271 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
4277 int receivermask = 0;
4278 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
4279 Matrix4x4_Abs(&radiustolight);
4281 r_shadow_shadowmaplod = 0;
4282 for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
4283 if ((r_shadow_shadowmapmaxsize >> i) > lodlinear)
4284 r_shadow_shadowmaplod = i;
4286 size = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
4288 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
4290 surfacesides = NULL;
4293 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
4295 castermask = rtlight->static_shadowmap_casters;
4296 receivermask = rtlight->static_shadowmap_receivers;
4300 surfacesides = r_shadow_buffer_surfacesides;
4301 for(i = 0;i < numsurfaces;i++)
4303 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
4304 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4305 castermask |= surfacesides[i];
4306 receivermask |= surfacesides[i];
4310 if (receivermask < 0x3F)
4312 for (i = 0;i < numlightentities;i++)
4313 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4314 if (receivermask < 0x3F)
4315 for(i = 0; i < numlightentities_noselfshadow;i++)
4316 receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4319 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
4323 for (i = 0;i < numshadowentities;i++)
4324 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
4325 for (i = 0;i < numshadowentities_noselfshadow;i++)
4326 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
4329 //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
4331 // render shadow casters into 6 sided depth texture
4332 for (side = 0;side < 6;side++) if (receivermask & (1 << side))
4334 R_Shadow_RenderMode_ShadowMap(side, receivermask, size);
4335 if (! (castermask & (1 << side))) continue;
4337 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
4338 for (i = 0;i < numshadowentities;i++) if (entitysides[i] & (1 << side))
4339 R_Shadow_DrawEntityShadow(shadowentities[i]);
4342 if (numlightentities_noselfshadow)
4344 // render lighting using the depth texture as shadowmap
4345 // draw lighting in the unmasked areas
4346 R_Shadow_RenderMode_Lighting(false, false, true);
4347 for (i = 0;i < numlightentities_noselfshadow;i++)
4348 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4351 // render shadow casters into 6 sided depth texture
4352 if (numshadowentities_noselfshadow)
4354 for (side = 0;side < 6;side++) if ((receivermask & castermask) & (1 << side))
4356 R_Shadow_RenderMode_ShadowMap(side, 0, size);
4357 for (i = 0;i < numshadowentities_noselfshadow;i++) if (entitysides_noselfshadow[i] & (1 << side))
4358 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
4362 // render lighting using the depth texture as shadowmap
4363 // draw lighting in the unmasked areas
4364 R_Shadow_RenderMode_Lighting(false, false, true);
4365 // draw lighting in the unmasked areas
4367 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4368 for (i = 0;i < numlightentities;i++)
4369 R_Shadow_DrawEntityLight(lightentities[i]);
4371 else if (castshadows && vid.stencil)
4373 // draw stencil shadow volumes to mask off pixels that are in shadow
4374 // so that they won't receive lighting
4375 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
4376 R_Shadow_ClearStencil();
4379 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
4380 for (i = 0;i < numshadowentities;i++)
4381 R_Shadow_DrawEntityShadow(shadowentities[i]);
4383 // draw lighting in the unmasked areas
4384 R_Shadow_RenderMode_Lighting(true, false, false);
4385 for (i = 0;i < numlightentities_noselfshadow;i++)
4386 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4388 for (i = 0;i < numshadowentities_noselfshadow;i++)
4389 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
4391 // draw lighting in the unmasked areas
4392 R_Shadow_RenderMode_Lighting(true, false, false);
4394 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4395 for (i = 0;i < numlightentities;i++)
4396 R_Shadow_DrawEntityLight(lightentities[i]);
4400 // draw lighting in the unmasked areas
4401 R_Shadow_RenderMode_Lighting(false, false, false);
4403 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4404 for (i = 0;i < numlightentities;i++)
4405 R_Shadow_DrawEntityLight(lightentities[i]);
4406 for (i = 0;i < numlightentities_noselfshadow;i++)
4407 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4410 if (r_shadow_usingdeferredprepass)
4412 // when rendering deferred lighting, we simply rasterize the box
4413 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
4414 R_Shadow_RenderMode_DrawDeferredLight(false, true);
4415 else if (castshadows && vid.stencil)
4416 R_Shadow_RenderMode_DrawDeferredLight(true, false);
4418 R_Shadow_RenderMode_DrawDeferredLight(false, false);
4422 static void R_Shadow_FreeDeferred(void)
4424 R_Mesh_DestroyFramebufferObject(r_shadow_prepassgeometryfbo);
4425 r_shadow_prepassgeometryfbo = 0;
4427 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusespecularfbo);
4428 r_shadow_prepasslightingdiffusespecularfbo = 0;
4430 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusefbo);
4431 r_shadow_prepasslightingdiffusefbo = 0;
4433 if (r_shadow_prepassgeometrydepthbuffer)
4434 R_FreeTexture(r_shadow_prepassgeometrydepthbuffer);
4435 r_shadow_prepassgeometrydepthbuffer = NULL;
4437 if (r_shadow_prepassgeometrynormalmaptexture)
4438 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
4439 r_shadow_prepassgeometrynormalmaptexture = NULL;
4441 if (r_shadow_prepasslightingdiffusetexture)
4442 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
4443 r_shadow_prepasslightingdiffusetexture = NULL;
4445 if (r_shadow_prepasslightingspeculartexture)
4446 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
4447 r_shadow_prepasslightingspeculartexture = NULL;
4450 void R_Shadow_DrawPrepass(void)
4458 entity_render_t *ent;
4459 float clearcolor[4];
4461 R_Mesh_ResetTextureState();
4463 GL_ColorMask(1,1,1,1);
4464 GL_BlendFunc(GL_ONE, GL_ZERO);
4467 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4468 Vector4Set(clearcolor, 0.5f,0.5f,0.5f,1.0f);
4469 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4470 if (r_timereport_active)
4471 R_TimeReport("prepasscleargeom");
4473 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
4474 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
4475 if (r_timereport_active)
4476 R_TimeReport("prepassworld");
4478 for (i = 0;i < r_refdef.scene.numentities;i++)
4480 if (!r_refdef.viewcache.entityvisible[i])
4482 ent = r_refdef.scene.entities[i];
4483 if (ent->model && ent->model->DrawPrepass != NULL)
4484 ent->model->DrawPrepass(ent);
4487 if (r_timereport_active)
4488 R_TimeReport("prepassmodels");
4490 GL_DepthMask(false);
4491 GL_ColorMask(1,1,1,1);
4494 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4495 Vector4Set(clearcolor, 0, 0, 0, 0);
4496 GL_Clear(GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
4497 if (r_timereport_active)
4498 R_TimeReport("prepassclearlit");
4500 R_Shadow_RenderMode_Begin();
4502 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4503 if (r_shadow_debuglight.integer >= 0)
4505 lightindex = r_shadow_debuglight.integer;
4506 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4507 if (light && (light->flags & flag) && light->rtlight.draw)
4508 R_Shadow_DrawLight(&light->rtlight);
4512 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4513 for (lightindex = 0;lightindex < range;lightindex++)
4515 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4516 if (light && (light->flags & flag) && light->rtlight.draw)
4517 R_Shadow_DrawLight(&light->rtlight);
4520 if (r_refdef.scene.rtdlight)
4521 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4522 if (r_refdef.scene.lights[lnum]->draw)
4523 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4525 R_Shadow_RenderMode_End();
4527 if (r_timereport_active)
4528 R_TimeReport("prepasslights");
4531 void R_Shadow_DrawLightSprites(void);
4532 void R_Shadow_PrepareLights(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture)
4541 if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4) ||
4542 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
4543 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20) ||
4544 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
4545 r_shadow_shadowmapshadowsampler != (vid.support.arb_shadow && r_shadow_shadowmapping_useshadowsampler.integer) ||
4546 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
4547 r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16) ||
4548 r_shadow_shadowmapdepthtexture != r_fb.usedepthtextures)
4549 R_Shadow_FreeShadowMaps();
4551 r_shadow_fb_fbo = fbo;
4552 r_shadow_fb_depthtexture = depthtexture;
4553 r_shadow_fb_colortexture = colortexture;
4555 r_shadow_usingshadowmaportho = false;
4557 switch (vid.renderpath)
4559 case RENDERPATH_GL20:
4560 case RENDERPATH_D3D9:
4561 case RENDERPATH_D3D10:
4562 case RENDERPATH_D3D11:
4563 case RENDERPATH_SOFT:
4565 if (!r_shadow_deferred.integer || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_STENCIL || !vid.support.ext_framebuffer_object || vid.maxdrawbuffers < 2)
4567 r_shadow_usingdeferredprepass = false;
4568 if (r_shadow_prepass_width)
4569 R_Shadow_FreeDeferred();
4570 r_shadow_prepass_width = r_shadow_prepass_height = 0;
4574 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
4576 R_Shadow_FreeDeferred();
4578 r_shadow_usingdeferredprepass = true;
4579 r_shadow_prepass_width = vid.width;
4580 r_shadow_prepass_height = vid.height;
4581 r_shadow_prepassgeometrydepthbuffer = R_LoadTextureRenderBuffer(r_shadow_texturepool, "prepassgeometrydepthbuffer", vid.width, vid.height, TEXTYPE_DEPTHBUFFER24);
4582 r_shadow_prepassgeometrynormalmaptexture = R_LoadTexture2D(r_shadow_texturepool, "prepassgeometrynormalmap", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER32F, TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, -1, NULL);
4583 r_shadow_prepasslightingdiffusetexture = R_LoadTexture2D(r_shadow_texturepool, "prepasslightingdiffuse", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER16F, TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, -1, NULL);
4584 r_shadow_prepasslightingspeculartexture = R_LoadTexture2D(r_shadow_texturepool, "prepasslightingspecular", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER16F, TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, -1, NULL);
4586 // set up the geometry pass fbo (depth + normalmap)
4587 r_shadow_prepassgeometryfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4588 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4589 // render depth into a renderbuffer and other important properties into the normalmap texture
4591 // set up the lighting pass fbo (diffuse + specular)
4592 r_shadow_prepasslightingdiffusespecularfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4593 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4594 // render diffuse into one texture and specular into another,
4595 // with depth and normalmap bound as textures,
4596 // with depth bound as attachment as well
4598 // set up the lighting pass fbo (diffuse)
4599 r_shadow_prepasslightingdiffusefbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
4600 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
4601 // render diffuse into one texture,
4602 // with depth and normalmap bound as textures,
4603 // with depth bound as attachment as well
4607 case RENDERPATH_GL11:
4608 case RENDERPATH_GL13:
4609 case RENDERPATH_GLES1:
4610 case RENDERPATH_GLES2:
4611 r_shadow_usingdeferredprepass = false;
4615 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);
4617 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4618 if (r_shadow_debuglight.integer >= 0)
4620 lightindex = r_shadow_debuglight.integer;
4621 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4623 R_Shadow_PrepareLight(&light->rtlight);
4627 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4628 for (lightindex = 0;lightindex < range;lightindex++)
4630 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4631 if (light && (light->flags & flag))
4632 R_Shadow_PrepareLight(&light->rtlight);
4635 if (r_refdef.scene.rtdlight)
4637 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4638 R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
4640 else if(gl_flashblend.integer)
4642 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4644 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
4645 f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4646 VectorScale(rtlight->color, f, rtlight->currentcolor);
4650 if (r_editlights.integer)
4651 R_Shadow_DrawLightSprites();
4654 void R_Shadow_DrawLights(void)
4662 R_Shadow_RenderMode_Begin();
4664 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4665 if (r_shadow_debuglight.integer >= 0)
4667 lightindex = r_shadow_debuglight.integer;
4668 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4670 R_Shadow_DrawLight(&light->rtlight);
4674 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4675 for (lightindex = 0;lightindex < range;lightindex++)
4677 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4678 if (light && (light->flags & flag))
4679 R_Shadow_DrawLight(&light->rtlight);
4682 if (r_refdef.scene.rtdlight)
4683 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4684 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4686 R_Shadow_RenderMode_End();
4689 #define MAX_MODELSHADOWS 1024
4690 static int r_shadow_nummodelshadows;
4691 static entity_render_t *r_shadow_modelshadows[MAX_MODELSHADOWS];
4693 void R_Shadow_PrepareModelShadows(void)
4696 float scale, size, radius, dot1, dot2;
4697 prvm_vec3_t prvmshadowdir, prvmshadowfocus;
4698 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
4699 entity_render_t *ent;
4701 r_shadow_nummodelshadows = 0;
4702 if (!r_refdef.scene.numentities)
4705 switch (r_shadow_shadowmode)
4707 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4708 if (r_shadows.integer >= 2)
4711 case R_SHADOW_SHADOWMODE_STENCIL:
4714 for (i = 0;i < r_refdef.scene.numentities;i++)
4716 ent = r_refdef.scene.entities[i];
4717 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4719 if (r_shadow_nummodelshadows >= MAX_MODELSHADOWS)
4721 r_shadow_modelshadows[r_shadow_nummodelshadows++] = ent;
4722 R_AnimCache_GetEntity(ent, false, false);
4730 size = 2*r_shadow_shadowmapmaxsize;
4731 scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
4732 radius = 0.5f * size / scale;
4734 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
4735 VectorCopy(prvmshadowdir, shadowdir);
4736 VectorNormalize(shadowdir);
4737 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4738 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4739 if (fabs(dot1) <= fabs(dot2))
4740 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4742 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4743 VectorNormalize(shadowforward);
4744 CrossProduct(shadowdir, shadowforward, shadowright);
4745 Math_atov(r_shadows_focus.string, prvmshadowfocus);
4746 VectorCopy(prvmshadowfocus, shadowfocus);
4747 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4748 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4749 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4750 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4751 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4753 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4755 shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4756 shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4757 shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4758 shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4759 shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4760 shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4762 for (i = 0;i < r_refdef.scene.numentities;i++)
4764 ent = r_refdef.scene.entities[i];
4765 if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
4767 // cast shadows from anything of the map (submodels are optional)
4768 if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4770 if (r_shadow_nummodelshadows >= MAX_MODELSHADOWS)
4772 r_shadow_modelshadows[r_shadow_nummodelshadows++] = ent;
4773 R_AnimCache_GetEntity(ent, false, false);
4778 void R_DrawModelShadowMaps(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture)
4781 float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
4782 entity_render_t *ent;
4783 vec3_t relativelightorigin;
4784 vec3_t relativelightdirection, relativeforward, relativeright;
4785 vec3_t relativeshadowmins, relativeshadowmaxs;
4786 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
4787 prvm_vec3_t prvmshadowdir, prvmshadowfocus;
4789 matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
4790 r_viewport_t viewport;
4791 GLuint shadowfbo = 0;
4792 float clearcolor[4];
4794 if (!r_shadow_nummodelshadows)
4797 switch (r_shadow_shadowmode)
4799 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4805 r_shadow_fb_fbo = fbo;
4806 r_shadow_fb_depthtexture = depthtexture;
4807 r_shadow_fb_colortexture = colortexture;
4809 R_ResetViewRendering3D(fbo, depthtexture, colortexture);
4810 R_Shadow_RenderMode_Begin();
4811 R_Shadow_RenderMode_ActiveLight(NULL);
4813 switch (r_shadow_shadowmode)
4815 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4816 if (!r_shadow_shadowmap2ddepthtexture)
4817 R_Shadow_MakeShadowMap(0, r_shadow_shadowmapmaxsize);
4818 shadowfbo = r_shadow_fbo2d;
4819 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2ddepthtexture);
4820 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2ddepthtexture);
4821 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
4827 size = 2*r_shadow_shadowmapmaxsize;
4828 scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
4829 radius = 0.5f / scale;
4830 nearclip = -r_shadows_throwdistance.value;
4831 farclip = r_shadows_throwdistance.value;
4832 bias = (r_shadows_shadowmapbias.value < 0) ? r_shadow_shadowmapping_bias.value : r_shadows_shadowmapbias.value * r_shadow_shadowmapping_nearclip.value / (2 * r_shadows_throwdistance.value) * (1024.0f / size);
4834 r_shadow_shadowmap_parameters[0] = size;
4835 r_shadow_shadowmap_parameters[1] = size;
4836 r_shadow_shadowmap_parameters[2] = 1.0;
4837 r_shadow_shadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
4839 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
4840 VectorCopy(prvmshadowdir, shadowdir);
4841 VectorNormalize(shadowdir);
4842 Math_atov(r_shadows_focus.string, prvmshadowfocus);
4843 VectorCopy(prvmshadowfocus, shadowfocus);
4844 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4845 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4846 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4847 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4848 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4849 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4850 if (fabs(dot1) <= fabs(dot2))
4851 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4853 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4854 VectorNormalize(shadowforward);
4855 VectorM(scale, shadowforward, &m[0]);
4856 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4858 m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
4859 CrossProduct(shadowdir, shadowforward, shadowright);
4860 VectorM(scale, shadowright, &m[4]);
4861 m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
4862 VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
4863 m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
4864 Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
4865 Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
4866 R_Viewport_InitOrtho(&viewport, &cameramatrix, 0, 0, size, size, 0, 0, 1, 1, 0, -1, NULL);
4868 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4870 if (r_shadow_shadowmap2ddepthbuffer)
4871 R_Mesh_SetRenderTargets(shadowfbo, r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
4873 R_Mesh_SetRenderTargets(shadowfbo, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
4874 R_SetupShader_DepthOrShadow(true, r_shadow_shadowmap2ddepthbuffer != NULL, false); // FIXME test if we have a skeletal model?
4875 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
4878 R_SetViewport(&viewport);
4879 GL_Scissor(viewport.x, viewport.y, min(viewport.width + r_shadow_shadowmapborder, 2*r_shadow_shadowmapmaxsize), viewport.height + r_shadow_shadowmapborder);
4880 Vector4Set(clearcolor, 1,1,1,1);
4881 // in D3D9 we have to render to a color texture shadowmap
4882 // in GL we render directly to a depth texture only
4883 if (r_shadow_shadowmap2ddepthbuffer)
4884 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4886 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4887 // render into a slightly restricted region so that the borders of the
4888 // shadowmap area fade away, rather than streaking across everything
4889 // outside the usable area
4890 GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
4892 for (i = 0;i < r_shadow_nummodelshadows;i++)
4894 ent = r_shadow_modelshadows[i];
4895 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4896 Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
4897 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4898 Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
4899 Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
4900 relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4901 relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4902 relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4903 relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4904 relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4905 relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4906 RSurf_ActiveModelEntity(ent, false, false, false);
4907 ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
4908 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4914 unsigned char *rawpixels = Z_Malloc(viewport.width*viewport.height*4);
4916 qglReadPixels(viewport.x, viewport.y, viewport.width, viewport.height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, rawpixels);
4918 Image_WriteTGABGRA("r_shadows_2.tga", viewport.width, viewport.height, rawpixels);
4919 Cvar_SetValueQuick(&r_test, 0);
4924 R_Shadow_RenderMode_End();
4926 Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
4927 Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
4928 Matrix4x4_CreateScale3(&scalematrix, size, -size, 1);
4929 Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
4930 Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
4931 Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
4933 switch (vid.renderpath)
4935 case RENDERPATH_GL11:
4936 case RENDERPATH_GL13:
4937 case RENDERPATH_GL20:
4938 case RENDERPATH_SOFT:
4939 case RENDERPATH_GLES1:
4940 case RENDERPATH_GLES2:
4942 case RENDERPATH_D3D9:
4943 case RENDERPATH_D3D10:
4944 case RENDERPATH_D3D11:
4945 #ifdef MATRIX4x4_OPENGLORIENTATION
4946 r_shadow_shadowmapmatrix.m[0][0] *= -1.0f;
4947 r_shadow_shadowmapmatrix.m[0][1] *= -1.0f;
4948 r_shadow_shadowmapmatrix.m[0][2] *= -1.0f;
4949 r_shadow_shadowmapmatrix.m[0][3] *= -1.0f;
4951 r_shadow_shadowmapmatrix.m[0][0] *= -1.0f;
4952 r_shadow_shadowmapmatrix.m[1][0] *= -1.0f;
4953 r_shadow_shadowmapmatrix.m[2][0] *= -1.0f;
4954 r_shadow_shadowmapmatrix.m[3][0] *= -1.0f;
4959 r_shadow_usingshadowmaportho = true;
4960 switch (r_shadow_shadowmode)
4962 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4963 r_shadow_usingshadowmap2d = true;
4970 void R_DrawModelShadows(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture)
4973 float relativethrowdistance;
4974 entity_render_t *ent;
4975 vec3_t relativelightorigin;
4976 vec3_t relativelightdirection;
4977 vec3_t relativeshadowmins, relativeshadowmaxs;
4978 vec3_t tmp, shadowdir;
4979 prvm_vec3_t prvmshadowdir;
4981 if (!r_shadow_nummodelshadows || (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL && r_shadows.integer != 1))
4984 r_shadow_fb_fbo = fbo;
4985 r_shadow_fb_depthtexture = depthtexture;
4986 r_shadow_fb_colortexture = colortexture;
4988 R_ResetViewRendering3D(fbo, depthtexture, colortexture);
4989 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4990 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4991 R_Shadow_RenderMode_Begin();
4992 R_Shadow_RenderMode_ActiveLight(NULL);
4993 r_shadow_lightscissor[0] = r_refdef.view.x;
4994 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
4995 r_shadow_lightscissor[2] = r_refdef.view.width;
4996 r_shadow_lightscissor[3] = r_refdef.view.height;
4997 R_Shadow_RenderMode_StencilShadowVolumes(false);
5000 if (r_shadows.integer == 2)
5002 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
5003 VectorCopy(prvmshadowdir, shadowdir);
5004 VectorNormalize(shadowdir);
5007 R_Shadow_ClearStencil();
5009 for (i = 0;i < r_shadow_nummodelshadows;i++)
5011 ent = r_shadow_modelshadows[i];
5013 // cast shadows from anything of the map (submodels are optional)
5014 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
5015 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
5016 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
5017 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
5018 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
5021 if(ent->entitynumber != 0)
5023 if(ent->entitynumber >= MAX_EDICTS) // csqc entity
5025 // FIXME handle this
5026 VectorNegate(ent->modellight_lightdir, relativelightdirection);
5030 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
5031 int entnum, entnum2, recursion;
5032 entnum = entnum2 = ent->entitynumber;
5033 for(recursion = 32; recursion > 0; --recursion)
5035 entnum2 = cl.entities[entnum].state_current.tagentity;
5036 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
5041 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
5043 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
5044 // transform into modelspace of OUR entity
5045 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
5046 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
5049 VectorNegate(ent->modellight_lightdir, relativelightdirection);
5053 VectorNegate(ent->modellight_lightdir, relativelightdirection);
5056 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
5057 RSurf_ActiveModelEntity(ent, false, false, false);
5058 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
5059 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
5062 // not really the right mode, but this will disable any silly stencil features
5063 R_Shadow_RenderMode_End();
5065 // set up ortho view for rendering this pass
5066 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
5067 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5068 //GL_ScissorTest(true);
5069 //R_EntityMatrix(&identitymatrix);
5070 //R_Mesh_ResetTextureState();
5071 R_ResetViewRendering2D(fbo, depthtexture, colortexture);
5073 // set up a darkening blend on shadowed areas
5074 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5075 //GL_DepthRange(0, 1);
5076 //GL_DepthTest(false);
5077 //GL_DepthMask(false);
5078 //GL_PolygonOffset(0, 0);CHECKGLERROR
5079 GL_Color(0, 0, 0, r_shadows_darken.value);
5080 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5081 //GL_DepthFunc(GL_ALWAYS);
5082 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_NOTEQUAL, 128, 255);
5084 // apply the blend to the shadowed areas
5085 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, NULL);
5086 R_SetupShader_Generic_NoTexture(false, true);
5087 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5089 // restore the viewport
5090 R_SetViewport(&r_refdef.view.viewport);
5092 // restore other state to normal
5093 //R_Shadow_RenderMode_End();
5096 static void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
5099 vec3_t centerorigin;
5100 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5103 // if it's too close, skip it
5104 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
5106 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
5109 if (usequery && r_numqueries + 2 <= r_maxqueries)
5111 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
5112 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
5113 // 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
5114 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
5116 switch(vid.renderpath)
5118 case RENDERPATH_GL11:
5119 case RENDERPATH_GL13:
5120 case RENDERPATH_GL20:
5121 case RENDERPATH_GLES1:
5122 case RENDERPATH_GLES2:
5123 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5125 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use GL_DepthFunc instead
5126 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
5127 GL_DepthFunc(GL_ALWAYS);
5128 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5129 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
5130 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5131 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
5132 GL_DepthFunc(GL_LEQUAL);
5133 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
5134 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5135 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
5136 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5137 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
5141 case RENDERPATH_D3D9:
5142 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5144 case RENDERPATH_D3D10:
5145 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5147 case RENDERPATH_D3D11:
5148 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5150 case RENDERPATH_SOFT:
5151 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5155 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
5158 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
5160 static void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
5163 unsigned int occlude = 0;
5164 GLint allpixels = 0, visiblepixels = 0;
5166 // now we have to check the query result
5167 if (rtlight->corona_queryindex_visiblepixels)
5169 switch(vid.renderpath)
5171 case RENDERPATH_GL11:
5172 case RENDERPATH_GL13:
5173 case RENDERPATH_GL20:
5174 case RENDERPATH_GLES1:
5175 case RENDERPATH_GLES2:
5176 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5178 // See if we can use the GPU-side method to prevent implicit sync
5179 if (vid.support.arb_query_buffer_object) {
5180 #define BUFFER_OFFSET(i) ((GLint *)((unsigned char*)NULL + (i)))
5181 if (!r_shadow_occlusion_buf) {
5182 qglGenBuffersARB(1, &r_shadow_occlusion_buf);
5183 qglBindBufferARB(GL_QUERY_BUFFER_ARB, r_shadow_occlusion_buf);
5184 qglBufferDataARB(GL_QUERY_BUFFER_ARB, 8, NULL, GL_DYNAMIC_COPY);
5186 qglBindBufferARB(GL_QUERY_BUFFER_ARB, r_shadow_occlusion_buf);
5188 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, BUFFER_OFFSET(0));
5189 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, BUFFER_OFFSET(4));
5190 qglBindBufferBase(GL_UNIFORM_BUFFER, 0, r_shadow_occlusion_buf);
5191 occlude = MATERIALFLAG_OCCLUDE;
5193 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
5194 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
5195 if (visiblepixels < 1 || allpixels < 1)
5197 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
5199 cscale *= rtlight->corona_visibility;
5205 case RENDERPATH_D3D9:
5206 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5208 case RENDERPATH_D3D10:
5209 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5211 case RENDERPATH_D3D11:
5212 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5214 case RENDERPATH_SOFT:
5215 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5223 // FIXME: these traces should scan all render entities instead of cl.world
5224 if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, collision_extendmovelength.value, true, false, NULL, false, true).fraction < 1)
5227 VectorScale(rtlight->currentcolor, cscale, color);
5228 if (VectorLength(color) > (1.0f / 256.0f))
5231 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
5234 VectorNegate(color, color);
5235 GL_BlendEquationSubtract(true);
5237 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5238 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);
5239 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE | MATERIALFLAG_NODEPTHTEST | occlude, 0, 4, 0, 2, false, false);
5241 GL_BlendEquationSubtract(false);
5245 void R_Shadow_DrawCoronas(void)
5248 qboolean usequery = false;
5253 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
5255 if (r_fb.water.renderingscene)
5257 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
5258 R_EntityMatrix(&identitymatrix);
5260 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5262 // check occlusion of coronas
5263 // use GL_ARB_occlusion_query if available
5264 // otherwise use raytraces
5266 switch (vid.renderpath)
5268 case RENDERPATH_GL11:
5269 case RENDERPATH_GL13:
5270 case RENDERPATH_GL20:
5271 case RENDERPATH_GLES1:
5272 case RENDERPATH_GLES2:
5273 usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
5274 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5277 GL_ColorMask(0,0,0,0);
5278 if (r_maxqueries < ((unsigned int)range + r_refdef.scene.numlights) * 2)
5279 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
5282 r_maxqueries = ((unsigned int)range + r_refdef.scene.numlights) * 4;
5283 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
5285 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
5288 RSurf_ActiveWorldEntity();
5289 GL_BlendFunc(GL_ONE, GL_ZERO);
5290 GL_CullFace(GL_NONE);
5291 GL_DepthMask(false);
5292 GL_DepthRange(0, 1);
5293 GL_PolygonOffset(0, 0);
5295 R_Mesh_ResetTextureState();
5296 R_SetupShader_Generic_NoTexture(false, false);
5300 case RENDERPATH_D3D9:
5302 //Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5304 case RENDERPATH_D3D10:
5305 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5307 case RENDERPATH_D3D11:
5308 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5310 case RENDERPATH_SOFT:
5312 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5315 for (lightindex = 0;lightindex < range;lightindex++)
5317 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5320 rtlight = &light->rtlight;
5321 rtlight->corona_visibility = 0;
5322 rtlight->corona_queryindex_visiblepixels = 0;
5323 rtlight->corona_queryindex_allpixels = 0;
5324 if (!(rtlight->flags & flag))
5326 if (rtlight->corona <= 0)
5328 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
5330 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
5332 for (i = 0;i < r_refdef.scene.numlights;i++)
5334 rtlight = r_refdef.scene.lights[i];
5335 rtlight->corona_visibility = 0;
5336 rtlight->corona_queryindex_visiblepixels = 0;
5337 rtlight->corona_queryindex_allpixels = 0;
5338 if (!(rtlight->flags & flag))
5340 if (rtlight->corona <= 0)
5342 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
5345 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5347 // now draw the coronas using the query data for intensity info
5348 for (lightindex = 0;lightindex < range;lightindex++)
5350 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5353 rtlight = &light->rtlight;
5354 if (rtlight->corona_visibility <= 0)
5356 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
5358 for (i = 0;i < r_refdef.scene.numlights;i++)
5360 rtlight = r_refdef.scene.lights[i];
5361 if (rtlight->corona_visibility <= 0)
5363 if (gl_flashblend.integer)
5364 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
5366 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
5372 static dlight_t *R_Shadow_NewWorldLight(void)
5374 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
5377 static void R_Shadow_UpdateWorldLight(dlight_t *light, vec3_t origin, vec3_t angles, vec3_t color, vec_t radius, vec_t corona, int style, int shadowenable, const char *cubemapname, vec_t coronasizescale, vec_t ambientscale, vec_t diffusescale, vec_t specularscale, int flags)
5381 // note that style is no longer validated here, -1 is used for unstyled lights and >= MAX_LIGHTSTYLES is accepted for sake of editing rtlights files that might be out of bounds but perfectly formatted
5383 // validate parameters
5387 // copy to light properties
5388 VectorCopy(origin, light->origin);
5389 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
5390 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
5391 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
5393 light->color[0] = max(color[0], 0);
5394 light->color[1] = max(color[1], 0);
5395 light->color[2] = max(color[2], 0);
5397 light->color[0] = color[0];
5398 light->color[1] = color[1];
5399 light->color[2] = color[2];
5400 light->radius = max(radius, 0);
5401 light->style = style;
5402 light->shadow = shadowenable;
5403 light->corona = corona;
5404 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
5405 light->coronasizescale = coronasizescale;
5406 light->ambientscale = ambientscale;
5407 light->diffusescale = diffusescale;
5408 light->specularscale = specularscale;
5409 light->flags = flags;
5411 // update renderable light data
5412 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
5413 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);
5416 static void R_Shadow_FreeWorldLight(dlight_t *light)
5418 if (r_shadow_selectedlight == light)
5419 r_shadow_selectedlight = NULL;
5420 R_RTLight_Uncompile(&light->rtlight);
5421 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
5424 void R_Shadow_ClearWorldLights(void)
5428 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5429 for (lightindex = 0;lightindex < range;lightindex++)
5431 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5433 R_Shadow_FreeWorldLight(light);
5435 r_shadow_selectedlight = NULL;
5438 static void R_Shadow_SelectLight(dlight_t *light)
5440 if (r_shadow_selectedlight)
5441 r_shadow_selectedlight->selected = false;
5442 r_shadow_selectedlight = light;
5443 if (r_shadow_selectedlight)
5444 r_shadow_selectedlight->selected = true;
5447 static void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
5449 // this is never batched (there can be only one)
5451 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
5452 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
5453 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5456 static void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
5461 skinframe_t *skinframe;
5464 // this is never batched (due to the ent parameter changing every time)
5465 // so numsurfaces == 1 and surfacelist[0] == lightnumber
5466 const dlight_t *light = (dlight_t *)ent;
5469 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
5472 VectorScale(light->color, intensity, spritecolor);
5473 if (VectorLength(spritecolor) < 0.1732f)
5474 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
5475 if (VectorLength(spritecolor) > 1.0f)
5476 VectorNormalize(spritecolor);
5478 // draw light sprite
5479 if (light->cubemapname[0] && !light->shadow)
5480 skinframe = r_editlights_sprcubemapnoshadowlight;
5481 else if (light->cubemapname[0])
5482 skinframe = r_editlights_sprcubemaplight;
5483 else if (!light->shadow)
5484 skinframe = r_editlights_sprnoshadowlight;
5486 skinframe = r_editlights_sprlight;
5488 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);
5489 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5491 // draw selection sprite if light is selected
5492 if (light->selected)
5494 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
5495 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5496 // VorteX todo: add normalmode/realtime mode light overlay sprites?
5500 void R_Shadow_DrawLightSprites(void)
5504 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5505 for (lightindex = 0;lightindex < range;lightindex++)
5507 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5509 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
5511 if (!r_editlights_lockcursor)
5512 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
5515 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
5520 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
5521 if (lightindex >= range)
5523 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5526 rtlight = &light->rtlight;
5527 //if (!(rtlight->flags & flag))
5529 VectorCopy(rtlight->shadoworigin, origin);
5530 *radius = rtlight->radius;
5531 VectorCopy(rtlight->color, color);
5535 static void R_Shadow_SelectLightInView(void)
5537 float bestrating, rating, temp[3];
5541 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5545 if (r_editlights_lockcursor)
5547 for (lightindex = 0;lightindex < range;lightindex++)
5549 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5552 VectorSubtract(light->origin, r_refdef.view.origin, temp);
5553 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
5556 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
5557 if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, collision_extendmovelength.value, true, false, NULL, false, true).fraction == 1.0f)
5559 bestrating = rating;
5564 R_Shadow_SelectLight(best);
5567 void R_Shadow_LoadWorldLights(void)
5569 int n, a, style, shadow, flags;
5570 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
5571 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
5572 if (cl.worldmodel == NULL)
5574 Con_Print("No map loaded.\n");
5577 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
5578 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5588 for (;COM_Parse(t, true) && strcmp(
5589 if (COM_Parse(t, true))
5591 if (com_token[0] == '!')
5594 origin[0] = atof(com_token+1);
5597 origin[0] = atof(com_token);
5602 while (*s && *s != '\n' && *s != '\r')
5608 // check for modifier flags
5615 #if _MSC_VER >= 1400
5616 #define sscanf sscanf_s
5618 cubemapname[sizeof(cubemapname)-1] = 0;
5619 #if MAX_QPATH != 128
5620 #error update this code if MAX_QPATH changes
5622 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
5623 #if _MSC_VER >= 1400
5624 , sizeof(cubemapname)
5626 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
5629 flags = LIGHTFLAG_REALTIMEMODE;
5637 coronasizescale = 0.25f;
5639 VectorClear(angles);
5642 if (a < 9 || !strcmp(cubemapname, "\"\""))
5644 // remove quotes on cubemapname
5645 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
5648 namelen = strlen(cubemapname) - 2;
5649 memmove(cubemapname, cubemapname + 1, namelen);
5650 cubemapname[namelen] = '\0';
5654 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);
5657 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5665 Con_Printf("invalid rtlights file \"%s\"\n", name);
5666 Mem_Free(lightsstring);
5670 void R_Shadow_SaveWorldLights(void)
5674 size_t bufchars, bufmaxchars;
5676 char name[MAX_QPATH];
5677 char line[MAX_INPUTLINE];
5678 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
5679 // I hate lines which are 3 times my screen size :( --blub
5682 if (cl.worldmodel == NULL)
5684 Con_Print("No map loaded.\n");
5687 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
5688 bufchars = bufmaxchars = 0;
5690 for (lightindex = 0;lightindex < range;lightindex++)
5692 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5695 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
5696 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);
5697 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
5698 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]);
5700 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);
5701 if (bufchars + strlen(line) > bufmaxchars)
5703 bufmaxchars = bufchars + strlen(line) + 2048;
5705 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
5709 memcpy(buf, oldbuf, bufchars);
5715 memcpy(buf + bufchars, line, strlen(line));
5716 bufchars += strlen(line);
5720 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
5725 void R_Shadow_LoadLightsFile(void)
5728 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
5729 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
5730 if (cl.worldmodel == NULL)
5732 Con_Print("No map loaded.\n");
5735 dpsnprintf(name, sizeof(name), "%s.lights", cl.worldnamenoextension);
5736 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5744 while (*s && *s != '\n' && *s != '\r')
5750 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);
5754 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);
5757 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
5758 radius = bound(15, radius, 4096);
5759 VectorScale(color, (2.0f / (8388608.0f)), color);
5760 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5768 Con_Printf("invalid lights file \"%s\"\n", name);
5769 Mem_Free(lightsstring);
5773 // tyrlite/hmap2 light types in the delay field
5774 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
5776 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
5788 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
5789 char key[256], value[MAX_INPUTLINE];
5792 if (cl.worldmodel == NULL)
5794 Con_Print("No map loaded.\n");
5797 // try to load a .ent file first
5798 dpsnprintf(key, sizeof(key), "%s.ent", cl.worldnamenoextension);
5799 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
5800 // and if that is not found, fall back to the bsp file entity string
5802 data = cl.worldmodel->brush.entities;
5805 for (entnum = 0;COM_ParseToken_Simple(&data, false, false, true) && com_token[0] == '{';entnum++)
5807 type = LIGHTTYPE_MINUSX;
5808 origin[0] = origin[1] = origin[2] = 0;
5809 originhack[0] = originhack[1] = originhack[2] = 0;
5810 angles[0] = angles[1] = angles[2] = 0;
5811 color[0] = color[1] = color[2] = 1;
5812 light[0] = light[1] = light[2] = 1;light[3] = 300;
5813 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
5823 if (!COM_ParseToken_Simple(&data, false, false, true))
5825 if (com_token[0] == '}')
5826 break; // end of entity
5827 if (com_token[0] == '_')
5828 strlcpy(key, com_token + 1, sizeof(key));
5830 strlcpy(key, com_token, sizeof(key));
5831 while (key[strlen(key)-1] == ' ') // remove trailing spaces
5832 key[strlen(key)-1] = 0;
5833 if (!COM_ParseToken_Simple(&data, false, false, true))
5835 strlcpy(value, com_token, sizeof(value));
5837 // now that we have the key pair worked out...
5838 if (!strcmp("light", key))
5840 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5844 light[0] = vec[0] * (1.0f / 256.0f);
5845 light[1] = vec[0] * (1.0f / 256.0f);
5846 light[2] = vec[0] * (1.0f / 256.0f);
5852 light[0] = vec[0] * (1.0f / 255.0f);
5853 light[1] = vec[1] * (1.0f / 255.0f);
5854 light[2] = vec[2] * (1.0f / 255.0f);
5858 else if (!strcmp("delay", key))
5860 else if (!strcmp("origin", key))
5861 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5862 else if (!strcmp("angle", key))
5863 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5864 else if (!strcmp("angles", key))
5865 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5866 else if (!strcmp("color", key))
5867 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5868 else if (!strcmp("wait", key))
5869 fadescale = atof(value);
5870 else if (!strcmp("classname", key))
5872 if (!strncmp(value, "light", 5))
5875 if (!strcmp(value, "light_fluoro"))
5880 overridecolor[0] = 1;
5881 overridecolor[1] = 1;
5882 overridecolor[2] = 1;
5884 if (!strcmp(value, "light_fluorospark"))
5889 overridecolor[0] = 1;
5890 overridecolor[1] = 1;
5891 overridecolor[2] = 1;
5893 if (!strcmp(value, "light_globe"))
5898 overridecolor[0] = 1;
5899 overridecolor[1] = 0.8;
5900 overridecolor[2] = 0.4;
5902 if (!strcmp(value, "light_flame_large_yellow"))
5907 overridecolor[0] = 1;
5908 overridecolor[1] = 0.5;
5909 overridecolor[2] = 0.1;
5911 if (!strcmp(value, "light_flame_small_yellow"))
5916 overridecolor[0] = 1;
5917 overridecolor[1] = 0.5;
5918 overridecolor[2] = 0.1;
5920 if (!strcmp(value, "light_torch_small_white"))
5925 overridecolor[0] = 1;
5926 overridecolor[1] = 0.5;
5927 overridecolor[2] = 0.1;
5929 if (!strcmp(value, "light_torch_small_walltorch"))
5934 overridecolor[0] = 1;
5935 overridecolor[1] = 0.5;
5936 overridecolor[2] = 0.1;
5940 else if (!strcmp("style", key))
5941 style = atoi(value);
5942 else if (!strcmp("skin", key))
5943 skin = (int)atof(value);
5944 else if (!strcmp("pflags", key))
5945 pflags = (int)atof(value);
5946 //else if (!strcmp("effects", key))
5947 // effects = (int)atof(value);
5948 else if (cl.worldmodel->type == mod_brushq3)
5950 if (!strcmp("scale", key))
5951 lightscale = atof(value);
5952 if (!strcmp("fade", key))
5953 fadescale = atof(value);
5958 if (lightscale <= 0)
5962 if (color[0] == color[1] && color[0] == color[2])
5964 color[0] *= overridecolor[0];
5965 color[1] *= overridecolor[1];
5966 color[2] *= overridecolor[2];
5968 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5969 color[0] = color[0] * light[0];
5970 color[1] = color[1] * light[1];
5971 color[2] = color[2] * light[2];
5974 case LIGHTTYPE_MINUSX:
5976 case LIGHTTYPE_RECIPX:
5978 VectorScale(color, (1.0f / 16.0f), color);
5980 case LIGHTTYPE_RECIPXX:
5982 VectorScale(color, (1.0f / 16.0f), color);
5985 case LIGHTTYPE_NONE:
5989 case LIGHTTYPE_MINUSXX:
5992 VectorAdd(origin, originhack, origin);
5994 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, (pflags & PFLAGS_CORONA) != 0, style, (pflags & PFLAGS_NOSHADOW) == 0, skin >= 16 ? va(vabuf, sizeof(vabuf), "cubemaps/%i", skin) : NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5997 Mem_Free(entfiledata);
6001 static void R_Shadow_SetCursorLocationForView(void)
6004 vec3_t dest, endpos;
6006 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
6007 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, collision_extendmovelength.value, true, false, NULL, false, true);
6008 if (trace.fraction < 1)
6010 dist = trace.fraction * r_editlights_cursordistance.value;
6011 push = r_editlights_cursorpushback.value;
6015 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
6016 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
6020 VectorClear( endpos );
6022 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
6023 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
6024 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
6027 void R_Shadow_UpdateWorldLightSelection(void)
6029 if (r_editlights.integer)
6031 R_Shadow_SetCursorLocationForView();
6032 R_Shadow_SelectLightInView();
6035 R_Shadow_SelectLight(NULL);
6038 static void R_Shadow_EditLights_Clear_f(void)
6040 R_Shadow_ClearWorldLights();
6043 void R_Shadow_EditLights_Reload_f(void)
6047 strlcpy(r_shadow_mapname, cl.worldname, sizeof(r_shadow_mapname));
6048 R_Shadow_ClearWorldLights();
6049 if (r_shadow_realtime_world_importlightentitiesfrommap.integer <= 1)
6051 R_Shadow_LoadWorldLights();
6052 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
6053 R_Shadow_LoadLightsFile();
6055 if (r_shadow_realtime_world_importlightentitiesfrommap.integer >= 1)
6057 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
6058 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
6062 static void R_Shadow_EditLights_Save_f(void)
6066 R_Shadow_SaveWorldLights();
6069 static void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
6071 R_Shadow_ClearWorldLights();
6072 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
6075 static void R_Shadow_EditLights_ImportLightsFile_f(void)
6077 R_Shadow_ClearWorldLights();
6078 R_Shadow_LoadLightsFile();
6081 static void R_Shadow_EditLights_Spawn_f(void)
6084 if (!r_editlights.integer)
6086 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6089 if (Cmd_Argc() != 1)
6091 Con_Print("r_editlights_spawn does not take parameters\n");
6094 color[0] = color[1] = color[2] = 1;
6095 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
6098 static void R_Shadow_EditLights_Edit_f(void)
6100 vec3_t origin, angles, color;
6101 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
6102 int style, shadows, flags, normalmode, realtimemode;
6103 char cubemapname[MAX_INPUTLINE];
6104 if (!r_editlights.integer)
6106 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6109 if (!r_shadow_selectedlight)
6111 Con_Print("No selected light.\n");
6114 VectorCopy(r_shadow_selectedlight->origin, origin);
6115 VectorCopy(r_shadow_selectedlight->angles, angles);
6116 VectorCopy(r_shadow_selectedlight->color, color);
6117 radius = r_shadow_selectedlight->radius;
6118 style = r_shadow_selectedlight->style;
6119 if (r_shadow_selectedlight->cubemapname)
6120 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
6123 shadows = r_shadow_selectedlight->shadow;
6124 corona = r_shadow_selectedlight->corona;
6125 coronasizescale = r_shadow_selectedlight->coronasizescale;
6126 ambientscale = r_shadow_selectedlight->ambientscale;
6127 diffusescale = r_shadow_selectedlight->diffusescale;
6128 specularscale = r_shadow_selectedlight->specularscale;
6129 flags = r_shadow_selectedlight->flags;
6130 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
6131 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
6132 if (!strcmp(Cmd_Argv(1), "origin"))
6134 if (Cmd_Argc() != 5)
6136 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6139 origin[0] = atof(Cmd_Argv(2));
6140 origin[1] = atof(Cmd_Argv(3));
6141 origin[2] = atof(Cmd_Argv(4));
6143 else if (!strcmp(Cmd_Argv(1), "originscale"))
6145 if (Cmd_Argc() != 5)
6147 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6150 origin[0] *= atof(Cmd_Argv(2));
6151 origin[1] *= atof(Cmd_Argv(3));
6152 origin[2] *= atof(Cmd_Argv(4));
6154 else if (!strcmp(Cmd_Argv(1), "originx"))
6156 if (Cmd_Argc() != 3)
6158 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6161 origin[0] = atof(Cmd_Argv(2));
6163 else if (!strcmp(Cmd_Argv(1), "originy"))
6165 if (Cmd_Argc() != 3)
6167 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6170 origin[1] = atof(Cmd_Argv(2));
6172 else if (!strcmp(Cmd_Argv(1), "originz"))
6174 if (Cmd_Argc() != 3)
6176 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6179 origin[2] = atof(Cmd_Argv(2));
6181 else if (!strcmp(Cmd_Argv(1), "move"))
6183 if (Cmd_Argc() != 5)
6185 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6188 origin[0] += atof(Cmd_Argv(2));
6189 origin[1] += atof(Cmd_Argv(3));
6190 origin[2] += atof(Cmd_Argv(4));
6192 else if (!strcmp(Cmd_Argv(1), "movex"))
6194 if (Cmd_Argc() != 3)
6196 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6199 origin[0] += atof(Cmd_Argv(2));
6201 else if (!strcmp(Cmd_Argv(1), "movey"))
6203 if (Cmd_Argc() != 3)
6205 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6208 origin[1] += atof(Cmd_Argv(2));
6210 else if (!strcmp(Cmd_Argv(1), "movez"))
6212 if (Cmd_Argc() != 3)
6214 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6217 origin[2] += atof(Cmd_Argv(2));
6219 else if (!strcmp(Cmd_Argv(1), "angles"))
6221 if (Cmd_Argc() != 5)
6223 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6226 angles[0] = atof(Cmd_Argv(2));
6227 angles[1] = atof(Cmd_Argv(3));
6228 angles[2] = atof(Cmd_Argv(4));
6230 else if (!strcmp(Cmd_Argv(1), "anglesx"))
6232 if (Cmd_Argc() != 3)
6234 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6237 angles[0] = atof(Cmd_Argv(2));
6239 else if (!strcmp(Cmd_Argv(1), "anglesy"))
6241 if (Cmd_Argc() != 3)
6243 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6246 angles[1] = atof(Cmd_Argv(2));
6248 else if (!strcmp(Cmd_Argv(1), "anglesz"))
6250 if (Cmd_Argc() != 3)
6252 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6255 angles[2] = atof(Cmd_Argv(2));
6257 else if (!strcmp(Cmd_Argv(1), "color"))
6259 if (Cmd_Argc() != 5)
6261 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
6264 color[0] = atof(Cmd_Argv(2));
6265 color[1] = atof(Cmd_Argv(3));
6266 color[2] = atof(Cmd_Argv(4));
6268 else if (!strcmp(Cmd_Argv(1), "radius"))
6270 if (Cmd_Argc() != 3)
6272 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6275 radius = atof(Cmd_Argv(2));
6277 else if (!strcmp(Cmd_Argv(1), "colorscale"))
6279 if (Cmd_Argc() == 3)
6281 double scale = atof(Cmd_Argv(2));
6288 if (Cmd_Argc() != 5)
6290 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
6293 color[0] *= atof(Cmd_Argv(2));
6294 color[1] *= atof(Cmd_Argv(3));
6295 color[2] *= atof(Cmd_Argv(4));
6298 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
6300 if (Cmd_Argc() != 3)
6302 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6305 radius *= atof(Cmd_Argv(2));
6307 else if (!strcmp(Cmd_Argv(1), "style"))
6309 if (Cmd_Argc() != 3)
6311 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6314 style = atoi(Cmd_Argv(2));
6316 else if (!strcmp(Cmd_Argv(1), "cubemap"))
6320 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6323 if (Cmd_Argc() == 3)
6324 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
6328 else if (!strcmp(Cmd_Argv(1), "shadows"))
6330 if (Cmd_Argc() != 3)
6332 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6335 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
6337 else if (!strcmp(Cmd_Argv(1), "corona"))
6339 if (Cmd_Argc() != 3)
6341 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6344 corona = atof(Cmd_Argv(2));
6346 else if (!strcmp(Cmd_Argv(1), "coronasize"))
6348 if (Cmd_Argc() != 3)
6350 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6353 coronasizescale = atof(Cmd_Argv(2));
6355 else if (!strcmp(Cmd_Argv(1), "ambient"))
6357 if (Cmd_Argc() != 3)
6359 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6362 ambientscale = atof(Cmd_Argv(2));
6364 else if (!strcmp(Cmd_Argv(1), "diffuse"))
6366 if (Cmd_Argc() != 3)
6368 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6371 diffusescale = atof(Cmd_Argv(2));
6373 else if (!strcmp(Cmd_Argv(1), "specular"))
6375 if (Cmd_Argc() != 3)
6377 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6380 specularscale = atof(Cmd_Argv(2));
6382 else if (!strcmp(Cmd_Argv(1), "normalmode"))
6384 if (Cmd_Argc() != 3)
6386 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6389 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
6391 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
6393 if (Cmd_Argc() != 3)
6395 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6398 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
6402 Con_Print("usage: r_editlights_edit [property] [value]\n");
6403 Con_Print("Selected light's properties:\n");
6404 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
6405 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
6406 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
6407 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
6408 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
6409 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
6410 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
6411 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
6412 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
6413 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
6414 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
6415 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
6416 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
6417 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
6420 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
6421 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
6424 static void R_Shadow_EditLights_EditAll_f(void)
6427 dlight_t *light, *oldselected;
6430 if (!r_editlights.integer)
6432 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
6436 oldselected = r_shadow_selectedlight;
6437 // EditLights doesn't seem to have a "remove" command or something so:
6438 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6439 for (lightindex = 0;lightindex < range;lightindex++)
6441 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6444 R_Shadow_SelectLight(light);
6445 R_Shadow_EditLights_Edit_f();
6447 // return to old selected (to not mess editing once selection is locked)
6448 R_Shadow_SelectLight(oldselected);
6451 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
6453 int lightnumber, lightcount;
6454 size_t lightindex, range;
6459 if (!r_editlights.integer)
6462 // update cvars so QC can query them
6463 if (r_shadow_selectedlight)
6465 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
6466 Cvar_SetQuick(&r_editlights_current_origin, temp);
6467 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
6468 Cvar_SetQuick(&r_editlights_current_angles, temp);
6469 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
6470 Cvar_SetQuick(&r_editlights_current_color, temp);
6471 Cvar_SetValueQuick(&r_editlights_current_radius, r_shadow_selectedlight->radius);
6472 Cvar_SetValueQuick(&r_editlights_current_corona, r_shadow_selectedlight->corona);
6473 Cvar_SetValueQuick(&r_editlights_current_coronasize, r_shadow_selectedlight->coronasizescale);
6474 Cvar_SetValueQuick(&r_editlights_current_style, r_shadow_selectedlight->style);
6475 Cvar_SetValueQuick(&r_editlights_current_shadows, r_shadow_selectedlight->shadow);
6476 Cvar_SetQuick(&r_editlights_current_cubemap, r_shadow_selectedlight->cubemapname);
6477 Cvar_SetValueQuick(&r_editlights_current_ambient, r_shadow_selectedlight->ambientscale);
6478 Cvar_SetValueQuick(&r_editlights_current_diffuse, r_shadow_selectedlight->diffusescale);
6479 Cvar_SetValueQuick(&r_editlights_current_specular, r_shadow_selectedlight->specularscale);
6480 Cvar_SetValueQuick(&r_editlights_current_normalmode, (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? 1 : 0);
6481 Cvar_SetValueQuick(&r_editlights_current_realtimemode, (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? 1 : 0);
6484 // draw properties on screen
6485 if (!r_editlights_drawproperties.integer)
6487 x = vid_conwidth.value - 240;
6489 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
6492 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6493 for (lightindex = 0;lightindex < range;lightindex++)
6495 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6498 if (light == r_shadow_selectedlight)
6499 lightnumber = (int)lightindex;
6502 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;
6503 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;
6505 if (r_shadow_selectedlight == NULL)
6507 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;
6508 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;
6509 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;
6510 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;
6511 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;
6512 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;
6513 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;
6514 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;
6515 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;
6516 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;
6517 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;
6518 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;
6519 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;
6520 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;
6521 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;
6524 static void R_Shadow_EditLights_ToggleShadow_f(void)
6526 if (!r_editlights.integer)
6528 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6531 if (!r_shadow_selectedlight)
6533 Con_Print("No selected light.\n");
6536 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);
6539 static void R_Shadow_EditLights_ToggleCorona_f(void)
6541 if (!r_editlights.integer)
6543 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6546 if (!r_shadow_selectedlight)
6548 Con_Print("No selected light.\n");
6551 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);
6554 static void R_Shadow_EditLights_Remove_f(void)
6556 if (!r_editlights.integer)
6558 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
6561 if (!r_shadow_selectedlight)
6563 Con_Print("No selected light.\n");
6566 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
6567 r_shadow_selectedlight = NULL;
6570 static void R_Shadow_EditLights_Help_f(void)
6573 "Documentation on r_editlights system:\n"
6575 "r_editlights : enable/disable editing mode\n"
6576 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
6577 "r_editlights_cursorpushback : push back cursor this far from surface\n"
6578 "r_editlights_cursorpushoff : push cursor off surface this far\n"
6579 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
6580 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
6582 "r_editlights_help : this help\n"
6583 "r_editlights_clear : remove all lights\n"
6584 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
6585 "r_editlights_lock : lock selection to current light, if already locked - unlock\n"
6586 "r_editlights_save : save to .rtlights file\n"
6587 "r_editlights_spawn : create a light with default settings\n"
6588 "r_editlights_edit command : edit selected light - more documentation below\n"
6589 "r_editlights_remove : remove selected light\n"
6590 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
6591 "r_editlights_importlightentitiesfrommap : reload light entities\n"
6592 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
6594 "origin x y z : set light location\n"
6595 "originx x: set x component of light location\n"
6596 "originy y: set y component of light location\n"
6597 "originz z: set z component of light location\n"
6598 "move x y z : adjust light location\n"
6599 "movex x: adjust x component of light location\n"
6600 "movey y: adjust y component of light location\n"
6601 "movez z: adjust z component of light location\n"
6602 "angles x y z : set light angles\n"
6603 "anglesx x: set x component of light angles\n"
6604 "anglesy y: set y component of light angles\n"
6605 "anglesz z: set z component of light angles\n"
6606 "color r g b : set color of light (can be brighter than 1 1 1)\n"
6607 "radius radius : set radius (size) of light\n"
6608 "colorscale grey : multiply color of light (1 does nothing)\n"
6609 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
6610 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
6611 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
6612 "originscale x y z : multiply origin of light (1 1 1 does nothing)\n"
6613 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
6614 "cubemap basename : set filter cubemap of light\n"
6615 "shadows 1/0 : turn on/off shadows\n"
6616 "corona n : set corona intensity\n"
6617 "coronasize n : set corona size (0-1)\n"
6618 "ambient n : set ambient intensity (0-1)\n"
6619 "diffuse n : set diffuse intensity (0-1)\n"
6620 "specular n : set specular intensity (0-1)\n"
6621 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
6622 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
6623 "<nothing> : print light properties to console\n"
6627 static void R_Shadow_EditLights_CopyInfo_f(void)
6629 if (!r_editlights.integer)
6631 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
6634 if (!r_shadow_selectedlight)
6636 Con_Print("No selected light.\n");
6639 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
6640 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
6641 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
6642 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
6643 if (r_shadow_selectedlight->cubemapname)
6644 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
6646 r_shadow_bufferlight.cubemapname[0] = 0;
6647 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
6648 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
6649 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
6650 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
6651 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
6652 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
6653 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
6656 static void R_Shadow_EditLights_PasteInfo_f(void)
6658 if (!r_editlights.integer)
6660 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
6663 if (!r_shadow_selectedlight)
6665 Con_Print("No selected light.\n");
6668 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);
6671 static void R_Shadow_EditLights_Lock_f(void)
6673 if (!r_editlights.integer)
6675 Con_Print("Cannot lock on light when not in editing mode. Set r_editlights to 1.\n");
6678 if (r_editlights_lockcursor)
6680 r_editlights_lockcursor = false;
6683 if (!r_shadow_selectedlight)
6685 Con_Print("No selected light to lock on.\n");
6688 r_editlights_lockcursor = true;
6691 static void R_Shadow_EditLights_Init(void)
6693 Cvar_RegisterVariable(&r_editlights);
6694 Cvar_RegisterVariable(&r_editlights_cursordistance);
6695 Cvar_RegisterVariable(&r_editlights_cursorpushback);
6696 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
6697 Cvar_RegisterVariable(&r_editlights_cursorgrid);
6698 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
6699 Cvar_RegisterVariable(&r_editlights_drawproperties);
6700 Cvar_RegisterVariable(&r_editlights_current_origin);
6701 Cvar_RegisterVariable(&r_editlights_current_angles);
6702 Cvar_RegisterVariable(&r_editlights_current_color);
6703 Cvar_RegisterVariable(&r_editlights_current_radius);
6704 Cvar_RegisterVariable(&r_editlights_current_corona);
6705 Cvar_RegisterVariable(&r_editlights_current_coronasize);
6706 Cvar_RegisterVariable(&r_editlights_current_style);
6707 Cvar_RegisterVariable(&r_editlights_current_shadows);
6708 Cvar_RegisterVariable(&r_editlights_current_cubemap);
6709 Cvar_RegisterVariable(&r_editlights_current_ambient);
6710 Cvar_RegisterVariable(&r_editlights_current_diffuse);
6711 Cvar_RegisterVariable(&r_editlights_current_specular);
6712 Cvar_RegisterVariable(&r_editlights_current_normalmode);
6713 Cvar_RegisterVariable(&r_editlights_current_realtimemode);
6714 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
6715 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
6716 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)");
6717 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
6718 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
6719 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
6720 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)");
6721 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
6722 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
6723 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
6724 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
6725 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
6726 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
6727 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)");
6728 Cmd_AddCommand("r_editlights_lock", R_Shadow_EditLights_Lock_f, "lock selection to current light, if already locked - unlock");
6734 =============================================================================
6738 =============================================================================
6741 void R_LightPoint(float *color, const vec3_t p, const int flags)
6743 int i, numlights, flag;
6744 float f, relativepoint[3], dist, dist2, lightradius2;
6749 if (r_fullbright.integer)
6751 VectorSet(color, 1, 1, 1);
6757 if (flags & LP_LIGHTMAP)
6759 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
6761 VectorClear(diffuse);
6762 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, color, diffuse, n);
6763 VectorAdd(color, diffuse, color);
6766 VectorSet(color, 1, 1, 1);
6767 color[0] += r_refdef.scene.ambient;
6768 color[1] += r_refdef.scene.ambient;
6769 color[2] += r_refdef.scene.ambient;
6772 if (flags & LP_RTWORLD)
6774 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
6775 numlights = (int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
6776 for (i = 0; i < numlights; i++)
6778 dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
6781 light = &dlight->rtlight;
6782 if (!(light->flags & flag))
6785 lightradius2 = light->radius * light->radius;
6786 VectorSubtract(light->shadoworigin, p, relativepoint);
6787 dist2 = VectorLength2(relativepoint);
6788 if (dist2 >= lightradius2)
6790 dist = sqrt(dist2) / light->radius;
6791 f = dist < 1 ? (r_shadow_lightintensityscale.value * ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist))) : 0;
6794 // todo: add to both ambient and diffuse
6795 if (!light->shadow || CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, collision_extendmovelength.value, true, false, NULL, false, true).fraction == 1)
6796 VectorMA(color, f, light->currentcolor, color);
6799 if (flags & LP_DYNLIGHT)
6802 for (i = 0;i < r_refdef.scene.numlights;i++)
6804 light = r_refdef.scene.lights[i];
6806 lightradius2 = light->radius * light->radius;
6807 VectorSubtract(light->shadoworigin, p, relativepoint);
6808 dist2 = VectorLength2(relativepoint);
6809 if (dist2 >= lightradius2)
6811 dist = sqrt(dist2) / light->radius;
6812 f = dist < 1 ? (r_shadow_lightintensityscale.value * ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist))) : 0;
6815 // todo: add to both ambient and diffuse
6816 if (!light->shadow || CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, collision_extendmovelength.value, true, false, NULL, false, true).fraction == 1)
6817 VectorMA(color, f, light->color, color);
6822 void R_CompleteLightPoint(vec3_t ambient, vec3_t diffuse, vec3_t lightdir, const vec3_t p, const int flags)
6824 int i, numlights, flag;
6827 float relativepoint[3];
6836 if (r_fullbright.integer)
6838 VectorSet(ambient, 1, 1, 1);
6839 VectorClear(diffuse);
6840 VectorClear(lightdir);
6844 if (flags == LP_LIGHTMAP)
6846 VectorSet(ambient, r_refdef.scene.ambient, r_refdef.scene.ambient, r_refdef.scene.ambient);
6847 VectorClear(diffuse);
6848 VectorClear(lightdir);
6849 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
6850 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambient, diffuse, lightdir);
6852 VectorSet(ambient, 1, 1, 1);
6856 memset(sample, 0, sizeof(sample));
6857 VectorSet(sample, r_refdef.scene.ambient, r_refdef.scene.ambient, r_refdef.scene.ambient);
6859 if ((flags & LP_LIGHTMAP) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
6862 VectorClear(tempambient);
6864 VectorClear(relativepoint);
6865 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, tempambient, color, relativepoint);
6866 VectorScale(tempambient, r_refdef.lightmapintensity, tempambient);
6867 VectorScale(color, r_refdef.lightmapintensity, color);
6868 VectorAdd(sample, tempambient, sample);
6869 VectorMA(sample , 0.5f , color, sample );
6870 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
6871 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
6872 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
6873 // calculate a weighted average light direction as well
6874 intensity = VectorLength(color);
6875 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
6878 if (flags & LP_RTWORLD)
6880 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
6881 numlights = (int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
6882 for (i = 0; i < numlights; i++)
6884 dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
6887 light = &dlight->rtlight;
6888 if (!(light->flags & flag))
6891 lightradius2 = light->radius * light->radius;
6892 VectorSubtract(light->shadoworigin, p, relativepoint);
6893 dist2 = VectorLength2(relativepoint);
6894 if (dist2 >= lightradius2)
6896 dist = sqrt(dist2) / light->radius;
6897 intensity = min(1.0f, (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) * r_shadow_lightintensityscale.value;
6898 if (intensity <= 0.0f)
6900 if (light->shadow && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, collision_extendmovelength.value, true, false, NULL, false, true).fraction < 1)
6902 // scale down intensity to add to both ambient and diffuse
6903 //intensity *= 0.5f;
6904 VectorNormalize(relativepoint);
6905 VectorScale(light->currentcolor, intensity, color);
6906 VectorMA(sample , 0.5f , color, sample );
6907 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
6908 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
6909 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
6910 // calculate a weighted average light direction as well
6911 intensity *= VectorLength(color);
6912 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
6914 // FIXME: sample bouncegrid too!
6917 if (flags & LP_DYNLIGHT)
6920 for (i = 0;i < r_refdef.scene.numlights;i++)
6922 light = r_refdef.scene.lights[i];
6924 lightradius2 = light->radius * light->radius;
6925 VectorSubtract(light->shadoworigin, p, relativepoint);
6926 dist2 = VectorLength2(relativepoint);
6927 if (dist2 >= lightradius2)
6929 dist = sqrt(dist2) / light->radius;
6930 intensity = (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist) * r_shadow_lightintensityscale.value;
6931 if (intensity <= 0.0f)
6933 if (light->shadow && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, collision_extendmovelength.value, true, false, NULL, false, true).fraction < 1)
6935 // scale down intensity to add to both ambient and diffuse
6936 //intensity *= 0.5f;
6937 VectorNormalize(relativepoint);
6938 VectorScale(light->currentcolor, intensity, color);
6939 VectorMA(sample , 0.5f , color, sample );
6940 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
6941 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
6942 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
6943 // calculate a weighted average light direction as well
6944 intensity *= VectorLength(color);
6945 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
6949 // calculate the direction we'll use to reduce the sample to a directional light source
6950 VectorCopy(sample + 12, dir);
6951 //VectorSet(dir, sample[3] + sample[4] + sample[5], sample[6] + sample[7] + sample[8], sample[9] + sample[10] + sample[11]);
6952 VectorNormalize(dir);
6953 // extract the diffuse color along the chosen direction and scale it
6954 diffuse[0] = (dir[0]*sample[3] + dir[1]*sample[6] + dir[2]*sample[ 9] + sample[ 0]);
6955 diffuse[1] = (dir[0]*sample[4] + dir[1]*sample[7] + dir[2]*sample[10] + sample[ 1]);
6956 diffuse[2] = (dir[0]*sample[5] + dir[1]*sample[8] + dir[2]*sample[11] + sample[ 2]);
6957 // subtract some of diffuse from ambient
6958 VectorMA(sample, -0.333f, diffuse, ambient);
6959 // store the normalized lightdir
6960 VectorCopy(dir, lightdir);