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_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"};
302 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
303 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
304 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"};
305 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)"};
306 cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "1", "enables portal-based culling optimization during compilation (overrides compilesvbsp)"};
307 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)"};
308 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"};
309 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)"};
310 cvar_t r_shadow_shadowmapping_useshadowsampler = {CVAR_SAVE, "r_shadow_shadowmapping_useshadowsampler", "1", "whether to use sampler2DShadow if available"};
311 cvar_t r_shadow_shadowmapping_depthbits = {CVAR_SAVE, "r_shadow_shadowmapping_depthbits", "24", "requested minimum shadowmap texture depth bits"};
312 cvar_t r_shadow_shadowmapping_vsdct = {CVAR_SAVE, "r_shadow_shadowmapping_vsdct", "1", "enables use of virtual shadow depth cube texture"};
313 cvar_t r_shadow_shadowmapping_minsize = {CVAR_SAVE, "r_shadow_shadowmapping_minsize", "32", "shadowmap size limit"};
314 cvar_t r_shadow_shadowmapping_maxsize = {CVAR_SAVE, "r_shadow_shadowmapping_maxsize", "512", "shadowmap size limit"};
315 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"};
316 //cvar_t r_shadow_shadowmapping_lod_bias = {CVAR_SAVE, "r_shadow_shadowmapping_lod_bias", "16", "shadowmap size bias"};
317 //cvar_t r_shadow_shadowmapping_lod_scale = {CVAR_SAVE, "r_shadow_shadowmapping_lod_scale", "128", "shadowmap size scaling parameter"};
318 cvar_t r_shadow_shadowmapping_bordersize = {CVAR_SAVE, "r_shadow_shadowmapping_bordersize", "4", "shadowmap size bias for filtering"};
319 cvar_t r_shadow_shadowmapping_nearclip = {CVAR_SAVE, "r_shadow_shadowmapping_nearclip", "1", "shadowmap nearclip in world units"};
320 cvar_t r_shadow_shadowmapping_bias = {CVAR_SAVE, "r_shadow_shadowmapping_bias", "0.03", "shadowmap bias parameter (this is multiplied by nearclip * 1024 / lodsize)"};
321 cvar_t r_shadow_shadowmapping_polygonfactor = {CVAR_SAVE, "r_shadow_shadowmapping_polygonfactor", "2", "slope-dependent shadowmapping bias"};
322 cvar_t r_shadow_shadowmapping_polygonoffset = {CVAR_SAVE, "r_shadow_shadowmapping_polygonoffset", "0", "constant shadowmapping bias"};
323 cvar_t r_shadow_sortsurfaces = {0, "r_shadow_sortsurfaces", "1", "improve performance by sorting illuminated surfaces by texture"};
324 cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
325 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)"};
326 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)"};
327 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)"};
328 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"};
329 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"};
330 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"};
331 cvar_t r_shadow_bouncegrid_hitmodels = {CVAR_SAVE, "r_shadow_bouncegrid_hitmodels", "0", "enables hitting character model geometry (SLOW)"};
332 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)"};
333 cvar_t r_shadow_bouncegrid_intensity = {CVAR_SAVE, "r_shadow_bouncegrid_intensity", "4", "overall brightness of bouncegrid texture"};
334 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)"};
335 cvar_t r_shadow_bouncegrid_maxbounce = {CVAR_SAVE, "r_shadow_bouncegrid_maxbounce", "2", "maximum number of bounces for a particle (minimum is 0)"};
336 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"};
337 cvar_t r_shadow_bouncegrid_particleintensity = {CVAR_SAVE, "r_shadow_bouncegrid_particleintensity", "1", "brightness of particles contributing to bouncegrid texture"};
338 cvar_t r_shadow_bouncegrid_photons = {CVAR_SAVE, "r_shadow_bouncegrid_photons", "2000", "total photons to shoot per update, divided proportionately between lights"};
339 cvar_t r_shadow_bouncegrid_spacing = {CVAR_SAVE, "r_shadow_bouncegrid_spacing", "64", "unit size of bouncegrid pixel"};
340 cvar_t r_shadow_bouncegrid_stablerandom = {CVAR_SAVE, "r_shadow_bouncegrid_stablerandom", "1", "make particle distribution consistent from frame to frame"};
341 cvar_t r_shadow_bouncegrid_static = {CVAR_SAVE, "r_shadow_bouncegrid_static", "1", "use static radiosity solution (high quality) rather than dynamic (splotchy)"};
342 cvar_t r_shadow_bouncegrid_static_directionalshading = {CVAR_SAVE, "r_shadow_bouncegrid_static_directionalshading", "1", "whether to use directionalshading when in static mode"};
343 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"};
344 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"};
345 cvar_t r_shadow_bouncegrid_static_photons = {CVAR_SAVE, "r_shadow_bouncegrid_static_photons", "25000", "photons value to use when in static mode"};
346 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"};
347 cvar_t r_shadow_bouncegrid_x = {CVAR_SAVE, "r_shadow_bouncegrid_x", "64", "maximum texture size of bouncegrid on X axis"};
348 cvar_t r_shadow_bouncegrid_y = {CVAR_SAVE, "r_shadow_bouncegrid_y", "64", "maximum texture size of bouncegrid on Y axis"};
349 cvar_t r_shadow_bouncegrid_z = {CVAR_SAVE, "r_shadow_bouncegrid_z", "32", "maximum texture size of bouncegrid on Z axis"};
350 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "0", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
351 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"};
352 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!"};
353 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
354 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
355 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
356 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
357 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
358 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
359 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
360 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
361 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
362 cvar_t r_editlights_drawproperties = {0, "r_editlights_drawproperties", "1", "draw properties of currently selected light"};
363 cvar_t r_editlights_current_origin = {0, "r_editlights_current_origin", "0 0 0", "origin of selected light"};
364 cvar_t r_editlights_current_angles = {0, "r_editlights_current_angles", "0 0 0", "angles of selected light"};
365 cvar_t r_editlights_current_color = {0, "r_editlights_current_color", "1 1 1", "color of selected light"};
366 cvar_t r_editlights_current_radius = {0, "r_editlights_current_radius", "0", "radius of selected light"};
367 cvar_t r_editlights_current_corona = {0, "r_editlights_current_corona", "0", "corona intensity of selected light"};
368 cvar_t r_editlights_current_coronasize = {0, "r_editlights_current_coronasize", "0", "corona size of selected light"};
369 cvar_t r_editlights_current_style = {0, "r_editlights_current_style", "0", "style of selected light"};
370 cvar_t r_editlights_current_shadows = {0, "r_editlights_current_shadows", "0", "shadows flag of selected light"};
371 cvar_t r_editlights_current_cubemap = {0, "r_editlights_current_cubemap", "0", "cubemap of selected light"};
372 cvar_t r_editlights_current_ambient = {0, "r_editlights_current_ambient", "0", "ambient intensity of selected light"};
373 cvar_t r_editlights_current_diffuse = {0, "r_editlights_current_diffuse", "1", "diffuse intensity of selected light"};
374 cvar_t r_editlights_current_specular = {0, "r_editlights_current_specular", "1", "specular intensity of selected light"};
375 cvar_t r_editlights_current_normalmode = {0, "r_editlights_current_normalmode", "0", "normalmode flag of selected light"};
376 cvar_t r_editlights_current_realtimemode = {0, "r_editlights_current_realtimemode", "0", "realtimemode flag of selected light"};
379 typedef struct r_shadow_bouncegrid_settings_s
382 qboolean bounceanglediffuse;
383 qboolean directionalshading;
384 qboolean includedirectlighting;
385 float dlightparticlemultiplier;
387 float lightradiusscale;
389 float particlebounceintensity;
390 float particleintensity;
395 r_shadow_bouncegrid_settings_t;
397 r_shadow_bouncegrid_settings_t r_shadow_bouncegridsettings;
398 rtexture_t *r_shadow_bouncegridtexture;
399 matrix4x4_t r_shadow_bouncegridmatrix;
400 vec_t r_shadow_bouncegridintensity;
401 qboolean r_shadow_bouncegriddirectional;
402 static double r_shadow_bouncegridtime;
403 static int r_shadow_bouncegridresolution[3];
404 static int r_shadow_bouncegridnumpixels;
405 static unsigned char *r_shadow_bouncegridpixels;
406 static float *r_shadow_bouncegridhighpixels;
408 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
409 #define ATTENTABLESIZE 256
410 // 1D gradient, 2D circle and 3D sphere attenuation textures
411 #define ATTEN1DSIZE 32
412 #define ATTEN2DSIZE 64
413 #define ATTEN3DSIZE 32
415 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
416 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
417 static float r_shadow_attentable[ATTENTABLESIZE+1];
419 rtlight_t *r_shadow_compilingrtlight;
420 static memexpandablearray_t r_shadow_worldlightsarray;
421 dlight_t *r_shadow_selectedlight;
422 dlight_t r_shadow_bufferlight;
423 vec3_t r_editlights_cursorlocation;
424 qboolean r_editlights_lockcursor;
426 extern int con_vislines;
428 void R_Shadow_UncompileWorldLights(void);
429 void R_Shadow_ClearWorldLights(void);
430 void R_Shadow_SaveWorldLights(void);
431 void R_Shadow_LoadWorldLights(void);
432 void R_Shadow_LoadLightsFile(void);
433 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
434 void R_Shadow_EditLights_Reload_f(void);
435 void R_Shadow_ValidateCvars(void);
436 static void R_Shadow_MakeTextures(void);
438 #define EDLIGHTSPRSIZE 8
439 skinframe_t *r_editlights_sprcursor;
440 skinframe_t *r_editlights_sprlight;
441 skinframe_t *r_editlights_sprnoshadowlight;
442 skinframe_t *r_editlights_sprcubemaplight;
443 skinframe_t *r_editlights_sprcubemapnoshadowlight;
444 skinframe_t *r_editlights_sprselection;
446 static void R_Shadow_SetShadowMode(void)
448 r_shadow_shadowmapmaxsize = bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4);
449 r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20;
450 r_shadow_shadowmapfilterquality = r_shadow_shadowmapping_filterquality.integer;
451 r_shadow_shadowmapshadowsampler = r_shadow_shadowmapping_useshadowsampler.integer != 0;
452 r_shadow_shadowmapdepthbits = r_shadow_shadowmapping_depthbits.integer;
453 r_shadow_shadowmapborder = bound(0, r_shadow_shadowmapping_bordersize.integer, 16);
454 r_shadow_shadowmaplod = -1;
455 r_shadow_shadowmapsize = 0;
456 r_shadow_shadowmapsampler = false;
457 r_shadow_shadowmappcf = 0;
458 r_shadow_shadowmapdepthtexture = r_fb.usedepthtextures;
459 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
460 if ((r_shadow_shadowmapping.integer || r_shadow_deferred.integer) && vid.support.ext_framebuffer_object)
462 switch(vid.renderpath)
464 case RENDERPATH_GL20:
465 if(r_shadow_shadowmapfilterquality < 0)
467 if (!r_fb.usedepthtextures)
468 r_shadow_shadowmappcf = 1;
469 else if((strstr(gl_vendor, "NVIDIA") || strstr(gl_renderer, "Radeon HD")) && vid.support.arb_shadow && r_shadow_shadowmapshadowsampler)
471 r_shadow_shadowmapsampler = true;
472 r_shadow_shadowmappcf = 1;
474 else if(vid.support.amd_texture_texture4 || vid.support.arb_texture_gather)
475 r_shadow_shadowmappcf = 1;
476 else if((strstr(gl_vendor, "ATI") || strstr(gl_vendor, "Advanced Micro Devices")) && !strstr(gl_renderer, "Mesa") && !strstr(gl_version, "Mesa"))
477 r_shadow_shadowmappcf = 1;
479 r_shadow_shadowmapsampler = vid.support.arb_shadow && r_shadow_shadowmapshadowsampler;
483 r_shadow_shadowmapsampler = vid.support.arb_shadow && r_shadow_shadowmapshadowsampler;
484 switch (r_shadow_shadowmapfilterquality)
489 r_shadow_shadowmappcf = 1;
492 r_shadow_shadowmappcf = 1;
495 r_shadow_shadowmappcf = 2;
499 if (!r_fb.usedepthtextures)
500 r_shadow_shadowmapsampler = false;
501 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
503 case RENDERPATH_D3D9:
504 case RENDERPATH_D3D10:
505 case RENDERPATH_D3D11:
506 case RENDERPATH_SOFT:
507 r_shadow_shadowmapsampler = false;
508 r_shadow_shadowmappcf = 1;
509 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
511 case RENDERPATH_GL11:
512 case RENDERPATH_GL13:
513 case RENDERPATH_GLES1:
514 case RENDERPATH_GLES2:
519 if(R_CompileShader_CheckStaticParms())
523 qboolean R_Shadow_ShadowMappingEnabled(void)
525 switch (r_shadow_shadowmode)
527 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
534 static void R_Shadow_FreeShadowMaps(void)
536 R_Shadow_SetShadowMode();
538 R_Mesh_DestroyFramebufferObject(r_shadow_fbo2d);
542 if (r_shadow_shadowmap2ddepthtexture)
543 R_FreeTexture(r_shadow_shadowmap2ddepthtexture);
544 r_shadow_shadowmap2ddepthtexture = NULL;
546 if (r_shadow_shadowmap2ddepthbuffer)
547 R_FreeTexture(r_shadow_shadowmap2ddepthbuffer);
548 r_shadow_shadowmap2ddepthbuffer = NULL;
550 if (r_shadow_shadowmapvsdcttexture)
551 R_FreeTexture(r_shadow_shadowmapvsdcttexture);
552 r_shadow_shadowmapvsdcttexture = NULL;
555 static void r_shadow_start(void)
557 // allocate vertex processing arrays
558 r_shadow_bouncegridpixels = NULL;
559 r_shadow_bouncegridhighpixels = NULL;
560 r_shadow_bouncegridnumpixels = 0;
561 r_shadow_bouncegridtexture = NULL;
562 r_shadow_bouncegriddirectional = false;
563 r_shadow_attenuationgradienttexture = NULL;
564 r_shadow_attenuation2dtexture = NULL;
565 r_shadow_attenuation3dtexture = NULL;
566 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
567 r_shadow_shadowmap2ddepthtexture = NULL;
568 r_shadow_shadowmap2ddepthbuffer = NULL;
569 r_shadow_shadowmapvsdcttexture = NULL;
570 r_shadow_shadowmapmaxsize = 0;
571 r_shadow_shadowmapsize = 0;
572 r_shadow_shadowmaplod = 0;
573 r_shadow_shadowmapfilterquality = -1;
574 r_shadow_shadowmapdepthbits = 0;
575 r_shadow_shadowmapvsdct = false;
576 r_shadow_shadowmapsampler = false;
577 r_shadow_shadowmappcf = 0;
580 R_Shadow_FreeShadowMaps();
582 r_shadow_texturepool = NULL;
583 r_shadow_filters_texturepool = NULL;
584 R_Shadow_ValidateCvars();
585 R_Shadow_MakeTextures();
586 maxshadowtriangles = 0;
587 shadowelements = NULL;
588 maxshadowvertices = 0;
589 shadowvertex3f = NULL;
597 shadowmarklist = NULL;
602 shadowsideslist = NULL;
603 r_shadow_buffer_numleafpvsbytes = 0;
604 r_shadow_buffer_visitingleafpvs = NULL;
605 r_shadow_buffer_leafpvs = NULL;
606 r_shadow_buffer_leaflist = NULL;
607 r_shadow_buffer_numsurfacepvsbytes = 0;
608 r_shadow_buffer_surfacepvs = NULL;
609 r_shadow_buffer_surfacelist = NULL;
610 r_shadow_buffer_surfacesides = NULL;
611 r_shadow_buffer_numshadowtrispvsbytes = 0;
612 r_shadow_buffer_shadowtrispvs = NULL;
613 r_shadow_buffer_numlighttrispvsbytes = 0;
614 r_shadow_buffer_lighttrispvs = NULL;
616 r_shadow_usingdeferredprepass = false;
617 r_shadow_prepass_width = r_shadow_prepass_height = 0;
620 static void R_Shadow_FreeDeferred(void);
621 static void r_shadow_shutdown(void)
624 R_Shadow_UncompileWorldLights();
626 R_Shadow_FreeShadowMaps();
628 r_shadow_usingdeferredprepass = false;
629 if (r_shadow_prepass_width)
630 R_Shadow_FreeDeferred();
631 r_shadow_prepass_width = r_shadow_prepass_height = 0;
634 r_shadow_bouncegridtexture = NULL;
635 r_shadow_bouncegridpixels = NULL;
636 r_shadow_bouncegridhighpixels = NULL;
637 r_shadow_bouncegridnumpixels = 0;
638 r_shadow_bouncegriddirectional = false;
639 r_shadow_attenuationgradienttexture = NULL;
640 r_shadow_attenuation2dtexture = NULL;
641 r_shadow_attenuation3dtexture = NULL;
642 R_FreeTexturePool(&r_shadow_texturepool);
643 R_FreeTexturePool(&r_shadow_filters_texturepool);
644 maxshadowtriangles = 0;
646 Mem_Free(shadowelements);
647 shadowelements = NULL;
649 Mem_Free(shadowvertex3f);
650 shadowvertex3f = NULL;
653 Mem_Free(vertexupdate);
656 Mem_Free(vertexremap);
662 Mem_Free(shadowmark);
665 Mem_Free(shadowmarklist);
666 shadowmarklist = NULL;
671 Mem_Free(shadowsides);
674 Mem_Free(shadowsideslist);
675 shadowsideslist = NULL;
676 r_shadow_buffer_numleafpvsbytes = 0;
677 if (r_shadow_buffer_visitingleafpvs)
678 Mem_Free(r_shadow_buffer_visitingleafpvs);
679 r_shadow_buffer_visitingleafpvs = NULL;
680 if (r_shadow_buffer_leafpvs)
681 Mem_Free(r_shadow_buffer_leafpvs);
682 r_shadow_buffer_leafpvs = NULL;
683 if (r_shadow_buffer_leaflist)
684 Mem_Free(r_shadow_buffer_leaflist);
685 r_shadow_buffer_leaflist = NULL;
686 r_shadow_buffer_numsurfacepvsbytes = 0;
687 if (r_shadow_buffer_surfacepvs)
688 Mem_Free(r_shadow_buffer_surfacepvs);
689 r_shadow_buffer_surfacepvs = NULL;
690 if (r_shadow_buffer_surfacelist)
691 Mem_Free(r_shadow_buffer_surfacelist);
692 r_shadow_buffer_surfacelist = NULL;
693 if (r_shadow_buffer_surfacesides)
694 Mem_Free(r_shadow_buffer_surfacesides);
695 r_shadow_buffer_surfacesides = NULL;
696 r_shadow_buffer_numshadowtrispvsbytes = 0;
697 if (r_shadow_buffer_shadowtrispvs)
698 Mem_Free(r_shadow_buffer_shadowtrispvs);
699 r_shadow_buffer_numlighttrispvsbytes = 0;
700 if (r_shadow_buffer_lighttrispvs)
701 Mem_Free(r_shadow_buffer_lighttrispvs);
704 static void r_shadow_newmap(void)
706 if (r_shadow_bouncegridtexture) R_FreeTexture(r_shadow_bouncegridtexture);r_shadow_bouncegridtexture = NULL;
707 if (r_shadow_lightcorona) R_SkinFrame_MarkUsed(r_shadow_lightcorona);
708 if (r_editlights_sprcursor) R_SkinFrame_MarkUsed(r_editlights_sprcursor);
709 if (r_editlights_sprlight) R_SkinFrame_MarkUsed(r_editlights_sprlight);
710 if (r_editlights_sprnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprnoshadowlight);
711 if (r_editlights_sprcubemaplight) R_SkinFrame_MarkUsed(r_editlights_sprcubemaplight);
712 if (r_editlights_sprcubemapnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprcubemapnoshadowlight);
713 if (r_editlights_sprselection) R_SkinFrame_MarkUsed(r_editlights_sprselection);
714 if (strncmp(cl.worldname, r_shadow_mapname, sizeof(r_shadow_mapname)))
715 R_Shadow_EditLights_Reload_f();
718 void R_Shadow_Init(void)
720 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
721 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
722 Cvar_RegisterVariable(&r_shadow_usebihculling);
723 Cvar_RegisterVariable(&r_shadow_usenormalmap);
724 Cvar_RegisterVariable(&r_shadow_debuglight);
725 Cvar_RegisterVariable(&r_shadow_deferred);
726 Cvar_RegisterVariable(&r_shadow_gloss);
727 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
728 Cvar_RegisterVariable(&r_shadow_glossintensity);
729 Cvar_RegisterVariable(&r_shadow_glossexponent);
730 Cvar_RegisterVariable(&r_shadow_gloss2exponent);
731 Cvar_RegisterVariable(&r_shadow_glossexact);
732 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
733 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
734 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
735 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
736 Cvar_RegisterVariable(&r_shadow_projectdistance);
737 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
738 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
739 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
740 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
741 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
742 Cvar_RegisterVariable(&r_shadow_realtime_world);
743 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
744 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
745 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
746 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
747 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
748 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
749 Cvar_RegisterVariable(&r_shadow_scissor);
750 Cvar_RegisterVariable(&r_shadow_shadowmapping);
751 Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
752 Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
753 Cvar_RegisterVariable(&r_shadow_shadowmapping_useshadowsampler);
754 Cvar_RegisterVariable(&r_shadow_shadowmapping_depthbits);
755 Cvar_RegisterVariable(&r_shadow_shadowmapping_precision);
756 Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
757 Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
758 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
759 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
760 Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
761 Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
762 Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
763 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonfactor);
764 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonoffset);
765 Cvar_RegisterVariable(&r_shadow_sortsurfaces);
766 Cvar_RegisterVariable(&r_shadow_polygonfactor);
767 Cvar_RegisterVariable(&r_shadow_polygonoffset);
768 Cvar_RegisterVariable(&r_shadow_texture3d);
769 Cvar_RegisterVariable(&r_shadow_bouncegrid);
770 Cvar_RegisterVariable(&r_shadow_bouncegrid_bounceanglediffuse);
771 Cvar_RegisterVariable(&r_shadow_bouncegrid_directionalshading);
772 Cvar_RegisterVariable(&r_shadow_bouncegrid_dlightparticlemultiplier);
773 Cvar_RegisterVariable(&r_shadow_bouncegrid_hitmodels);
774 Cvar_RegisterVariable(&r_shadow_bouncegrid_includedirectlighting);
775 Cvar_RegisterVariable(&r_shadow_bouncegrid_intensity);
776 Cvar_RegisterVariable(&r_shadow_bouncegrid_lightradiusscale);
777 Cvar_RegisterVariable(&r_shadow_bouncegrid_maxbounce);
778 Cvar_RegisterVariable(&r_shadow_bouncegrid_particlebounceintensity);
779 Cvar_RegisterVariable(&r_shadow_bouncegrid_particleintensity);
780 Cvar_RegisterVariable(&r_shadow_bouncegrid_photons);
781 Cvar_RegisterVariable(&r_shadow_bouncegrid_spacing);
782 Cvar_RegisterVariable(&r_shadow_bouncegrid_stablerandom);
783 Cvar_RegisterVariable(&r_shadow_bouncegrid_static);
784 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_directionalshading);
785 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_lightradiusscale);
786 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_maxbounce);
787 Cvar_RegisterVariable(&r_shadow_bouncegrid_static_photons);
788 Cvar_RegisterVariable(&r_shadow_bouncegrid_updateinterval);
789 Cvar_RegisterVariable(&r_shadow_bouncegrid_x);
790 Cvar_RegisterVariable(&r_shadow_bouncegrid_y);
791 Cvar_RegisterVariable(&r_shadow_bouncegrid_z);
792 Cvar_RegisterVariable(&r_coronas);
793 Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
794 Cvar_RegisterVariable(&r_coronas_occlusionquery);
795 Cvar_RegisterVariable(&gl_flashblend);
796 Cvar_RegisterVariable(&gl_ext_separatestencil);
797 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
798 R_Shadow_EditLights_Init();
799 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
800 maxshadowtriangles = 0;
801 shadowelements = NULL;
802 maxshadowvertices = 0;
803 shadowvertex3f = NULL;
811 shadowmarklist = NULL;
816 shadowsideslist = NULL;
817 r_shadow_buffer_numleafpvsbytes = 0;
818 r_shadow_buffer_visitingleafpvs = NULL;
819 r_shadow_buffer_leafpvs = NULL;
820 r_shadow_buffer_leaflist = NULL;
821 r_shadow_buffer_numsurfacepvsbytes = 0;
822 r_shadow_buffer_surfacepvs = NULL;
823 r_shadow_buffer_surfacelist = NULL;
824 r_shadow_buffer_surfacesides = NULL;
825 r_shadow_buffer_shadowtrispvs = NULL;
826 r_shadow_buffer_lighttrispvs = NULL;
827 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap, NULL, NULL);
830 matrix4x4_t matrix_attenuationxyz =
833 {0.5, 0.0, 0.0, 0.5},
834 {0.0, 0.5, 0.0, 0.5},
835 {0.0, 0.0, 0.5, 0.5},
840 matrix4x4_t matrix_attenuationz =
843 {0.0, 0.0, 0.5, 0.5},
844 {0.0, 0.0, 0.0, 0.5},
845 {0.0, 0.0, 0.0, 0.5},
850 static void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles, int vertscale, int triscale)
852 numvertices = ((numvertices + 255) & ~255) * vertscale;
853 numtriangles = ((numtriangles + 255) & ~255) * triscale;
854 // make sure shadowelements is big enough for this volume
855 if (maxshadowtriangles < numtriangles)
857 maxshadowtriangles = numtriangles;
859 Mem_Free(shadowelements);
860 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[3]));
862 // make sure shadowvertex3f is big enough for this volume
863 if (maxshadowvertices < numvertices)
865 maxshadowvertices = numvertices;
867 Mem_Free(shadowvertex3f);
868 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[3]));
872 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
874 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
875 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
876 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
877 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
878 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
880 if (r_shadow_buffer_visitingleafpvs)
881 Mem_Free(r_shadow_buffer_visitingleafpvs);
882 if (r_shadow_buffer_leafpvs)
883 Mem_Free(r_shadow_buffer_leafpvs);
884 if (r_shadow_buffer_leaflist)
885 Mem_Free(r_shadow_buffer_leaflist);
886 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
887 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
888 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
889 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
891 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
893 if (r_shadow_buffer_surfacepvs)
894 Mem_Free(r_shadow_buffer_surfacepvs);
895 if (r_shadow_buffer_surfacelist)
896 Mem_Free(r_shadow_buffer_surfacelist);
897 if (r_shadow_buffer_surfacesides)
898 Mem_Free(r_shadow_buffer_surfacesides);
899 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
900 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
901 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
902 r_shadow_buffer_surfacesides = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
904 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
906 if (r_shadow_buffer_shadowtrispvs)
907 Mem_Free(r_shadow_buffer_shadowtrispvs);
908 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
909 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
911 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
913 if (r_shadow_buffer_lighttrispvs)
914 Mem_Free(r_shadow_buffer_lighttrispvs);
915 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
916 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
920 void R_Shadow_PrepareShadowMark(int numtris)
922 // make sure shadowmark is big enough for this volume
923 if (maxshadowmark < numtris)
925 maxshadowmark = numtris;
927 Mem_Free(shadowmark);
929 Mem_Free(shadowmarklist);
930 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
931 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
935 // if shadowmarkcount wrapped we clear the array and adjust accordingly
936 if (shadowmarkcount == 0)
939 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
944 void R_Shadow_PrepareShadowSides(int numtris)
946 if (maxshadowsides < numtris)
948 maxshadowsides = numtris;
950 Mem_Free(shadowsides);
952 Mem_Free(shadowsideslist);
953 shadowsides = (unsigned char *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsides));
954 shadowsideslist = (int *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsideslist));
959 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)
962 int outtriangles = 0, outvertices = 0;
965 float ratio, direction[3], projectvector[3];
967 if (projectdirection)
968 VectorScale(projectdirection, projectdistance, projectvector);
970 VectorClear(projectvector);
972 // create the vertices
973 if (projectdirection)
975 for (i = 0;i < numshadowmarktris;i++)
977 element = inelement3i + shadowmarktris[i] * 3;
978 for (j = 0;j < 3;j++)
980 if (vertexupdate[element[j]] != vertexupdatenum)
982 vertexupdate[element[j]] = vertexupdatenum;
983 vertexremap[element[j]] = outvertices;
984 vertex = invertex3f + element[j] * 3;
985 // project one copy of the vertex according to projectvector
986 VectorCopy(vertex, outvertex3f);
987 VectorAdd(vertex, projectvector, (outvertex3f + 3));
996 for (i = 0;i < numshadowmarktris;i++)
998 element = inelement3i + shadowmarktris[i] * 3;
999 for (j = 0;j < 3;j++)
1001 if (vertexupdate[element[j]] != vertexupdatenum)
1003 vertexupdate[element[j]] = vertexupdatenum;
1004 vertexremap[element[j]] = outvertices;
1005 vertex = invertex3f + element[j] * 3;
1006 // project one copy of the vertex to the sphere radius of the light
1007 // (FIXME: would projecting it to the light box be better?)
1008 VectorSubtract(vertex, projectorigin, direction);
1009 ratio = projectdistance / VectorLength(direction);
1010 VectorCopy(vertex, outvertex3f);
1011 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1019 if (r_shadow_frontsidecasting.integer)
1021 for (i = 0;i < numshadowmarktris;i++)
1023 int remappedelement[3];
1025 const int *neighbortriangle;
1027 markindex = shadowmarktris[i] * 3;
1028 element = inelement3i + markindex;
1029 neighbortriangle = inneighbor3i + markindex;
1030 // output the front and back triangles
1031 outelement3i[0] = vertexremap[element[0]];
1032 outelement3i[1] = vertexremap[element[1]];
1033 outelement3i[2] = vertexremap[element[2]];
1034 outelement3i[3] = vertexremap[element[2]] + 1;
1035 outelement3i[4] = vertexremap[element[1]] + 1;
1036 outelement3i[5] = vertexremap[element[0]] + 1;
1040 // output the sides (facing outward from this triangle)
1041 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
1043 remappedelement[0] = vertexremap[element[0]];
1044 remappedelement[1] = vertexremap[element[1]];
1045 outelement3i[0] = remappedelement[1];
1046 outelement3i[1] = remappedelement[0];
1047 outelement3i[2] = remappedelement[0] + 1;
1048 outelement3i[3] = remappedelement[1];
1049 outelement3i[4] = remappedelement[0] + 1;
1050 outelement3i[5] = remappedelement[1] + 1;
1055 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1057 remappedelement[1] = vertexremap[element[1]];
1058 remappedelement[2] = vertexremap[element[2]];
1059 outelement3i[0] = remappedelement[2];
1060 outelement3i[1] = remappedelement[1];
1061 outelement3i[2] = remappedelement[1] + 1;
1062 outelement3i[3] = remappedelement[2];
1063 outelement3i[4] = remappedelement[1] + 1;
1064 outelement3i[5] = remappedelement[2] + 1;
1069 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1071 remappedelement[0] = vertexremap[element[0]];
1072 remappedelement[2] = vertexremap[element[2]];
1073 outelement3i[0] = remappedelement[0];
1074 outelement3i[1] = remappedelement[2];
1075 outelement3i[2] = remappedelement[2] + 1;
1076 outelement3i[3] = remappedelement[0];
1077 outelement3i[4] = remappedelement[2] + 1;
1078 outelement3i[5] = remappedelement[0] + 1;
1087 for (i = 0;i < numshadowmarktris;i++)
1089 int remappedelement[3];
1091 const int *neighbortriangle;
1093 markindex = shadowmarktris[i] * 3;
1094 element = inelement3i + markindex;
1095 neighbortriangle = inneighbor3i + markindex;
1096 // output the front and back triangles
1097 outelement3i[0] = vertexremap[element[2]];
1098 outelement3i[1] = vertexremap[element[1]];
1099 outelement3i[2] = vertexremap[element[0]];
1100 outelement3i[3] = vertexremap[element[0]] + 1;
1101 outelement3i[4] = vertexremap[element[1]] + 1;
1102 outelement3i[5] = vertexremap[element[2]] + 1;
1106 // output the sides (facing outward from this triangle)
1107 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
1109 remappedelement[0] = vertexremap[element[0]];
1110 remappedelement[1] = vertexremap[element[1]];
1111 outelement3i[0] = remappedelement[0];
1112 outelement3i[1] = remappedelement[1];
1113 outelement3i[2] = remappedelement[1] + 1;
1114 outelement3i[3] = remappedelement[0];
1115 outelement3i[4] = remappedelement[1] + 1;
1116 outelement3i[5] = remappedelement[0] + 1;
1121 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1123 remappedelement[1] = vertexremap[element[1]];
1124 remappedelement[2] = vertexremap[element[2]];
1125 outelement3i[0] = remappedelement[1];
1126 outelement3i[1] = remappedelement[2];
1127 outelement3i[2] = remappedelement[2] + 1;
1128 outelement3i[3] = remappedelement[1];
1129 outelement3i[4] = remappedelement[2] + 1;
1130 outelement3i[5] = remappedelement[1] + 1;
1135 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1137 remappedelement[0] = vertexremap[element[0]];
1138 remappedelement[2] = vertexremap[element[2]];
1139 outelement3i[0] = remappedelement[2];
1140 outelement3i[1] = remappedelement[0];
1141 outelement3i[2] = remappedelement[0] + 1;
1142 outelement3i[3] = remappedelement[2];
1143 outelement3i[4] = remappedelement[0] + 1;
1144 outelement3i[5] = remappedelement[2] + 1;
1152 *outnumvertices = outvertices;
1153 return outtriangles;
1156 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)
1159 int outtriangles = 0, outvertices = 0;
1161 const float *vertex;
1162 float ratio, direction[3], projectvector[3];
1165 if (projectdirection)
1166 VectorScale(projectdirection, projectdistance, projectvector);
1168 VectorClear(projectvector);
1170 for (i = 0;i < numshadowmarktris;i++)
1172 int remappedelement[3];
1174 const int *neighbortriangle;
1176 markindex = shadowmarktris[i] * 3;
1177 neighbortriangle = inneighbor3i + markindex;
1178 side[0] = shadowmark[neighbortriangle[0]] == shadowmarkcount;
1179 side[1] = shadowmark[neighbortriangle[1]] == shadowmarkcount;
1180 side[2] = shadowmark[neighbortriangle[2]] == shadowmarkcount;
1181 if (side[0] + side[1] + side[2] == 0)
1185 element = inelement3i + markindex;
1187 // create the vertices
1188 for (j = 0;j < 3;j++)
1190 if (side[j] + side[j+1] == 0)
1193 if (vertexupdate[k] != vertexupdatenum)
1195 vertexupdate[k] = vertexupdatenum;
1196 vertexremap[k] = outvertices;
1197 vertex = invertex3f + k * 3;
1198 VectorCopy(vertex, outvertex3f);
1199 if (projectdirection)
1201 // project one copy of the vertex according to projectvector
1202 VectorAdd(vertex, projectvector, (outvertex3f + 3));
1206 // project one copy of the vertex to the sphere radius of the light
1207 // (FIXME: would projecting it to the light box be better?)
1208 VectorSubtract(vertex, projectorigin, direction);
1209 ratio = projectdistance / VectorLength(direction);
1210 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1217 // output the sides (facing outward from this triangle)
1220 remappedelement[0] = vertexremap[element[0]];
1221 remappedelement[1] = vertexremap[element[1]];
1222 outelement3i[0] = remappedelement[1];
1223 outelement3i[1] = remappedelement[0];
1224 outelement3i[2] = remappedelement[0] + 1;
1225 outelement3i[3] = remappedelement[1];
1226 outelement3i[4] = remappedelement[0] + 1;
1227 outelement3i[5] = remappedelement[1] + 1;
1234 remappedelement[1] = vertexremap[element[1]];
1235 remappedelement[2] = vertexremap[element[2]];
1236 outelement3i[0] = remappedelement[2];
1237 outelement3i[1] = remappedelement[1];
1238 outelement3i[2] = remappedelement[1] + 1;
1239 outelement3i[3] = remappedelement[2];
1240 outelement3i[4] = remappedelement[1] + 1;
1241 outelement3i[5] = remappedelement[2] + 1;
1248 remappedelement[0] = vertexremap[element[0]];
1249 remappedelement[2] = vertexremap[element[2]];
1250 outelement3i[0] = remappedelement[0];
1251 outelement3i[1] = remappedelement[2];
1252 outelement3i[2] = remappedelement[2] + 1;
1253 outelement3i[3] = remappedelement[0];
1254 outelement3i[4] = remappedelement[2] + 1;
1255 outelement3i[5] = remappedelement[0] + 1;
1262 *outnumvertices = outvertices;
1263 return outtriangles;
1266 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)
1272 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1274 tend = firsttriangle + numtris;
1275 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1277 // surface box entirely inside light box, no box cull
1278 if (projectdirection)
1280 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1282 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
1283 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1284 shadowmarklist[numshadowmark++] = t;
1289 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1290 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
1291 shadowmarklist[numshadowmark++] = t;
1296 // surface box not entirely inside light box, cull each triangle
1297 if (projectdirection)
1299 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1301 v[0] = invertex3f + e[0] * 3;
1302 v[1] = invertex3f + e[1] * 3;
1303 v[2] = invertex3f + e[2] * 3;
1304 TriangleNormal(v[0], v[1], v[2], normal);
1305 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1306 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1307 shadowmarklist[numshadowmark++] = t;
1312 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1314 v[0] = invertex3f + e[0] * 3;
1315 v[1] = invertex3f + e[1] * 3;
1316 v[2] = invertex3f + e[2] * 3;
1317 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1318 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1319 shadowmarklist[numshadowmark++] = t;
1325 static qboolean R_Shadow_UseZPass(vec3_t mins, vec3_t maxs)
1330 if (r_shadow_compilingrtlight || !r_shadow_frontsidecasting.integer || !r_shadow_usezpassifpossible.integer)
1332 // check if the shadow volume intersects the near plane
1334 // a ray between the eye and light origin may intersect the caster,
1335 // indicating that the shadow may touch the eye location, however we must
1336 // test the near plane (a polygon), not merely the eye location, so it is
1337 // easiest to enlarge the caster bounding shape slightly for this.
1343 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)
1345 int i, tris, outverts;
1346 if (projectdistance < 0.1)
1348 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
1351 if (!numverts || !nummarktris)
1353 // make sure shadowelements is big enough for this volume
1354 if (maxshadowtriangles < nummarktris*8 || maxshadowvertices < numverts*2)
1355 R_Shadow_ResizeShadowArrays(numverts, nummarktris, 2, 8);
1357 if (maxvertexupdate < numverts)
1359 maxvertexupdate = numverts;
1361 Mem_Free(vertexupdate);
1363 Mem_Free(vertexremap);
1364 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1365 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1366 vertexupdatenum = 0;
1369 if (vertexupdatenum == 0)
1371 vertexupdatenum = 1;
1372 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
1373 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
1376 for (i = 0;i < nummarktris;i++)
1377 shadowmark[marktris[i]] = shadowmarkcount;
1379 if (r_shadow_compilingrtlight)
1381 // if we're compiling an rtlight, capture the mesh
1382 //tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1383 //Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zpass, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1384 tris = R_Shadow_ConstructShadowVolume_ZFail(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_zfail, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1387 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
1389 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1390 R_Mesh_PrepareVertices_Vertex3f(outverts, shadowvertex3f, NULL, 0);
1391 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1395 // decide which type of shadow to generate and set stencil mode
1396 R_Shadow_RenderMode_StencilShadowVolumes(R_Shadow_UseZPass(trismins, trismaxs));
1397 // generate the sides or a solid volume, depending on type
1398 if (r_shadow_rendermode >= R_SHADOW_RENDERMODE_ZPASS_STENCIL && r_shadow_rendermode <= R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE)
1399 tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1401 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1402 r_refdef.stats[r_stat_lights_dynamicshadowtriangles] += tris;
1403 r_refdef.stats[r_stat_lights_shadowtriangles] += tris;
1404 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
1406 // increment stencil if frontface is infront of depthbuffer
1407 GL_CullFace(r_refdef.view.cullface_front);
1408 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
1409 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1410 // decrement stencil if backface is infront of depthbuffer
1411 GL_CullFace(r_refdef.view.cullface_back);
1412 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
1414 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
1416 // decrement stencil if backface is behind depthbuffer
1417 GL_CullFace(r_refdef.view.cullface_front);
1418 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
1419 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1420 // increment stencil if frontface is behind depthbuffer
1421 GL_CullFace(r_refdef.view.cullface_back);
1422 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
1424 R_Mesh_PrepareVertices_Vertex3f(outverts, shadowvertex3f, NULL, 0);
1425 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1429 int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias)
1431 // p1, p2, p3 are in the cubemap's local coordinate system
1432 // bias = border/(size - border)
1435 float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1436 dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2),
1437 dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3);
1438 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1440 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1441 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1442 | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1443 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1445 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1446 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1447 | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1449 dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1450 dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2),
1451 dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3);
1452 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1454 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1455 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1456 | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1457 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1459 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1460 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1461 | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1463 dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1464 dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2),
1465 dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3);
1466 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1468 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1469 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1470 | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1471 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1473 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1474 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1475 | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1480 static int R_Shadow_CalcBBoxSideMask(const vec3_t mins, const vec3_t maxs, const matrix4x4_t *worldtolight, const matrix4x4_t *radiustolight, float bias)
1482 vec3_t center, radius, lightcenter, lightradius, pmin, pmax;
1483 float dp1, dn1, ap1, an1, dp2, dn2, ap2, an2;
1486 VectorSubtract(maxs, mins, radius);
1487 VectorScale(radius, 0.5f, radius);
1488 VectorAdd(mins, radius, center);
1489 Matrix4x4_Transform(worldtolight, center, lightcenter);
1490 Matrix4x4_Transform3x3(radiustolight, radius, lightradius);
1491 VectorSubtract(lightcenter, lightradius, pmin);
1492 VectorAdd(lightcenter, lightradius, pmax);
1494 dp1 = pmax[0] + pmax[1], dn1 = pmax[0] - pmin[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1495 dp2 = pmin[0] + pmin[1], dn2 = pmin[0] - pmax[1], ap2 = fabs(dp2), an2 = fabs(dn2);
1496 if(ap1 > bias*an1 && ap2 > bias*an2)
1498 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1499 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1500 if(an1 > bias*ap1 && an2 > bias*ap2)
1502 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1503 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1505 dp1 = pmax[1] + pmax[2], dn1 = pmax[1] - pmin[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1506 dp2 = pmin[1] + pmin[2], dn2 = pmin[1] - pmax[2], ap2 = fabs(dp2), an2 = fabs(dn2);
1507 if(ap1 > bias*an1 && ap2 > bias*an2)
1509 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1510 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1511 if(an1 > bias*ap1 && an2 > bias*ap2)
1513 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1514 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1516 dp1 = pmax[2] + pmax[0], dn1 = pmax[2] - pmin[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1517 dp2 = pmin[2] + pmin[0], dn2 = pmin[2] - pmax[0], ap2 = fabs(dp2), an2 = fabs(dn2);
1518 if(ap1 > bias*an1 && ap2 > bias*an2)
1520 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1521 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1522 if(an1 > bias*ap1 && an2 > bias*ap2)
1524 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1525 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1530 #define R_Shadow_CalcEntitySideMask(ent, worldtolight, radiustolight, bias) R_Shadow_CalcBBoxSideMask((ent)->mins, (ent)->maxs, worldtolight, radiustolight, bias)
1532 int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
1534 // p is in the cubemap's local coordinate system
1535 // bias = border/(size - border)
1536 float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn);
1537 float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn);
1538 float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn);
1540 if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
1541 if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
1542 if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
1543 if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
1544 if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
1545 if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
1549 static int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
1553 int sides = 0x3F, masks[6] = { 3<<4, 3<<4, 3<<0, 3<<0, 3<<2, 3<<2 };
1554 float scale = (size - 2*border)/size, len;
1555 float bias = border / (float)(size - border), dp, dn, ap, an;
1556 // check if cone enclosing side would cross frustum plane
1557 scale = 2 / (scale*scale + 2);
1558 Matrix4x4_OriginFromMatrix(&rtlight->matrix_lighttoworld, o);
1559 for (i = 0;i < 5;i++)
1561 if (PlaneDiff(o, &r_refdef.view.frustum[i]) > -0.03125)
1563 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[i].normal, n);
1564 len = scale*VectorLength2(n);
1565 if(n[0]*n[0] > len) sides &= n[0] < 0 ? ~(1<<0) : ~(2 << 0);
1566 if(n[1]*n[1] > len) sides &= n[1] < 0 ? ~(1<<2) : ~(2 << 2);
1567 if(n[2]*n[2] > len) sides &= n[2] < 0 ? ~(1<<4) : ~(2 << 4);
1569 if (PlaneDiff(o, &r_refdef.view.frustum[4]) >= r_refdef.farclip - r_refdef.nearclip + 0.03125)
1571 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[4].normal, n);
1572 len = scale*VectorLength2(n);
1573 if(n[0]*n[0] > len) sides &= n[0] >= 0 ? ~(1<<0) : ~(2 << 0);
1574 if(n[1]*n[1] > len) sides &= n[1] >= 0 ? ~(1<<2) : ~(2 << 2);
1575 if(n[2]*n[2] > len) sides &= n[2] >= 0 ? ~(1<<4) : ~(2 << 4);
1577 // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results
1578 // check if frustum corners/origin cross plane sides
1580 // infinite version, assumes frustum corners merely give direction and extend to infinite distance
1581 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.origin, p);
1582 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1583 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1584 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1585 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1586 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1587 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1588 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1589 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1590 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1591 for (i = 0;i < 4;i++)
1593 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.frustumcorner[i], n);
1594 VectorSubtract(n, p, n);
1595 dp = n[0] + n[1], dn = n[0] - n[1], ap = fabs(dp), an = fabs(dn);
1596 if(ap > 0) masks[0] |= dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2);
1597 if(an > 0) masks[1] |= dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2);
1598 dp = n[1] + n[2], dn = n[1] - n[2], ap = fabs(dp), an = fabs(dn);
1599 if(ap > 0) masks[2] |= dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4);
1600 if(an > 0) masks[3] |= dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4);
1601 dp = n[2] + n[0], dn = n[2] - n[0], ap = fabs(dp), an = fabs(dn);
1602 if(ap > 0) masks[4] |= dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0);
1603 if(an > 0) masks[5] |= dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0);
1606 // finite version, assumes corners are a finite distance from origin dependent on far plane
1607 for (i = 0;i < 5;i++)
1609 Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p);
1610 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1611 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1612 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1613 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1614 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1615 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1616 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1617 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1618 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1621 return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5];
1624 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)
1632 int mask, surfacemask = 0;
1633 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1635 bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
1636 tend = firsttriangle + numtris;
1637 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1639 // surface box entirely inside light box, no box cull
1640 if (projectdirection)
1642 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1644 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1645 TriangleNormal(v[0], v[1], v[2], normal);
1646 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1648 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1649 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1650 surfacemask |= mask;
1653 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;
1654 shadowsides[numshadowsides] = mask;
1655 shadowsideslist[numshadowsides++] = t;
1662 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1664 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1665 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]))
1667 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1668 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1669 surfacemask |= mask;
1672 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;
1673 shadowsides[numshadowsides] = mask;
1674 shadowsideslist[numshadowsides++] = t;
1682 // surface box not entirely inside light box, cull each triangle
1683 if (projectdirection)
1685 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1687 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1688 TriangleNormal(v[0], v[1], v[2], normal);
1689 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1690 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1692 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1693 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1694 surfacemask |= mask;
1697 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;
1698 shadowsides[numshadowsides] = mask;
1699 shadowsideslist[numshadowsides++] = t;
1706 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1708 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1709 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1710 && TriangleBBoxOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1712 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1713 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1714 surfacemask |= mask;
1717 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;
1718 shadowsides[numshadowsides] = mask;
1719 shadowsideslist[numshadowsides++] = t;
1728 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)
1730 int i, j, outtriangles = 0;
1731 int *outelement3i[6];
1732 if (!numverts || !numsidetris || !r_shadow_compilingrtlight)
1734 outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5];
1735 // make sure shadowelements is big enough for this mesh
1736 if (maxshadowtriangles < outtriangles)
1737 R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1);
1739 // compute the offset and size of the separate index lists for each cubemap side
1741 for (i = 0;i < 6;i++)
1743 outelement3i[i] = shadowelements + outtriangles * 3;
1744 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles;
1745 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i];
1746 outtriangles += sidetotals[i];
1749 // gather up the (sparse) triangles into separate index lists for each cubemap side
1750 for (i = 0;i < numsidetris;i++)
1752 const int *element = elements + sidetris[i] * 3;
1753 for (j = 0;j < 6;j++)
1755 if (sides[i] & (1 << j))
1757 outelement3i[j][0] = element[0];
1758 outelement3i[j][1] = element[1];
1759 outelement3i[j][2] = element[2];
1760 outelement3i[j] += 3;
1765 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, outtriangles, shadowelements);
1768 static void R_Shadow_MakeTextures_MakeCorona(void)
1772 unsigned char pixels[32][32][4];
1773 for (y = 0;y < 32;y++)
1775 dy = (y - 15.5f) * (1.0f / 16.0f);
1776 for (x = 0;x < 32;x++)
1778 dx = (x - 15.5f) * (1.0f / 16.0f);
1779 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1780 a = bound(0, a, 255);
1781 pixels[y][x][0] = a;
1782 pixels[y][x][1] = a;
1783 pixels[y][x][2] = a;
1784 pixels[y][x][3] = 255;
1787 r_shadow_lightcorona = R_SkinFrame_LoadInternalBGRA("lightcorona", TEXF_FORCELINEAR, &pixels[0][0][0], 32, 32, false);
1790 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1792 float dist = sqrt(x*x+y*y+z*z);
1793 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1794 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1795 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1798 static void R_Shadow_MakeTextures(void)
1801 float intensity, dist;
1803 R_Shadow_FreeShadowMaps();
1804 R_FreeTexturePool(&r_shadow_texturepool);
1805 r_shadow_texturepool = R_AllocTexturePool();
1806 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1807 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1808 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1809 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1810 for (x = 0;x <= ATTENTABLESIZE;x++)
1812 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1813 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1814 r_shadow_attentable[x] = bound(0, intensity, 1);
1816 // 1D gradient texture
1817 for (x = 0;x < ATTEN1DSIZE;x++)
1818 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1819 r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1820 // 2D circle texture
1821 for (y = 0;y < ATTEN2DSIZE;y++)
1822 for (x = 0;x < ATTEN2DSIZE;x++)
1823 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);
1824 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1825 // 3D sphere texture
1826 if (r_shadow_texture3d.integer && vid.support.ext_texture_3d)
1828 for (z = 0;z < ATTEN3DSIZE;z++)
1829 for (y = 0;y < ATTEN3DSIZE;y++)
1830 for (x = 0;x < ATTEN3DSIZE;x++)
1831 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));
1832 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);
1835 r_shadow_attenuation3dtexture = NULL;
1838 R_Shadow_MakeTextures_MakeCorona();
1840 // Editor light sprites
1841 r_editlights_sprcursor = R_SkinFrame_LoadInternal8bit("gfx/editlights/cursor", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1858 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1859 r_editlights_sprlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/light", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1876 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1877 r_editlights_sprnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/noshadow", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1894 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1895 r_editlights_sprcubemaplight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemaplight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1912 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1913 r_editlights_sprcubemapnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemapnoshadowlight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1930 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1931 r_editlights_sprselection = R_SkinFrame_LoadInternal8bit("gfx/editlights/selection", TEXF_ALPHA | TEXF_CLAMP, (unsigned char *)
1948 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1951 void R_Shadow_ValidateCvars(void)
1953 if (r_shadow_texture3d.integer && !vid.support.ext_texture_3d)
1954 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1955 if (gl_ext_separatestencil.integer && !vid.support.ati_separate_stencil)
1956 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
1957 if (gl_ext_stenciltwoside.integer && !vid.support.ext_stencil_two_side)
1958 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1961 void R_Shadow_RenderMode_Begin(void)
1967 R_Shadow_ValidateCvars();
1969 if (!r_shadow_attenuation2dtexture
1970 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1971 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1972 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1973 R_Shadow_MakeTextures();
1976 R_Mesh_ResetTextureState();
1977 GL_BlendFunc(GL_ONE, GL_ZERO);
1978 GL_DepthRange(0, 1);
1979 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1981 GL_DepthMask(false);
1982 GL_Color(0, 0, 0, 1);
1983 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1985 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1987 if (gl_ext_separatestencil.integer && vid.support.ati_separate_stencil)
1989 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
1990 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
1992 else if (gl_ext_stenciltwoside.integer && vid.support.ext_stencil_two_side)
1994 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
1995 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
1999 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
2000 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
2003 switch(vid.renderpath)
2005 case RENDERPATH_GL20:
2006 case RENDERPATH_D3D9:
2007 case RENDERPATH_D3D10:
2008 case RENDERPATH_D3D11:
2009 case RENDERPATH_SOFT:
2010 case RENDERPATH_GLES2:
2011 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
2013 case RENDERPATH_GL11:
2014 case RENDERPATH_GL13:
2015 case RENDERPATH_GLES1:
2016 if (r_textureunits.integer >= 2 && vid.texunits >= 2 && r_shadow_texture3d.integer && r_shadow_attenuation3dtexture)
2017 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN;
2018 else if (r_textureunits.integer >= 3 && vid.texunits >= 3)
2019 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN;
2020 else if (r_textureunits.integer >= 2 && vid.texunits >= 2)
2021 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN;
2023 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
2029 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
2030 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
2031 r_shadow_drawbuffer = drawbuffer;
2032 r_shadow_readbuffer = readbuffer;
2034 r_shadow_cullface_front = r_refdef.view.cullface_front;
2035 r_shadow_cullface_back = r_refdef.view.cullface_back;
2038 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
2040 rsurface.rtlight = rtlight;
2043 void R_Shadow_RenderMode_Reset(void)
2045 R_Mesh_ResetTextureState();
2046 R_Mesh_SetRenderTargets(r_shadow_fb_fbo, r_shadow_fb_depthtexture, r_shadow_fb_colortexture, NULL, NULL, NULL);
2047 R_SetViewport(&r_refdef.view.viewport);
2048 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
2049 GL_DepthRange(0, 1);
2051 GL_DepthMask(false);
2052 GL_DepthFunc(GL_LEQUAL);
2053 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
2054 r_refdef.view.cullface_front = r_shadow_cullface_front;
2055 r_refdef.view.cullface_back = r_shadow_cullface_back;
2056 GL_CullFace(r_refdef.view.cullface_back);
2057 GL_Color(1, 1, 1, 1);
2058 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
2059 GL_BlendFunc(GL_ONE, GL_ZERO);
2060 R_SetupShader_Generic_NoTexture(false, false);
2061 r_shadow_usingshadowmap2d = false;
2062 r_shadow_usingshadowmaportho = false;
2063 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
2066 void R_Shadow_ClearStencil(void)
2068 GL_Clear(GL_STENCIL_BUFFER_BIT, NULL, 1.0f, 128);
2069 r_refdef.stats[r_stat_lights_clears]++;
2072 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
2074 r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
2075 if (r_shadow_rendermode == mode)
2077 R_Shadow_RenderMode_Reset();
2078 GL_DepthFunc(GL_LESS);
2079 GL_ColorMask(0, 0, 0, 0);
2080 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2081 GL_CullFace(GL_NONE);
2082 R_SetupShader_DepthOrShadow(false, false, false); // FIXME test if we have a skeletal model?
2083 r_shadow_rendermode = mode;
2088 case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
2089 case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
2090 R_SetStencilSeparate(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, GL_ALWAYS, 128, 255);
2092 case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
2093 case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
2094 R_SetStencilSeparate(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, GL_ALWAYS, 128, 255);
2099 static void R_Shadow_MakeVSDCT(void)
2101 // maps to a 2x3 texture rectangle with normalized coordinates
2106 // stores abs(dir.xy), offset.xy/2.5
2107 unsigned char data[4*6] =
2109 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
2110 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
2111 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
2112 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
2113 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
2114 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
2116 r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
2119 static void R_Shadow_MakeShadowMap(int side, int size)
2121 switch (r_shadow_shadowmode)
2123 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2124 if (r_shadow_shadowmap2ddepthtexture) return;
2125 if (r_fb.usedepthtextures)
2127 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);
2128 r_shadow_shadowmap2ddepthbuffer = NULL;
2129 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
2133 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);
2134 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);
2135 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
2143 static void R_Shadow_RenderMode_ShadowMap(int side, int clear, int size)
2145 float nearclip, farclip, bias;
2146 r_viewport_t viewport;
2149 float clearcolor[4];
2150 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
2152 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
2153 r_shadow_shadowmap_parameters[1] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
2154 r_shadow_shadowmap_parameters[3] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
2155 r_shadow_shadowmapside = side;
2156 r_shadow_shadowmapsize = size;
2158 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2159 r_shadow_shadowmap_parameters[2] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2160 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
2161 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D) goto init_done;
2163 // complex unrolled cube approach (more flexible)
2164 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2165 R_Shadow_MakeVSDCT();
2166 if (!r_shadow_shadowmap2ddepthtexture)
2167 R_Shadow_MakeShadowMap(side, r_shadow_shadowmapmaxsize);
2168 fbo2d = r_shadow_fbo2d;
2169 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2ddepthtexture);
2170 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2ddepthtexture);
2171 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
2173 R_Mesh_ResetTextureState();
2174 R_Shadow_RenderMode_Reset();
2175 if (r_shadow_shadowmap2ddepthbuffer)
2176 R_Mesh_SetRenderTargets(fbo2d, r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
2178 R_Mesh_SetRenderTargets(fbo2d, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
2179 R_SetupShader_DepthOrShadow(true, r_shadow_shadowmap2ddepthbuffer != NULL, false); // FIXME test if we have a skeletal model?
2180 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
2185 R_SetViewport(&viewport);
2186 flipped = (side & 1) ^ (side >> 2);
2187 r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
2188 r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
2189 if (r_shadow_shadowmap2ddepthbuffer)
2191 // completely different meaning than in depthtexture approach
2192 r_shadow_shadowmap_parameters[1] = 0;
2193 r_shadow_shadowmap_parameters[3] = -bias;
2195 Vector4Set(clearcolor, 1,1,1,1);
2196 if (r_shadow_shadowmap2ddepthbuffer)
2197 GL_ColorMask(1,1,1,1);
2199 GL_ColorMask(0,0,0,0);
2200 switch(vid.renderpath)
2202 case RENDERPATH_GL11:
2203 case RENDERPATH_GL13:
2204 case RENDERPATH_GL20:
2205 case RENDERPATH_SOFT:
2206 case RENDERPATH_GLES1:
2207 case RENDERPATH_GLES2:
2208 GL_CullFace(r_refdef.view.cullface_back);
2209 // OpenGL lets us scissor larger than the viewport, so go ahead and clear all views at once
2210 if ((clear & ((2 << side) - 1)) == (1 << side)) // only clear if the side is the first in the mask
2212 // get tightest scissor rectangle that encloses all viewports in the clear mask
2213 int x1 = clear & 0x15 ? 0 : size;
2214 int x2 = clear & 0x2A ? 2 * size : size;
2215 int y1 = clear & 0x03 ? 0 : (clear & 0xC ? size : 2 * size);
2216 int y2 = clear & 0x30 ? 3 * size : (clear & 0xC ? 2 * size : size);
2217 GL_Scissor(x1, y1, x2 - x1, y2 - y1);
2220 if (r_shadow_shadowmap2ddepthbuffer)
2221 GL_Clear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
2223 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
2226 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2228 case RENDERPATH_D3D9:
2229 case RENDERPATH_D3D10:
2230 case RENDERPATH_D3D11:
2231 // we invert the cull mode because we flip the projection matrix
2232 // NOTE: this actually does nothing because the DrawShadowMap code sets it to doublesided...
2233 GL_CullFace(r_refdef.view.cullface_front);
2234 // D3D considers it an error to use a scissor larger than the viewport... clear just this view
2235 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2238 if (r_shadow_shadowmap2ddepthbuffer)
2239 GL_Clear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
2241 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
2247 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
2249 R_Mesh_ResetTextureState();
2252 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2253 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2254 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2255 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2257 R_Shadow_RenderMode_Reset();
2258 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2260 GL_DepthFunc(GL_EQUAL);
2261 // do global setup needed for the chosen lighting mode
2262 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2263 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2264 r_shadow_usingshadowmap2d = shadowmapping;
2265 r_shadow_rendermode = r_shadow_lightingrendermode;
2266 // only draw light where this geometry was already rendered AND the
2267 // stencil is 128 (values other than this mean shadow)
2269 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2271 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
2274 static const unsigned short bboxelements[36] =
2284 static const float bboxpoints[8][3] =
2296 void R_Shadow_RenderMode_DrawDeferredLight(qboolean stenciltest, qboolean shadowmapping)
2299 float vertex3f[8*3];
2300 const matrix4x4_t *matrix = &rsurface.rtlight->matrix_lighttoworld;
2301 // do global setup needed for the chosen lighting mode
2302 R_Shadow_RenderMode_Reset();
2303 r_shadow_rendermode = r_shadow_lightingrendermode;
2304 R_EntityMatrix(&identitymatrix);
2305 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2306 // only draw light where this geometry was already rendered AND the
2307 // stencil is 128 (values other than this mean shadow)
2308 R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2309 if (rsurface.rtlight->specularscale > 0 && r_shadow_gloss.integer > 0)
2310 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
2312 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
2314 r_shadow_usingshadowmap2d = shadowmapping;
2316 // render the lighting
2317 R_SetupShader_DeferredLight(rsurface.rtlight);
2318 for (i = 0;i < 8;i++)
2319 Matrix4x4_Transform(matrix, bboxpoints[i], vertex3f + i*3);
2320 GL_ColorMask(1,1,1,1);
2321 GL_DepthMask(false);
2322 GL_DepthRange(0, 1);
2323 GL_PolygonOffset(0, 0);
2325 GL_DepthFunc(GL_GREATER);
2326 GL_CullFace(r_refdef.view.cullface_back);
2327 R_Mesh_PrepareVertices_Vertex3f(8, vertex3f, NULL, 0);
2328 R_Mesh_Draw(0, 8, 0, 12, NULL, NULL, 0, bboxelements, NULL, 0);
2331 void R_Shadow_UpdateBounceGridTexture(void)
2333 #define MAXBOUNCEGRIDPARTICLESPERLIGHT 1048576
2335 int flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
2337 int hitsupercontentsmask;
2346 //trace_t cliptrace2;
2347 //trace_t cliptrace3;
2348 unsigned char *pixel;
2349 unsigned char *pixels;
2352 unsigned int lightindex;
2354 unsigned int range1;
2355 unsigned int range2;
2356 unsigned int seed = (unsigned int)(realtime * 1000.0f);
2358 vec3_t baseshotcolor;
2371 vec3_t cullmins, cullmaxs;
2374 vec_t lightintensity;
2375 vec_t photonscaling;
2376 vec_t photonresidual;
2378 float texlerp[2][3];
2379 float splatcolor[32];
2380 float pixelweight[8];
2392 r_shadow_bouncegrid_settings_t settings;
2393 qboolean enable = r_shadow_bouncegrid.integer != 0 && r_refdef.scene.worldmodel;
2394 qboolean allowdirectionalshading = false;
2395 switch(vid.renderpath)
2397 case RENDERPATH_GL20:
2398 allowdirectionalshading = true;
2399 if (!vid.support.ext_texture_3d)
2402 case RENDERPATH_GLES2:
2403 // for performance reasons, do not use directional shading on GLES devices
2404 if (!vid.support.ext_texture_3d)
2407 // these renderpaths do not currently have the code to display the bouncegrid, so disable it on them...
2408 case RENDERPATH_GL11:
2409 case RENDERPATH_GL13:
2410 case RENDERPATH_GLES1:
2411 case RENDERPATH_SOFT:
2412 case RENDERPATH_D3D9:
2413 case RENDERPATH_D3D10:
2414 case RENDERPATH_D3D11:
2418 r_shadow_bouncegridintensity = r_shadow_bouncegrid_intensity.value;
2420 // see if there are really any lights to render...
2421 if (enable && r_shadow_bouncegrid_static.integer)
2424 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
2425 for (lightindex = 0;lightindex < range;lightindex++)
2427 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2428 if (!light || !(light->flags & flag))
2430 rtlight = &light->rtlight;
2431 // when static, we skip styled lights because they tend to change...
2432 if (rtlight->style > 0)
2434 VectorScale(rtlight->color, (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale), lightcolor);
2435 if (!VectorLength2(lightcolor))
2444 if (r_shadow_bouncegridtexture)
2446 R_FreeTexture(r_shadow_bouncegridtexture);
2447 r_shadow_bouncegridtexture = NULL;
2449 if (r_shadow_bouncegridpixels)
2450 Mem_Free(r_shadow_bouncegridpixels);
2451 r_shadow_bouncegridpixels = NULL;
2452 if (r_shadow_bouncegridhighpixels)
2453 Mem_Free(r_shadow_bouncegridhighpixels);
2454 r_shadow_bouncegridhighpixels = NULL;
2455 r_shadow_bouncegridnumpixels = 0;
2456 r_shadow_bouncegriddirectional = false;
2460 // build up a complete collection of the desired settings, so that memcmp can be used to compare parameters
2461 memset(&settings, 0, sizeof(settings));
2462 settings.staticmode = r_shadow_bouncegrid_static.integer != 0;
2463 settings.bounceanglediffuse = r_shadow_bouncegrid_bounceanglediffuse.integer != 0;
2464 settings.directionalshading = (r_shadow_bouncegrid_static.integer != 0 ? r_shadow_bouncegrid_static_directionalshading.integer != 0 : r_shadow_bouncegrid_directionalshading.integer != 0) && allowdirectionalshading;
2465 settings.dlightparticlemultiplier = r_shadow_bouncegrid_dlightparticlemultiplier.value;
2466 settings.hitmodels = r_shadow_bouncegrid_hitmodels.integer != 0;
2467 settings.includedirectlighting = r_shadow_bouncegrid_includedirectlighting.integer != 0 || r_shadow_bouncegrid.integer == 2;
2468 settings.lightradiusscale = (r_shadow_bouncegrid_static.integer != 0 ? r_shadow_bouncegrid_static_lightradiusscale.value : r_shadow_bouncegrid_lightradiusscale.value);
2469 settings.maxbounce = (r_shadow_bouncegrid_static.integer != 0 ? r_shadow_bouncegrid_static_maxbounce.integer : r_shadow_bouncegrid_maxbounce.integer);
2470 settings.particlebounceintensity = r_shadow_bouncegrid_particlebounceintensity.value;
2471 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);
2472 settings.photons = r_shadow_bouncegrid_static.integer ? r_shadow_bouncegrid_static_photons.integer : r_shadow_bouncegrid_photons.integer;
2473 settings.spacing[0] = r_shadow_bouncegrid_spacing.value;
2474 settings.spacing[1] = r_shadow_bouncegrid_spacing.value;
2475 settings.spacing[2] = r_shadow_bouncegrid_spacing.value;
2476 settings.stablerandom = r_shadow_bouncegrid_stablerandom.integer;
2478 // bound the values for sanity
2479 settings.photons = bound(1, settings.photons, 1048576);
2480 settings.lightradiusscale = bound(0.0001f, settings.lightradiusscale, 1024.0f);
2481 settings.maxbounce = bound(0, settings.maxbounce, 16);
2482 settings.spacing[0] = bound(1, settings.spacing[0], 512);
2483 settings.spacing[1] = bound(1, settings.spacing[1], 512);
2484 settings.spacing[2] = bound(1, settings.spacing[2], 512);
2486 // get the spacing values
2487 spacing[0] = settings.spacing[0];
2488 spacing[1] = settings.spacing[1];
2489 spacing[2] = settings.spacing[2];
2490 ispacing[0] = 1.0f / spacing[0];
2491 ispacing[1] = 1.0f / spacing[1];
2492 ispacing[2] = 1.0f / spacing[2];
2494 // calculate texture size enclosing entire world bounds at the spacing
2495 VectorMA(r_refdef.scene.worldmodel->normalmins, -2.0f, spacing, mins);
2496 VectorMA(r_refdef.scene.worldmodel->normalmaxs, 2.0f, spacing, maxs);
2497 VectorSubtract(maxs, mins, size);
2498 // now we can calculate the resolution we want
2499 c[0] = (int)floor(size[0] / spacing[0] + 0.5f);
2500 c[1] = (int)floor(size[1] / spacing[1] + 0.5f);
2501 c[2] = (int)floor(size[2] / spacing[2] + 0.5f);
2502 // figure out the exact texture size (honoring power of 2 if required)
2503 c[0] = bound(4, c[0], (int)vid.maxtexturesize_3d);
2504 c[1] = bound(4, c[1], (int)vid.maxtexturesize_3d);
2505 c[2] = bound(4, c[2], (int)vid.maxtexturesize_3d);
2506 if (vid.support.arb_texture_non_power_of_two)
2508 resolution[0] = c[0];
2509 resolution[1] = c[1];
2510 resolution[2] = c[2];
2514 for (resolution[0] = 4;resolution[0] < c[0];resolution[0]*=2) ;
2515 for (resolution[1] = 4;resolution[1] < c[1];resolution[1]*=2) ;
2516 for (resolution[2] = 4;resolution[2] < c[2];resolution[2]*=2) ;
2518 size[0] = spacing[0] * resolution[0];
2519 size[1] = spacing[1] * resolution[1];
2520 size[2] = spacing[2] * resolution[2];
2522 // if dynamic we may or may not want to use the world bounds
2523 // if the dynamic size is smaller than the world bounds, use it instead
2524 if (!settings.staticmode && (r_shadow_bouncegrid_x.integer * r_shadow_bouncegrid_y.integer * r_shadow_bouncegrid_z.integer < resolution[0] * resolution[1] * resolution[2]))
2526 // we know the resolution we want
2527 c[0] = r_shadow_bouncegrid_x.integer;
2528 c[1] = r_shadow_bouncegrid_y.integer;
2529 c[2] = r_shadow_bouncegrid_z.integer;
2530 // now we can calculate the texture size (power of 2 if required)
2531 c[0] = bound(4, c[0], (int)vid.maxtexturesize_3d);
2532 c[1] = bound(4, c[1], (int)vid.maxtexturesize_3d);
2533 c[2] = bound(4, c[2], (int)vid.maxtexturesize_3d);
2534 if (vid.support.arb_texture_non_power_of_two)
2536 resolution[0] = c[0];
2537 resolution[1] = c[1];
2538 resolution[2] = c[2];
2542 for (resolution[0] = 4;resolution[0] < c[0];resolution[0]*=2) ;
2543 for (resolution[1] = 4;resolution[1] < c[1];resolution[1]*=2) ;
2544 for (resolution[2] = 4;resolution[2] < c[2];resolution[2]*=2) ;
2546 size[0] = spacing[0] * resolution[0];
2547 size[1] = spacing[1] * resolution[1];
2548 size[2] = spacing[2] * resolution[2];
2549 // center the rendering on the view
2550 mins[0] = floor(r_refdef.view.origin[0] * ispacing[0] + 0.5f) * spacing[0] - 0.5f * size[0];
2551 mins[1] = floor(r_refdef.view.origin[1] * ispacing[1] + 0.5f) * spacing[1] - 0.5f * size[1];
2552 mins[2] = floor(r_refdef.view.origin[2] * ispacing[2] + 0.5f) * spacing[2] - 0.5f * size[2];
2555 // recalculate the maxs in case the resolution was not satisfactory
2556 VectorAdd(mins, size, maxs);
2558 // if all the settings seem identical to the previous update, return
2559 if (r_shadow_bouncegridtexture && (settings.staticmode || realtime < r_shadow_bouncegridtime + r_shadow_bouncegrid_updateinterval.value) && !memcmp(&r_shadow_bouncegridsettings, &settings, sizeof(settings)))
2562 // store the new settings
2563 r_shadow_bouncegridsettings = settings;
2565 pixelbands = settings.directionalshading ? 8 : 1;
2566 pixelsperband = resolution[0]*resolution[1]*resolution[2];
2567 numpixels = pixelsperband*pixelbands;
2569 // we're going to update the bouncegrid, update the matrix...
2570 memset(m, 0, sizeof(m));
2571 m[0] = 1.0f / size[0];
2572 m[3] = -mins[0] * m[0];
2573 m[5] = 1.0f / size[1];
2574 m[7] = -mins[1] * m[5];
2575 m[10] = 1.0f / size[2];
2576 m[11] = -mins[2] * m[10];
2578 Matrix4x4_FromArrayFloatD3D(&r_shadow_bouncegridmatrix, m);
2579 // reallocate pixels for this update if needed...
2580 if (r_shadow_bouncegridnumpixels != numpixels || !r_shadow_bouncegridpixels || !r_shadow_bouncegridhighpixels)
2582 if (r_shadow_bouncegridtexture)
2584 R_FreeTexture(r_shadow_bouncegridtexture);
2585 r_shadow_bouncegridtexture = NULL;
2587 r_shadow_bouncegridpixels = (unsigned char *)Mem_Realloc(r_main_mempool, r_shadow_bouncegridpixels, numpixels * sizeof(unsigned char[4]));
2588 r_shadow_bouncegridhighpixels = (float *)Mem_Realloc(r_main_mempool, r_shadow_bouncegridhighpixels, numpixels * sizeof(float[4]));
2590 r_shadow_bouncegridnumpixels = numpixels;
2591 pixels = r_shadow_bouncegridpixels;
2592 highpixels = r_shadow_bouncegridhighpixels;
2593 x = pixelsperband*4;
2594 for (pixelband = 0;pixelband < pixelbands;pixelband++)
2597 memset(pixels + pixelband * x, 128, x);
2599 memset(pixels + pixelband * x, 0, x);
2601 memset(highpixels, 0, numpixels * sizeof(float[4]));
2602 // figure out what we want to interact with
2603 if (settings.hitmodels)
2604 hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY;// | SUPERCONTENTS_LIQUIDSMASK;
2606 hitsupercontentsmask = SUPERCONTENTS_SOLID;// | SUPERCONTENTS_LIQUIDSMASK;
2607 maxbounce = settings.maxbounce;
2608 // clear variables that produce warnings otherwise
2609 memset(splatcolor, 0, sizeof(splatcolor));
2610 // iterate world rtlights
2611 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
2612 range1 = settings.staticmode ? 0 : r_refdef.scene.numlights;
2613 range2 = range + range1;
2615 for (lightindex = 0;lightindex < range2;lightindex++)
2617 if (lightindex < range)
2619 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2622 rtlight = &light->rtlight;
2623 VectorClear(rtlight->photoncolor);
2624 rtlight->photons = 0;
2625 if (!(light->flags & flag))
2627 if (settings.staticmode)
2629 // when static, we skip styled lights because they tend to change...
2630 if (rtlight->style > 0 && r_shadow_bouncegrid.integer != 2)
2636 rtlight = r_refdef.scene.lights[lightindex - range];
2637 VectorClear(rtlight->photoncolor);
2638 rtlight->photons = 0;
2640 // draw only visible lights (major speedup)
2641 radius = rtlight->radius * settings.lightradiusscale;
2642 cullmins[0] = rtlight->shadoworigin[0] - radius;
2643 cullmins[1] = rtlight->shadoworigin[1] - radius;
2644 cullmins[2] = rtlight->shadoworigin[2] - radius;
2645 cullmaxs[0] = rtlight->shadoworigin[0] + radius;
2646 cullmaxs[1] = rtlight->shadoworigin[1] + radius;
2647 cullmaxs[2] = rtlight->shadoworigin[2] + radius;
2648 if (R_CullBox(cullmins, cullmaxs))
2650 if (r_refdef.scene.worldmodel
2651 && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs
2652 && !r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, cullmins, cullmaxs))
2654 w = r_shadow_lightintensityscale.value * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2655 if (w * VectorLength2(rtlight->color) == 0.0f)
2657 w *= ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1);
2658 VectorScale(rtlight->color, w, rtlight->photoncolor);
2659 //if (!VectorLength2(rtlight->photoncolor))
2661 // shoot particles from this light
2662 // use a calculation for the number of particles that will not
2663 // vary with lightstyle, otherwise we get randomized particle
2664 // distribution, the seeded random is only consistent for a
2665 // consistent number of particles on this light...
2666 s = rtlight->radius;
2667 lightintensity = VectorLength(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale);
2668 if (lightindex >= range)
2669 lightintensity *= settings.dlightparticlemultiplier;
2670 rtlight->photons = max(0.0f, lightintensity * s * s);
2671 photoncount += rtlight->photons;
2673 photonscaling = (float)settings.photons / max(1, photoncount);
2674 photonresidual = 0.0f;
2675 for (lightindex = 0;lightindex < range2;lightindex++)
2677 if (lightindex < range)
2679 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2682 rtlight = &light->rtlight;
2685 rtlight = r_refdef.scene.lights[lightindex - range];
2686 // skip a light with no photons
2687 if (rtlight->photons == 0.0f)
2689 // skip a light with no photon color)
2690 if (VectorLength2(rtlight->photoncolor) == 0.0f)
2692 photonresidual += rtlight->photons * photonscaling;
2693 shootparticles = (int)bound(0, photonresidual, MAXBOUNCEGRIDPARTICLESPERLIGHT);
2694 if (!shootparticles)
2696 photonresidual -= shootparticles;
2697 radius = rtlight->radius * settings.lightradiusscale;
2698 s = settings.particleintensity / shootparticles;
2699 VectorScale(rtlight->photoncolor, s, baseshotcolor);
2700 r_refdef.stats[r_stat_bouncegrid_lights]++;
2701 r_refdef.stats[r_stat_bouncegrid_particles] += shootparticles;
2702 for (shotparticles = 0;shotparticles < shootparticles;shotparticles++)
2704 if (settings.stablerandom > 0)
2705 seed = lightindex * 11937 + shotparticles;
2706 VectorCopy(baseshotcolor, shotcolor);
2707 VectorCopy(rtlight->shadoworigin, clipstart);
2708 if (settings.stablerandom < 0)
2709 VectorRandom(clipend);
2711 VectorCheeseRandom(clipend);
2712 VectorMA(clipstart, radius, clipend, clipend);
2713 for (bouncecount = 0;;bouncecount++)
2715 r_refdef.stats[r_stat_bouncegrid_traces]++;
2716 //r_refdef.scene.worldmodel->TraceLineAgainstSurfaces(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace, clipstart, clipend, hitsupercontentsmask);
2717 //r_refdef.scene.worldmodel->TraceLine(r_refdef.scene.worldmodel, NULL, NULL, &cliptrace2, clipstart, clipend, hitsupercontentsmask);
2718 if (settings.staticmode)
2720 // static mode fires a LOT of rays but none of them are identical, so they are not cached
2721 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);
2725 // dynamic mode fires many rays and most will match the cache from the previous frame
2726 cliptrace = CL_Cache_TraceLineSurfaces(clipstart, clipend, settings.staticmode ? MOVE_WORLDONLY : (settings.hitmodels ? MOVE_HITMODEL : MOVE_NOMONSTERS), hitsupercontentsmask);
2728 if (bouncecount > 0 || settings.includedirectlighting)
2730 // calculate second order spherical harmonics values (average, slopeX, slopeY, slopeZ)
2731 // accumulate average shotcolor
2732 w = VectorLength(shotcolor);
2733 splatcolor[ 0] = shotcolor[0];
2734 splatcolor[ 1] = shotcolor[1];
2735 splatcolor[ 2] = shotcolor[2];
2736 splatcolor[ 3] = 0.0f;
2739 VectorSubtract(clipstart, cliptrace.endpos, clipdiff);
2740 VectorNormalize(clipdiff);
2741 // store bentnormal in case the shader has a use for it
2742 splatcolor[ 4] = clipdiff[0] * w;
2743 splatcolor[ 5] = clipdiff[1] * w;
2744 splatcolor[ 6] = clipdiff[2] * w;
2746 // accumulate directional contributions (+X, +Y, +Z, -X, -Y, -Z)
2747 splatcolor[ 8] = shotcolor[0] * max(0.0f, clipdiff[0]);
2748 splatcolor[ 9] = shotcolor[0] * max(0.0f, clipdiff[1]);
2749 splatcolor[10] = shotcolor[0] * max(0.0f, clipdiff[2]);
2750 splatcolor[11] = 0.0f;
2751 splatcolor[12] = shotcolor[1] * max(0.0f, clipdiff[0]);
2752 splatcolor[13] = shotcolor[1] * max(0.0f, clipdiff[1]);
2753 splatcolor[14] = shotcolor[1] * max(0.0f, clipdiff[2]);
2754 splatcolor[15] = 0.0f;
2755 splatcolor[16] = shotcolor[2] * max(0.0f, clipdiff[0]);
2756 splatcolor[17] = shotcolor[2] * max(0.0f, clipdiff[1]);
2757 splatcolor[18] = shotcolor[2] * max(0.0f, clipdiff[2]);
2758 splatcolor[19] = 0.0f;
2759 splatcolor[20] = shotcolor[0] * max(0.0f, -clipdiff[0]);
2760 splatcolor[21] = shotcolor[0] * max(0.0f, -clipdiff[1]);
2761 splatcolor[22] = shotcolor[0] * max(0.0f, -clipdiff[2]);
2762 splatcolor[23] = 0.0f;
2763 splatcolor[24] = shotcolor[1] * max(0.0f, -clipdiff[0]);
2764 splatcolor[25] = shotcolor[1] * max(0.0f, -clipdiff[1]);
2765 splatcolor[26] = shotcolor[1] * max(0.0f, -clipdiff[2]);
2766 splatcolor[27] = 0.0f;
2767 splatcolor[28] = shotcolor[2] * max(0.0f, -clipdiff[0]);
2768 splatcolor[29] = shotcolor[2] * max(0.0f, -clipdiff[1]);
2769 splatcolor[30] = shotcolor[2] * max(0.0f, -clipdiff[2]);
2770 splatcolor[31] = 0.0f;
2772 // calculate the number of steps we need to traverse this distance
2773 VectorSubtract(cliptrace.endpos, clipstart, stepdelta);
2774 numsteps = (int)(VectorLength(stepdelta) * ispacing[0]);
2775 numsteps = bound(1, numsteps, 1024);
2776 w = 1.0f / numsteps;
2777 VectorScale(stepdelta, w, stepdelta);
2778 VectorMA(clipstart, 0.5f, stepdelta, steppos);
2779 for (step = 0;step < numsteps;step++)
2781 r_refdef.stats[r_stat_bouncegrid_splats]++;
2782 // figure out which texture pixel this is in
2783 texlerp[1][0] = ((steppos[0] - mins[0]) * ispacing[0]) - 0.5f;
2784 texlerp[1][1] = ((steppos[1] - mins[1]) * ispacing[1]) - 0.5f;
2785 texlerp[1][2] = ((steppos[2] - mins[2]) * ispacing[2]) - 0.5f;
2786 tex[0] = (int)floor(texlerp[1][0]);
2787 tex[1] = (int)floor(texlerp[1][1]);
2788 tex[2] = (int)floor(texlerp[1][2]);
2789 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)
2791 // it is within bounds... do the real work now
2792 // calculate the lerp factors
2793 texlerp[1][0] -= tex[0];
2794 texlerp[1][1] -= tex[1];
2795 texlerp[1][2] -= tex[2];
2796 texlerp[0][0] = 1.0f - texlerp[1][0];
2797 texlerp[0][1] = 1.0f - texlerp[1][1];
2798 texlerp[0][2] = 1.0f - texlerp[1][2];
2799 // calculate individual pixel indexes and weights
2800 pixelindex[0] = (((tex[2] )*resolution[1]+tex[1] )*resolution[0]+tex[0] );pixelweight[0] = (texlerp[0][0]*texlerp[0][1]*texlerp[0][2]);
2801 pixelindex[1] = (((tex[2] )*resolution[1]+tex[1] )*resolution[0]+tex[0]+1);pixelweight[1] = (texlerp[1][0]*texlerp[0][1]*texlerp[0][2]);
2802 pixelindex[2] = (((tex[2] )*resolution[1]+tex[1]+1)*resolution[0]+tex[0] );pixelweight[2] = (texlerp[0][0]*texlerp[1][1]*texlerp[0][2]);
2803 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]);
2804 pixelindex[4] = (((tex[2]+1)*resolution[1]+tex[1] )*resolution[0]+tex[0] );pixelweight[4] = (texlerp[0][0]*texlerp[0][1]*texlerp[1][2]);
2805 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]);
2806 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]);
2807 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]);
2808 // update the 8 pixels...
2809 for (pixelband = 0;pixelband < pixelbands;pixelband++)
2811 for (corner = 0;corner < 8;corner++)
2813 // calculate address for pixel
2814 w = pixelweight[corner];
2815 pixel = pixels + 4 * pixelindex[corner] + pixelband * pixelsperband * 4;
2816 highpixel = highpixels + 4 * pixelindex[corner] + pixelband * pixelsperband * 4;
2817 // add to the high precision pixel color
2818 highpixel[0] += (splatcolor[pixelband*4+0]*w);
2819 highpixel[1] += (splatcolor[pixelband*4+1]*w);
2820 highpixel[2] += (splatcolor[pixelband*4+2]*w);
2821 highpixel[3] += (splatcolor[pixelband*4+3]*w);
2822 // flag the low precision pixel as needing to be updated
2824 // advance to next band of coefficients
2825 //pixel += pixelsperband*4;
2826 //highpixel += pixelsperband*4;
2830 VectorAdd(steppos, stepdelta, steppos);
2833 if (cliptrace.fraction >= 1.0f)
2835 r_refdef.stats[r_stat_bouncegrid_hits]++;
2836 if (bouncecount >= maxbounce)
2838 // scale down shot color by bounce intensity and texture color (or 50% if no texture reported)
2839 // also clamp the resulting color to never add energy, even if the user requests extreme values
2840 if (cliptrace.hittexture && cliptrace.hittexture->currentskinframe)
2841 VectorCopy(cliptrace.hittexture->currentskinframe->avgcolor, surfcolor);
2843 VectorSet(surfcolor, 0.5f, 0.5f, 0.5f);
2844 VectorScale(surfcolor, settings.particlebounceintensity, surfcolor);
2845 surfcolor[0] = min(surfcolor[0], 1.0f);
2846 surfcolor[1] = min(surfcolor[1], 1.0f);
2847 surfcolor[2] = min(surfcolor[2], 1.0f);
2848 VectorMultiply(shotcolor, surfcolor, shotcolor);
2849 if (VectorLength2(baseshotcolor) == 0.0f)
2851 r_refdef.stats[r_stat_bouncegrid_bounces]++;
2852 if (settings.bounceanglediffuse)
2854 // random direction, primarily along plane normal
2855 s = VectorDistance(cliptrace.endpos, clipend);
2856 if (settings.stablerandom < 0)
2857 VectorRandom(clipend);
2859 VectorCheeseRandom(clipend);
2860 VectorMA(cliptrace.plane.normal, 0.95f, clipend, clipend);
2861 VectorNormalize(clipend);
2862 VectorScale(clipend, s, clipend);
2866 // reflect the remaining portion of the line across plane normal
2867 VectorSubtract(clipend, cliptrace.endpos, clipdiff);
2868 VectorReflect(clipdiff, 1.0, cliptrace.plane.normal, clipend);
2870 // calculate the new line start and end
2871 VectorCopy(cliptrace.endpos, clipstart);
2872 VectorAdd(clipstart, clipend, clipend);
2876 // generate pixels array from highpixels array
2877 // skip first and last columns, rows, and layers as these are blank
2878 // the pixel[3] value was written above, so we can use it to detect only pixels that need to be calculated
2879 for (pixelband = 0;pixelband < pixelbands;pixelband++)
2881 for (z = 1;z < resolution[2]-1;z++)
2883 for (y = 1;y < resolution[1]-1;y++)
2885 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)
2887 // only convert pixels that were hit by photons
2888 if (pixel[3] == 255)
2890 // normalize the bentnormal...
2893 VectorNormalize(highpixel);
2894 c[0] = (int)(highpixel[0]*128.0f+128.0f);
2895 c[1] = (int)(highpixel[1]*128.0f+128.0f);
2896 c[2] = (int)(highpixel[2]*128.0f+128.0f);
2897 c[3] = (int)(highpixel[3]*128.0f+128.0f);
2901 c[0] = (int)(highpixel[0]*256.0f);
2902 c[1] = (int)(highpixel[1]*256.0f);
2903 c[2] = (int)(highpixel[2]*256.0f);
2904 c[3] = (int)(highpixel[3]*256.0f);
2906 pixel[2] = (unsigned char)bound(0, c[0], 255);
2907 pixel[1] = (unsigned char)bound(0, c[1], 255);
2908 pixel[0] = (unsigned char)bound(0, c[2], 255);
2909 pixel[3] = (unsigned char)bound(0, c[3], 255);
2915 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)
2916 R_UpdateTexture(r_shadow_bouncegridtexture, pixels, 0, 0, 0, resolution[0], resolution[1], resolution[2]*pixelbands);
2919 VectorCopy(resolution, r_shadow_bouncegridresolution);
2920 r_shadow_bouncegriddirectional = settings.directionalshading;
2921 if (r_shadow_bouncegridtexture)
2922 R_FreeTexture(r_shadow_bouncegridtexture);
2923 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);
2925 r_shadow_bouncegridtime = realtime;
2928 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
2930 R_Shadow_RenderMode_Reset();
2931 GL_BlendFunc(GL_ONE, GL_ONE);
2932 GL_DepthRange(0, 1);
2933 GL_DepthTest(r_showshadowvolumes.integer < 2);
2934 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
2935 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2936 GL_CullFace(GL_NONE);
2937 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
2940 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
2942 R_Shadow_RenderMode_Reset();
2943 GL_BlendFunc(GL_ONE, GL_ONE);
2944 GL_DepthRange(0, 1);
2945 GL_DepthTest(r_showlighting.integer < 2);
2946 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2948 GL_DepthFunc(GL_EQUAL);
2949 R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2950 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2953 void R_Shadow_RenderMode_End(void)
2955 R_Shadow_RenderMode_Reset();
2956 R_Shadow_RenderMode_ActiveLight(NULL);
2958 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2959 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2962 int bboxedges[12][2] =
2981 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2983 if (!r_shadow_scissor.integer || r_shadow_usingdeferredprepass || r_trippy.integer)
2985 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2986 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2987 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2988 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2991 if(R_ScissorForBBox(mins, maxs, r_shadow_lightscissor))
2992 return true; // invisible
2993 if(r_shadow_lightscissor[0] != r_refdef.view.viewport.x
2994 || r_shadow_lightscissor[1] != r_refdef.view.viewport.y
2995 || r_shadow_lightscissor[2] != r_refdef.view.viewport.width
2996 || r_shadow_lightscissor[3] != r_refdef.view.viewport.height)
2997 r_refdef.stats[r_stat_lights_scissored]++;
3001 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, const float *diffusecolor, const float *ambientcolor)
3004 const float *vertex3f;
3005 const float *normal3f;
3007 float dist, dot, distintensity, shadeintensity, v[3], n[3];
3008 switch (r_shadow_rendermode)
3010 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
3011 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
3012 if (VectorLength2(diffusecolor) > 0)
3014 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)
3016 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3017 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
3018 if ((dot = DotProduct(n, v)) < 0)
3020 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
3021 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
3024 VectorCopy(ambientcolor, color4f);
3025 if (r_refdef.fogenabled)
3028 f = RSurf_FogVertex(vertex3f);
3029 VectorScale(color4f, f, color4f);
3036 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
3038 VectorCopy(ambientcolor, color4f);
3039 if (r_refdef.fogenabled)
3042 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3043 f = RSurf_FogVertex(vertex3f);
3044 VectorScale(color4f + 4*i, f, color4f);
3050 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
3051 if (VectorLength2(diffusecolor) > 0)
3053 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)
3055 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3056 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3058 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
3059 if ((dot = DotProduct(n, v)) < 0)
3061 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
3062 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
3063 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
3064 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
3068 color4f[0] = ambientcolor[0] * distintensity;
3069 color4f[1] = ambientcolor[1] * distintensity;
3070 color4f[2] = ambientcolor[2] * distintensity;
3072 if (r_refdef.fogenabled)
3075 f = RSurf_FogVertex(vertex3f);
3076 VectorScale(color4f, f, color4f);
3080 VectorClear(color4f);
3086 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
3088 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3089 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3091 color4f[0] = ambientcolor[0] * distintensity;
3092 color4f[1] = ambientcolor[1] * distintensity;
3093 color4f[2] = ambientcolor[2] * distintensity;
3094 if (r_refdef.fogenabled)
3097 f = RSurf_FogVertex(vertex3f);
3098 VectorScale(color4f, f, color4f);
3102 VectorClear(color4f);
3107 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3108 if (VectorLength2(diffusecolor) > 0)
3110 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)
3112 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3113 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3115 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
3116 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
3117 if ((dot = DotProduct(n, v)) < 0)
3119 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
3120 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
3121 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
3122 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
3126 color4f[0] = ambientcolor[0] * distintensity;
3127 color4f[1] = ambientcolor[1] * distintensity;
3128 color4f[2] = ambientcolor[2] * distintensity;
3130 if (r_refdef.fogenabled)
3133 f = RSurf_FogVertex(vertex3f);
3134 VectorScale(color4f, f, color4f);
3138 VectorClear(color4f);
3144 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
3146 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
3147 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
3149 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
3150 color4f[0] = ambientcolor[0] * distintensity;
3151 color4f[1] = ambientcolor[1] * distintensity;
3152 color4f[2] = ambientcolor[2] * distintensity;
3153 if (r_refdef.fogenabled)
3156 f = RSurf_FogVertex(vertex3f);
3157 VectorScale(color4f, f, color4f);
3161 VectorClear(color4f);
3171 static void R_Shadow_RenderLighting_VisibleLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
3173 // used to display how many times a surface is lit for level design purposes
3174 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
3175 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
3179 static void R_Shadow_RenderLighting_Light_GLSL(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale, float specularscale)
3181 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
3182 R_SetupShader_Surface(lightcolor, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT, texturenumsurfaces, texturesurfacelist, NULL, false);
3186 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
3193 int newnumtriangles;
3197 int maxtriangles = 1024;
3198 int newelements[1024*3];
3199 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, diffusecolor2, ambientcolor2);
3200 for (renders = 0;renders < 4;renders++)
3205 newnumtriangles = 0;
3207 // due to low fillrate on the cards this vertex lighting path is
3208 // designed for, we manually cull all triangles that do not
3209 // contain a lit vertex
3210 // this builds batches of triangles from multiple surfaces and
3211 // renders them at once
3212 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
3214 if (VectorLength2(rsurface.passcolor4f + e[0] * 4) + VectorLength2(rsurface.passcolor4f + e[1] * 4) + VectorLength2(rsurface.passcolor4f + e[2] * 4) >= 0.01)
3216 if (newnumtriangles)
3218 newfirstvertex = min(newfirstvertex, e[0]);
3219 newlastvertex = max(newlastvertex, e[0]);
3223 newfirstvertex = e[0];
3224 newlastvertex = e[0];
3226 newfirstvertex = min(newfirstvertex, e[1]);
3227 newlastvertex = max(newlastvertex, e[1]);
3228 newfirstvertex = min(newfirstvertex, e[2]);
3229 newlastvertex = max(newlastvertex, e[2]);
3235 if (newnumtriangles >= maxtriangles)
3237 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
3238 newnumtriangles = 0;
3244 if (newnumtriangles >= 1)
3246 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
3249 // if we couldn't find any lit triangles, exit early
3252 // now reduce the intensity for the next overbright pass
3253 // we have to clamp to 0 here incase the drivers have improper
3254 // handling of negative colors
3255 // (some old drivers even have improper handling of >1 color)
3257 for (i = 0, c = rsurface.passcolor4f + 4 * firstvertex;i < numvertices;i++, c += 4)
3259 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
3261 c[0] = max(0, c[0] - 1);
3262 c[1] = max(0, c[1] - 1);
3263 c[2] = max(0, c[2] - 1);
3275 static void R_Shadow_RenderLighting_Light_Vertex(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale)
3277 // OpenGL 1.1 path (anything)
3278 float ambientcolorbase[3], diffusecolorbase[3];
3279 float ambientcolorpants[3], diffusecolorpants[3];
3280 float ambientcolorshirt[3], diffusecolorshirt[3];
3281 const float *surfacecolor = rsurface.texture->dlightcolor;
3282 const float *surfacepants = rsurface.colormap_pantscolor;
3283 const float *surfaceshirt = rsurface.colormap_shirtcolor;
3284 rtexture_t *basetexture = rsurface.texture->basetexture;
3285 rtexture_t *pantstexture = rsurface.texture->pantstexture;
3286 rtexture_t *shirttexture = rsurface.texture->shirttexture;
3287 qboolean dopants = pantstexture && VectorLength2(surfacepants) >= (1.0f / 1048576.0f);
3288 qboolean doshirt = shirttexture && VectorLength2(surfaceshirt) >= (1.0f / 1048576.0f);
3289 ambientscale *= 2 * r_refdef.view.colorscale;
3290 diffusescale *= 2 * r_refdef.view.colorscale;
3291 ambientcolorbase[0] = lightcolor[0] * ambientscale * surfacecolor[0];ambientcolorbase[1] = lightcolor[1] * ambientscale * surfacecolor[1];ambientcolorbase[2] = lightcolor[2] * ambientscale * surfacecolor[2];
3292 diffusecolorbase[0] = lightcolor[0] * diffusescale * surfacecolor[0];diffusecolorbase[1] = lightcolor[1] * diffusescale * surfacecolor[1];diffusecolorbase[2] = lightcolor[2] * diffusescale * surfacecolor[2];
3293 ambientcolorpants[0] = ambientcolorbase[0] * surfacepants[0];ambientcolorpants[1] = ambientcolorbase[1] * surfacepants[1];ambientcolorpants[2] = ambientcolorbase[2] * surfacepants[2];
3294 diffusecolorpants[0] = diffusecolorbase[0] * surfacepants[0];diffusecolorpants[1] = diffusecolorbase[1] * surfacepants[1];diffusecolorpants[2] = diffusecolorbase[2] * surfacepants[2];
3295 ambientcolorshirt[0] = ambientcolorbase[0] * surfaceshirt[0];ambientcolorshirt[1] = ambientcolorbase[1] * surfaceshirt[1];ambientcolorshirt[2] = ambientcolorbase[2] * surfaceshirt[2];
3296 diffusecolorshirt[0] = diffusecolorbase[0] * surfaceshirt[0];diffusecolorshirt[1] = diffusecolorbase[1] * surfaceshirt[1];diffusecolorshirt[2] = diffusecolorbase[2] * surfaceshirt[2];
3297 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | (diffusescale > 0 ? BATCHNEED_ARRAY_NORMAL : 0) | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
3298 rsurface.passcolor4f = (float *)R_FrameData_Alloc((rsurface.batchfirstvertex + rsurface.batchnumvertices) * sizeof(float[4]));
3299 R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3300 R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.passcolor4f, 0, 0);
3301 R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
3302 R_Mesh_TexBind(0, basetexture);
3303 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
3304 R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
3305 switch(r_shadow_rendermode)
3307 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
3308 R_Mesh_TexBind(1, r_shadow_attenuation3dtexture);
3309 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
3310 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
3311 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3313 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
3314 R_Mesh_TexBind(2, r_shadow_attenuation2dtexture);
3315 R_Mesh_TexMatrix(2, &rsurface.entitytoattenuationz);
3316 R_Mesh_TexCombine(2, GL_MODULATE, GL_MODULATE, 1, 1);
3317 R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3319 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
3320 R_Mesh_TexBind(1, r_shadow_attenuation2dtexture);
3321 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
3322 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
3323 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
3325 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3330 //R_Mesh_TexBind(0, basetexture);
3331 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorbase, ambientcolorbase);
3334 R_Mesh_TexBind(0, pantstexture);
3335 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorpants, ambientcolorpants);
3339 R_Mesh_TexBind(0, shirttexture);
3340 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorshirt, ambientcolorshirt);
3344 extern cvar_t gl_lightmaps;
3345 void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
3347 float ambientscale, diffusescale, specularscale;
3349 float lightcolor[3];
3350 VectorCopy(rsurface.rtlight->currentcolor, lightcolor);
3351 ambientscale = rsurface.rtlight->ambientscale + rsurface.texture->rtlightambient;
3352 diffusescale = rsurface.rtlight->diffusescale * max(0, 1.0 - rsurface.texture->rtlightambient);
3353 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
3354 if (!r_shadow_usenormalmap.integer)
3356 ambientscale += 1.0f * diffusescale;
3360 if ((ambientscale + diffusescale) * VectorLength2(lightcolor) + specularscale * VectorLength2(lightcolor) < (1.0f / 1048576.0f))
3362 negated = (lightcolor[0] + lightcolor[1] + lightcolor[2] < 0) && vid.support.ext_blend_subtract;
3365 VectorNegate(lightcolor, lightcolor);
3366 GL_BlendEquationSubtract(true);
3368 RSurf_SetupDepthAndCulling();
3369 switch (r_shadow_rendermode)
3371 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
3372 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
3373 R_Shadow_RenderLighting_VisibleLighting(texturenumsurfaces, texturesurfacelist);
3375 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
3376 R_Shadow_RenderLighting_Light_GLSL(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale, specularscale);
3378 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
3379 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
3380 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
3381 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3382 R_Shadow_RenderLighting_Light_Vertex(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale);
3385 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
3389 GL_BlendEquationSubtract(false);
3392 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)
3394 matrix4x4_t tempmatrix = *matrix;
3395 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
3397 // if this light has been compiled before, free the associated data
3398 R_RTLight_Uncompile(rtlight);
3400 // clear it completely to avoid any lingering data
3401 memset(rtlight, 0, sizeof(*rtlight));
3403 // copy the properties
3404 rtlight->matrix_lighttoworld = tempmatrix;
3405 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
3406 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
3407 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
3408 VectorCopy(color, rtlight->color);
3409 rtlight->cubemapname[0] = 0;
3410 if (cubemapname && cubemapname[0])
3411 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
3412 rtlight->shadow = shadow;
3413 rtlight->corona = corona;
3414 rtlight->style = style;
3415 rtlight->isstatic = isstatic;
3416 rtlight->coronasizescale = coronasizescale;
3417 rtlight->ambientscale = ambientscale;
3418 rtlight->diffusescale = diffusescale;
3419 rtlight->specularscale = specularscale;
3420 rtlight->flags = flags;
3422 // compute derived data
3423 //rtlight->cullradius = rtlight->radius;
3424 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
3425 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3426 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3427 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3428 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3429 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3430 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3433 // compiles rtlight geometry
3434 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
3435 void R_RTLight_Compile(rtlight_t *rtlight)
3438 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
3439 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
3440 entity_render_t *ent = r_refdef.scene.worldentity;
3441 dp_model_t *model = r_refdef.scene.worldmodel;
3442 unsigned char *data;
3445 // compile the light
3446 rtlight->compiled = true;
3447 rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
3448 rtlight->static_numleafs = 0;
3449 rtlight->static_numleafpvsbytes = 0;
3450 rtlight->static_leaflist = NULL;
3451 rtlight->static_leafpvs = NULL;
3452 rtlight->static_numsurfaces = 0;
3453 rtlight->static_surfacelist = NULL;
3454 rtlight->static_shadowmap_receivers = 0x3F;
3455 rtlight->static_shadowmap_casters = 0x3F;
3456 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3457 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3458 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3459 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3460 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3461 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3463 if (model && model->GetLightInfo)
3465 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
3466 r_shadow_compilingrtlight = rtlight;
3467 R_FrameData_SetMark();
3468 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);
3469 R_FrameData_ReturnToMark();
3470 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
3471 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
3472 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3473 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
3474 rtlight->static_numsurfaces = numsurfaces;
3475 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
3476 rtlight->static_numleafs = numleafs;
3477 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
3478 rtlight->static_numleafpvsbytes = numleafpvsbytes;
3479 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
3480 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
3481 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
3482 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
3483 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3484 if (rtlight->static_numsurfaces)
3485 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3486 if (rtlight->static_numleafs)
3487 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3488 if (rtlight->static_numleafpvsbytes)
3489 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3490 if (rtlight->static_numshadowtrispvsbytes)
3491 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3492 if (rtlight->static_numlighttrispvsbytes)
3493 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3494 R_FrameData_SetMark();
3495 switch (rtlight->shadowmode)
3497 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
3498 if (model->CompileShadowMap && rtlight->shadow)
3499 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3502 if (model->CompileShadowVolume && rtlight->shadow)
3503 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3506 R_FrameData_ReturnToMark();
3507 // now we're done compiling the rtlight
3508 r_shadow_compilingrtlight = NULL;
3512 // use smallest available cullradius - box radius or light radius
3513 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3514 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3516 shadowzpasstris = 0;
3517 if (rtlight->static_meshchain_shadow_zpass)
3518 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
3519 shadowzpasstris += mesh->numtriangles;
3521 shadowzfailtris = 0;
3522 if (rtlight->static_meshchain_shadow_zfail)
3523 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
3524 shadowzfailtris += mesh->numtriangles;
3527 if (rtlight->static_numlighttrispvsbytes)
3528 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3529 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3533 if (rtlight->static_numshadowtrispvsbytes)
3534 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3535 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3538 if (developer_extra.integer)
3539 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);
3542 void R_RTLight_Uncompile(rtlight_t *rtlight)
3544 if (rtlight->compiled)
3546 if (rtlight->static_meshchain_shadow_zpass)
3547 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
3548 rtlight->static_meshchain_shadow_zpass = NULL;
3549 if (rtlight->static_meshchain_shadow_zfail)
3550 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
3551 rtlight->static_meshchain_shadow_zfail = NULL;
3552 if (rtlight->static_meshchain_shadow_shadowmap)
3553 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
3554 rtlight->static_meshchain_shadow_shadowmap = NULL;
3555 // these allocations are grouped
3556 if (rtlight->static_surfacelist)
3557 Mem_Free(rtlight->static_surfacelist);
3558 rtlight->static_numleafs = 0;
3559 rtlight->static_numleafpvsbytes = 0;
3560 rtlight->static_leaflist = NULL;
3561 rtlight->static_leafpvs = NULL;
3562 rtlight->static_numsurfaces = 0;
3563 rtlight->static_surfacelist = NULL;
3564 rtlight->static_numshadowtrispvsbytes = 0;
3565 rtlight->static_shadowtrispvs = NULL;
3566 rtlight->static_numlighttrispvsbytes = 0;
3567 rtlight->static_lighttrispvs = NULL;
3568 rtlight->compiled = false;
3572 void R_Shadow_UncompileWorldLights(void)
3576 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3577 for (lightindex = 0;lightindex < range;lightindex++)
3579 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3582 R_RTLight_Uncompile(&light->rtlight);
3586 static void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3590 // reset the count of frustum planes
3591 // see rtlight->cached_frustumplanes definition for how much this array
3593 rtlight->cached_numfrustumplanes = 0;
3595 if (r_trippy.integer)
3598 // haven't implemented a culling path for ortho rendering
3599 if (!r_refdef.view.useperspective)
3601 // check if the light is on screen and copy the 4 planes if it is
3602 for (i = 0;i < 4;i++)
3603 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3606 for (i = 0;i < 4;i++)
3607 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3612 // generate a deformed frustum that includes the light origin, this is
3613 // used to cull shadow casting surfaces that can not possibly cast a
3614 // shadow onto the visible light-receiving surfaces, which can be a
3617 // if the light origin is onscreen the result will be 4 planes exactly
3618 // if the light origin is offscreen on only one axis the result will
3619 // be exactly 5 planes (split-side case)
3620 // if the light origin is offscreen on two axes the result will be
3621 // exactly 4 planes (stretched corner case)
3622 for (i = 0;i < 4;i++)
3624 // quickly reject standard frustum planes that put the light
3625 // origin outside the frustum
3626 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3629 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3631 // if all the standard frustum planes were accepted, the light is onscreen
3632 // otherwise we need to generate some more planes below...
3633 if (rtlight->cached_numfrustumplanes < 4)
3635 // at least one of the stock frustum planes failed, so we need to
3636 // create one or two custom planes to enclose the light origin
3637 for (i = 0;i < 4;i++)
3639 // create a plane using the view origin and light origin, and a
3640 // single point from the frustum corner set
3641 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3642 VectorNormalize(plane.normal);
3643 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3644 // see if this plane is backwards and flip it if so
3645 for (j = 0;j < 4;j++)
3646 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3650 VectorNegate(plane.normal, plane.normal);
3652 // flipped plane, test again to see if it is now valid
3653 for (j = 0;j < 4;j++)
3654 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3656 // if the plane is still not valid, then it is dividing the
3657 // frustum and has to be rejected
3661 // we have created a valid plane, compute extra info
3662 PlaneClassify(&plane);
3664 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3666 // if we've found 5 frustum planes then we have constructed a
3667 // proper split-side case and do not need to keep searching for
3668 // planes to enclose the light origin
3669 if (rtlight->cached_numfrustumplanes == 5)
3677 for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
3679 plane = rtlight->cached_frustumplanes[i];
3680 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));
3685 // now add the light-space box planes if the light box is rotated, as any
3686 // caster outside the oriented light box is irrelevant (even if it passed
3687 // the worldspace light box, which is axial)
3688 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3690 for (i = 0;i < 6;i++)
3694 v[i >> 1] = (i & 1) ? -1 : 1;
3695 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3696 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3697 plane.dist = VectorNormalizeLength(plane.normal);
3698 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3699 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3705 // add the world-space reduced box planes
3706 for (i = 0;i < 6;i++)
3708 VectorClear(plane.normal);
3709 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3710 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
3711 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3720 // reduce all plane distances to tightly fit the rtlight cull box, which
3722 VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3723 VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3724 VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3725 VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3726 VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3727 VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3728 VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3729 VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3730 oldnum = rtlight->cached_numfrustumplanes;
3731 rtlight->cached_numfrustumplanes = 0;
3732 for (j = 0;j < oldnum;j++)
3734 // find the nearest point on the box to this plane
3735 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
3736 for (i = 1;i < 8;i++)
3738 dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
3739 if (bestdist > dist)
3742 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);
3743 // if the nearest point is near or behind the plane, we want this
3744 // plane, otherwise the plane is useless as it won't cull anything
3745 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
3747 PlaneClassify(&rtlight->cached_frustumplanes[j]);
3748 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
3755 static void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
3759 RSurf_ActiveWorldEntity();
3761 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3764 GL_CullFace(GL_NONE);
3765 mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3766 for (;mesh;mesh = mesh->next)
3768 if (!mesh->sidetotals[r_shadow_shadowmapside])
3770 r_refdef.stats[r_stat_lights_shadowtriangles] += mesh->sidetotals[r_shadow_shadowmapside];
3771 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer, mesh->vbooffset_vertex3f);
3772 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);
3776 else if (r_refdef.scene.worldentity->model)
3777 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);
3779 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3782 static void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3784 qboolean zpass = false;
3787 int surfacelistindex;
3788 msurface_t *surface;
3790 // if triangle neighbors are disabled, shadowvolumes are disabled
3791 if (r_refdef.scene.worldmodel->brush.shadowmesh ? !r_refdef.scene.worldmodel->brush.shadowmesh->neighbor3i : !r_refdef.scene.worldmodel->surfmesh.data_neighbor3i)
3794 RSurf_ActiveWorldEntity();
3796 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3799 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
3801 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
3802 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
3804 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
3805 for (;mesh;mesh = mesh->next)
3807 r_refdef.stats[r_stat_lights_shadowtriangles] += mesh->numtriangles;
3808 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer, mesh->vbooffset_vertex3f);
3809 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
3811 // increment stencil if frontface is infront of depthbuffer
3812 GL_CullFace(r_refdef.view.cullface_back);
3813 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
3814 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);
3815 // decrement stencil if backface is infront of depthbuffer
3816 GL_CullFace(r_refdef.view.cullface_front);
3817 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
3819 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
3821 // decrement stencil if backface is behind depthbuffer
3822 GL_CullFace(r_refdef.view.cullface_front);
3823 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, 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 // increment stencil if frontface is behind depthbuffer
3826 GL_CullFace(r_refdef.view.cullface_back);
3827 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
3829 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);
3833 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh)
3835 // use the shadow trispvs calculated earlier by GetLightInfo to cull world triangles on this dynamic light
3836 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
3837 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
3839 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
3840 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
3841 if (CHECKPVSBIT(trispvs, t))
3842 shadowmarklist[numshadowmark++] = t;
3844 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);
3846 else if (numsurfaces)
3848 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);
3851 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3854 static void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3856 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3857 vec_t relativeshadowradius;
3858 RSurf_ActiveModelEntity(ent, false, false, false);
3859 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3860 // we need to re-init the shader for each entity because the matrix changed
3861 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3862 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3863 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3864 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3865 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3866 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3867 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3868 switch (r_shadow_rendermode)
3870 case R_SHADOW_RENDERMODE_SHADOWMAP2D:
3871 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
3874 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3877 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3880 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3882 // set up properties for rendering light onto this entity
3883 RSurf_ActiveModelEntity(ent, true, true, false);
3884 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3885 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3886 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3887 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3890 static void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
3892 if (!r_refdef.scene.worldmodel->DrawLight)
3895 // set up properties for rendering light onto this entity
3896 RSurf_ActiveWorldEntity();
3897 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3898 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3899 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3900 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3902 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
3904 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3907 static void R_Shadow_DrawEntityLight(entity_render_t *ent)
3909 dp_model_t *model = ent->model;
3910 if (!model->DrawLight)
3913 R_Shadow_SetupEntityLight(ent);
3915 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3917 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3920 static void R_Shadow_PrepareLight(rtlight_t *rtlight)
3924 int numleafs, numsurfaces;
3925 int *leaflist, *surfacelist;
3926 unsigned char *leafpvs;
3927 unsigned char *shadowtrispvs;
3928 unsigned char *lighttrispvs;
3929 //unsigned char *surfacesides;
3930 int numlightentities;
3931 int numlightentities_noselfshadow;
3932 int numshadowentities;
3933 int numshadowentities_noselfshadow;
3934 static entity_render_t *lightentities[MAX_EDICTS];
3935 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3936 static entity_render_t *shadowentities[MAX_EDICTS];
3937 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3939 qboolean castshadows;
3941 rtlight->draw = false;
3942 rtlight->cached_numlightentities = 0;
3943 rtlight->cached_numlightentities_noselfshadow = 0;
3944 rtlight->cached_numshadowentities = 0;
3945 rtlight->cached_numshadowentities_noselfshadow = 0;
3946 rtlight->cached_numsurfaces = 0;
3947 rtlight->cached_lightentities = NULL;
3948 rtlight->cached_lightentities_noselfshadow = NULL;
3949 rtlight->cached_shadowentities = NULL;
3950 rtlight->cached_shadowentities_noselfshadow = NULL;
3951 rtlight->cached_shadowtrispvs = NULL;
3952 rtlight->cached_lighttrispvs = NULL;
3953 rtlight->cached_surfacelist = NULL;
3955 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3956 // skip lights that are basically invisible (color 0 0 0)
3957 nolight = VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f);
3959 // loading is done before visibility checks because loading should happen
3960 // all at once at the start of a level, not when it stalls gameplay.
3961 // (especially important to benchmarks)
3963 if (rtlight->isstatic && !nolight && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
3965 if (rtlight->compiled)
3966 R_RTLight_Uncompile(rtlight);
3967 R_RTLight_Compile(rtlight);
3971 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
3973 // look up the light style value at this time
3974 f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3975 VectorScale(rtlight->color, f, rtlight->currentcolor);
3977 if (rtlight->selected)
3979 f = 2 + sin(realtime * M_PI * 4.0);
3980 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3984 // if lightstyle is currently off, don't draw the light
3985 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3988 // skip processing on corona-only lights
3992 // if the light box is offscreen, skip it
3993 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3996 VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
3997 VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
3999 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
4001 // 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
4002 if (r_shadow_bouncegrid.integer == 2 && (rtlight->isstatic || !r_shadow_bouncegrid_static.integer))
4005 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
4007 // compiled light, world available and can receive realtime lighting
4008 // retrieve leaf information
4009 numleafs = rtlight->static_numleafs;
4010 leaflist = rtlight->static_leaflist;
4011 leafpvs = rtlight->static_leafpvs;
4012 numsurfaces = rtlight->static_numsurfaces;
4013 surfacelist = rtlight->static_surfacelist;
4014 //surfacesides = NULL;
4015 shadowtrispvs = rtlight->static_shadowtrispvs;
4016 lighttrispvs = rtlight->static_lighttrispvs;
4018 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
4020 // dynamic light, world available and can receive realtime lighting
4021 // calculate lit surfaces and leafs
4022 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);
4023 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
4024 leaflist = r_shadow_buffer_leaflist;
4025 leafpvs = r_shadow_buffer_leafpvs;
4026 surfacelist = r_shadow_buffer_surfacelist;
4027 //surfacesides = r_shadow_buffer_surfacesides;
4028 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
4029 lighttrispvs = r_shadow_buffer_lighttrispvs;
4030 // if the reduced leaf bounds are offscreen, skip it
4031 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4042 //surfacesides = NULL;
4043 shadowtrispvs = NULL;
4044 lighttrispvs = NULL;
4046 // check if light is illuminating any visible leafs
4049 for (i = 0;i < numleafs;i++)
4050 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
4056 // make a list of lit entities and shadow casting entities
4057 numlightentities = 0;
4058 numlightentities_noselfshadow = 0;
4059 numshadowentities = 0;
4060 numshadowentities_noselfshadow = 0;
4062 // add dynamic entities that are lit by the light
4063 for (i = 0;i < r_refdef.scene.numentities;i++)
4066 entity_render_t *ent = r_refdef.scene.entities[i];
4068 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4070 // skip the object entirely if it is not within the valid
4071 // shadow-casting region (which includes the lit region)
4072 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
4074 if (!(model = ent->model))
4076 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
4078 // this entity wants to receive light, is visible, and is
4079 // inside the light box
4080 // TODO: check if the surfaces in the model can receive light
4081 // so now check if it's in a leaf seen by the light
4082 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))
4084 if (ent->flags & RENDER_NOSELFSHADOW)
4085 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
4087 lightentities[numlightentities++] = ent;
4088 // since it is lit, it probably also casts a shadow...
4089 // about the VectorDistance2 - light emitting entities should not cast their own shadow
4090 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
4091 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
4093 // note: exterior models without the RENDER_NOSELFSHADOW
4094 // flag still create a RENDER_NOSELFSHADOW shadow but
4095 // are lit normally, this means that they are
4096 // self-shadowing but do not shadow other
4097 // RENDER_NOSELFSHADOW entities such as the gun
4098 // (very weird, but keeps the player shadow off the gun)
4099 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
4100 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
4102 shadowentities[numshadowentities++] = ent;
4105 else if (ent->flags & RENDER_SHADOW)
4107 // this entity is not receiving light, but may still need to
4109 // TODO: check if the surfaces in the model can cast shadow
4110 // now check if it is in a leaf seen by the light
4111 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))
4113 // about the VectorDistance2 - light emitting entities should not cast their own shadow
4114 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
4115 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
4117 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
4118 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
4120 shadowentities[numshadowentities++] = ent;
4125 // return if there's nothing at all to light
4126 if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
4129 // count this light in the r_speeds
4130 r_refdef.stats[r_stat_lights]++;
4132 // flag it as worth drawing later
4133 rtlight->draw = true;
4135 // if we have shadows disabled, don't count the shadow entities, this way we don't do the R_AnimCache_GetEntity on each one
4136 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
4138 numshadowentities = numshadowentities_noselfshadow = 0;
4140 // cache all the animated entities that cast a shadow but are not visible
4141 for (i = 0;i < numshadowentities;i++)
4142 R_AnimCache_GetEntity(shadowentities[i], false, false);
4143 for (i = 0;i < numshadowentities_noselfshadow;i++)
4144 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
4146 // allocate some temporary memory for rendering this light later in the frame
4147 // reusable buffers need to be copied, static data can be used as-is
4148 rtlight->cached_numlightentities = numlightentities;
4149 rtlight->cached_numlightentities_noselfshadow = numlightentities_noselfshadow;
4150 rtlight->cached_numshadowentities = numshadowentities;
4151 rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
4152 rtlight->cached_numsurfaces = numsurfaces;
4153 rtlight->cached_lightentities = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
4154 rtlight->cached_lightentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
4155 rtlight->cached_shadowentities = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
4156 rtlight->cached_shadowentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
4157 if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
4159 int numshadowtrispvsbytes = (((r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles) + 7) >> 3);
4160 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
4161 rtlight->cached_shadowtrispvs = (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
4162 rtlight->cached_lighttrispvs = (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
4163 rtlight->cached_surfacelist = (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
4167 // compiled light data
4168 rtlight->cached_shadowtrispvs = shadowtrispvs;
4169 rtlight->cached_lighttrispvs = lighttrispvs;
4170 rtlight->cached_surfacelist = surfacelist;
4174 static void R_Shadow_DrawLight(rtlight_t *rtlight)
4178 unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
4179 int numlightentities;
4180 int numlightentities_noselfshadow;
4181 int numshadowentities;
4182 int numshadowentities_noselfshadow;
4183 entity_render_t **lightentities;
4184 entity_render_t **lightentities_noselfshadow;
4185 entity_render_t **shadowentities;
4186 entity_render_t **shadowentities_noselfshadow;
4188 static unsigned char entitysides[MAX_EDICTS];
4189 static unsigned char entitysides_noselfshadow[MAX_EDICTS];
4190 vec3_t nearestpoint;
4192 qboolean castshadows;
4195 // check if we cached this light this frame (meaning it is worth drawing)
4199 numlightentities = rtlight->cached_numlightentities;
4200 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
4201 numshadowentities = rtlight->cached_numshadowentities;
4202 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
4203 numsurfaces = rtlight->cached_numsurfaces;
4204 lightentities = rtlight->cached_lightentities;
4205 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
4206 shadowentities = rtlight->cached_shadowentities;
4207 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
4208 shadowtrispvs = rtlight->cached_shadowtrispvs;
4209 lighttrispvs = rtlight->cached_lighttrispvs;
4210 surfacelist = rtlight->cached_surfacelist;
4212 // set up a scissor rectangle for this light
4213 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
4216 // don't let sound skip if going slow
4217 if (r_refdef.scene.extraupdate)
4220 // make this the active rtlight for rendering purposes
4221 R_Shadow_RenderMode_ActiveLight(rtlight);
4223 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
4225 // optionally draw visible shape of the shadow volumes
4226 // for performance analysis by level designers
4227 R_Shadow_RenderMode_VisibleShadowVolumes();
4229 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
4230 for (i = 0;i < numshadowentities;i++)
4231 R_Shadow_DrawEntityShadow(shadowentities[i]);
4232 for (i = 0;i < numshadowentities_noselfshadow;i++)
4233 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
4234 R_Shadow_RenderMode_VisibleLighting(false, false);
4237 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
4239 // optionally draw the illuminated areas
4240 // for performance analysis by level designers
4241 R_Shadow_RenderMode_VisibleLighting(false, false);
4243 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4244 for (i = 0;i < numlightentities;i++)
4245 R_Shadow_DrawEntityLight(lightentities[i]);
4246 for (i = 0;i < numlightentities_noselfshadow;i++)
4247 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4250 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
4252 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
4253 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
4254 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
4255 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
4257 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance/rtlight->radius));
4258 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
4259 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
4261 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
4267 int receivermask = 0;
4268 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
4269 Matrix4x4_Abs(&radiustolight);
4271 r_shadow_shadowmaplod = 0;
4272 for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
4273 if ((r_shadow_shadowmapmaxsize >> i) > lodlinear)
4274 r_shadow_shadowmaplod = i;
4276 size = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
4278 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
4280 surfacesides = NULL;
4283 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
4285 castermask = rtlight->static_shadowmap_casters;
4286 receivermask = rtlight->static_shadowmap_receivers;
4290 surfacesides = r_shadow_buffer_surfacesides;
4291 for(i = 0;i < numsurfaces;i++)
4293 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
4294 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4295 castermask |= surfacesides[i];
4296 receivermask |= surfacesides[i];
4300 if (receivermask < 0x3F)
4302 for (i = 0;i < numlightentities;i++)
4303 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4304 if (receivermask < 0x3F)
4305 for(i = 0; i < numlightentities_noselfshadow;i++)
4306 receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4309 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
4313 for (i = 0;i < numshadowentities;i++)
4314 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
4315 for (i = 0;i < numshadowentities_noselfshadow;i++)
4316 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
4319 //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
4321 // render shadow casters into 6 sided depth texture
4322 for (side = 0;side < 6;side++) if (receivermask & (1 << side))
4324 R_Shadow_RenderMode_ShadowMap(side, receivermask, size);
4325 if (! (castermask & (1 << side))) continue;
4327 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
4328 for (i = 0;i < numshadowentities;i++) if (entitysides[i] & (1 << side))
4329 R_Shadow_DrawEntityShadow(shadowentities[i]);
4332 if (numlightentities_noselfshadow)
4334 // render lighting using the depth texture as shadowmap
4335 // draw lighting in the unmasked areas
4336 R_Shadow_RenderMode_Lighting(false, false, true);
4337 for (i = 0;i < numlightentities_noselfshadow;i++)
4338 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4341 // render shadow casters into 6 sided depth texture
4342 if (numshadowentities_noselfshadow)
4344 for (side = 0;side < 6;side++) if ((receivermask & castermask) & (1 << side))
4346 R_Shadow_RenderMode_ShadowMap(side, 0, size);
4347 for (i = 0;i < numshadowentities_noselfshadow;i++) if (entitysides_noselfshadow[i] & (1 << side))
4348 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
4352 // render lighting using the depth texture as shadowmap
4353 // draw lighting in the unmasked areas
4354 R_Shadow_RenderMode_Lighting(false, false, true);
4355 // draw lighting in the unmasked areas
4357 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4358 for (i = 0;i < numlightentities;i++)
4359 R_Shadow_DrawEntityLight(lightentities[i]);
4361 else if (castshadows && vid.stencil)
4363 // draw stencil shadow volumes to mask off pixels that are in shadow
4364 // so that they won't receive lighting
4365 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
4366 R_Shadow_ClearStencil();
4369 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
4370 for (i = 0;i < numshadowentities;i++)
4371 R_Shadow_DrawEntityShadow(shadowentities[i]);
4373 // draw lighting in the unmasked areas
4374 R_Shadow_RenderMode_Lighting(true, false, false);
4375 for (i = 0;i < numlightentities_noselfshadow;i++)
4376 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4378 for (i = 0;i < numshadowentities_noselfshadow;i++)
4379 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
4381 // draw lighting in the unmasked areas
4382 R_Shadow_RenderMode_Lighting(true, false, false);
4384 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4385 for (i = 0;i < numlightentities;i++)
4386 R_Shadow_DrawEntityLight(lightentities[i]);
4390 // draw lighting in the unmasked areas
4391 R_Shadow_RenderMode_Lighting(false, false, false);
4393 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4394 for (i = 0;i < numlightentities;i++)
4395 R_Shadow_DrawEntityLight(lightentities[i]);
4396 for (i = 0;i < numlightentities_noselfshadow;i++)
4397 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4400 if (r_shadow_usingdeferredprepass)
4402 // when rendering deferred lighting, we simply rasterize the box
4403 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
4404 R_Shadow_RenderMode_DrawDeferredLight(false, true);
4405 else if (castshadows && vid.stencil)
4406 R_Shadow_RenderMode_DrawDeferredLight(true, false);
4408 R_Shadow_RenderMode_DrawDeferredLight(false, false);
4412 static void R_Shadow_FreeDeferred(void)
4414 R_Mesh_DestroyFramebufferObject(r_shadow_prepassgeometryfbo);
4415 r_shadow_prepassgeometryfbo = 0;
4417 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusespecularfbo);
4418 r_shadow_prepasslightingdiffusespecularfbo = 0;
4420 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusefbo);
4421 r_shadow_prepasslightingdiffusefbo = 0;
4423 if (r_shadow_prepassgeometrydepthbuffer)
4424 R_FreeTexture(r_shadow_prepassgeometrydepthbuffer);
4425 r_shadow_prepassgeometrydepthbuffer = NULL;
4427 if (r_shadow_prepassgeometrynormalmaptexture)
4428 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
4429 r_shadow_prepassgeometrynormalmaptexture = NULL;
4431 if (r_shadow_prepasslightingdiffusetexture)
4432 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
4433 r_shadow_prepasslightingdiffusetexture = NULL;
4435 if (r_shadow_prepasslightingspeculartexture)
4436 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
4437 r_shadow_prepasslightingspeculartexture = NULL;
4440 void R_Shadow_DrawPrepass(void)
4448 entity_render_t *ent;
4449 float clearcolor[4];
4451 R_Mesh_ResetTextureState();
4453 GL_ColorMask(1,1,1,1);
4454 GL_BlendFunc(GL_ONE, GL_ZERO);
4457 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4458 Vector4Set(clearcolor, 0.5f,0.5f,0.5f,1.0f);
4459 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4460 if (r_timereport_active)
4461 R_TimeReport("prepasscleargeom");
4463 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
4464 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
4465 if (r_timereport_active)
4466 R_TimeReport("prepassworld");
4468 for (i = 0;i < r_refdef.scene.numentities;i++)
4470 if (!r_refdef.viewcache.entityvisible[i])
4472 ent = r_refdef.scene.entities[i];
4473 if (ent->model && ent->model->DrawPrepass != NULL)
4474 ent->model->DrawPrepass(ent);
4477 if (r_timereport_active)
4478 R_TimeReport("prepassmodels");
4480 GL_DepthMask(false);
4481 GL_ColorMask(1,1,1,1);
4484 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4485 Vector4Set(clearcolor, 0, 0, 0, 0);
4486 GL_Clear(GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
4487 if (r_timereport_active)
4488 R_TimeReport("prepassclearlit");
4490 R_Shadow_RenderMode_Begin();
4492 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4493 if (r_shadow_debuglight.integer >= 0)
4495 lightindex = r_shadow_debuglight.integer;
4496 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4497 if (light && (light->flags & flag) && light->rtlight.draw)
4498 R_Shadow_DrawLight(&light->rtlight);
4502 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4503 for (lightindex = 0;lightindex < range;lightindex++)
4505 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4506 if (light && (light->flags & flag) && light->rtlight.draw)
4507 R_Shadow_DrawLight(&light->rtlight);
4510 if (r_refdef.scene.rtdlight)
4511 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4512 if (r_refdef.scene.lights[lnum]->draw)
4513 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4515 R_Shadow_RenderMode_End();
4517 if (r_timereport_active)
4518 R_TimeReport("prepasslights");
4521 void R_Shadow_DrawLightSprites(void);
4522 void R_Shadow_PrepareLights(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture)
4531 if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4) ||
4532 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
4533 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20) ||
4534 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
4535 r_shadow_shadowmapshadowsampler != (vid.support.arb_shadow && r_shadow_shadowmapping_useshadowsampler.integer) ||
4536 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
4537 r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16) ||
4538 r_shadow_shadowmapdepthtexture != r_fb.usedepthtextures)
4539 R_Shadow_FreeShadowMaps();
4541 r_shadow_fb_fbo = fbo;
4542 r_shadow_fb_depthtexture = depthtexture;
4543 r_shadow_fb_colortexture = colortexture;
4545 r_shadow_usingshadowmaportho = false;
4547 switch (vid.renderpath)
4549 case RENDERPATH_GL20:
4550 case RENDERPATH_D3D9:
4551 case RENDERPATH_D3D10:
4552 case RENDERPATH_D3D11:
4553 case RENDERPATH_SOFT:
4555 if (!r_shadow_deferred.integer || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_STENCIL || !vid.support.ext_framebuffer_object || vid.maxdrawbuffers < 2)
4557 r_shadow_usingdeferredprepass = false;
4558 if (r_shadow_prepass_width)
4559 R_Shadow_FreeDeferred();
4560 r_shadow_prepass_width = r_shadow_prepass_height = 0;
4564 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
4566 R_Shadow_FreeDeferred();
4568 r_shadow_usingdeferredprepass = true;
4569 r_shadow_prepass_width = vid.width;
4570 r_shadow_prepass_height = vid.height;
4571 r_shadow_prepassgeometrydepthbuffer = R_LoadTextureRenderBuffer(r_shadow_texturepool, "prepassgeometrydepthbuffer", vid.width, vid.height, TEXTYPE_DEPTHBUFFER24);
4572 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);
4573 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);
4574 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);
4576 // set up the geometry pass fbo (depth + normalmap)
4577 r_shadow_prepassgeometryfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4578 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4579 // render depth into a renderbuffer and other important properties into the normalmap texture
4581 // set up the lighting pass fbo (diffuse + specular)
4582 r_shadow_prepasslightingdiffusespecularfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4583 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4584 // render diffuse into one texture and specular into another,
4585 // with depth and normalmap bound as textures,
4586 // with depth bound as attachment as well
4588 // set up the lighting pass fbo (diffuse)
4589 r_shadow_prepasslightingdiffusefbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
4590 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthbuffer, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
4591 // render diffuse into one texture,
4592 // with depth and normalmap bound as textures,
4593 // with depth bound as attachment as well
4597 case RENDERPATH_GL11:
4598 case RENDERPATH_GL13:
4599 case RENDERPATH_GLES1:
4600 case RENDERPATH_GLES2:
4601 r_shadow_usingdeferredprepass = false;
4605 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);
4607 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4608 if (r_shadow_debuglight.integer >= 0)
4610 lightindex = r_shadow_debuglight.integer;
4611 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4613 R_Shadow_PrepareLight(&light->rtlight);
4617 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4618 for (lightindex = 0;lightindex < range;lightindex++)
4620 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4621 if (light && (light->flags & flag))
4622 R_Shadow_PrepareLight(&light->rtlight);
4625 if (r_refdef.scene.rtdlight)
4627 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4628 R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
4630 else if(gl_flashblend.integer)
4632 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4634 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
4635 f = ((rtlight->style >= 0 && rtlight->style < MAX_LIGHTSTYLES) ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4636 VectorScale(rtlight->color, f, rtlight->currentcolor);
4640 if (r_editlights.integer)
4641 R_Shadow_DrawLightSprites();
4644 void R_Shadow_DrawLights(void)
4652 R_Shadow_RenderMode_Begin();
4654 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4655 if (r_shadow_debuglight.integer >= 0)
4657 lightindex = r_shadow_debuglight.integer;
4658 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4660 R_Shadow_DrawLight(&light->rtlight);
4664 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4665 for (lightindex = 0;lightindex < range;lightindex++)
4667 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4668 if (light && (light->flags & flag))
4669 R_Shadow_DrawLight(&light->rtlight);
4672 if (r_refdef.scene.rtdlight)
4673 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4674 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4676 R_Shadow_RenderMode_End();
4679 #define MAX_MODELSHADOWS 1024
4680 static int r_shadow_nummodelshadows;
4681 static entity_render_t *r_shadow_modelshadows[MAX_MODELSHADOWS];
4683 void R_Shadow_PrepareModelShadows(void)
4686 float scale, size, radius, dot1, dot2;
4687 prvm_vec3_t prvmshadowdir, prvmshadowfocus;
4688 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
4689 entity_render_t *ent;
4691 r_shadow_nummodelshadows = 0;
4692 if (!r_refdef.scene.numentities)
4695 switch (r_shadow_shadowmode)
4697 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4698 if (r_shadows.integer >= 2)
4701 case R_SHADOW_SHADOWMODE_STENCIL:
4704 for (i = 0;i < r_refdef.scene.numentities;i++)
4706 ent = r_refdef.scene.entities[i];
4707 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4709 if (r_shadow_nummodelshadows >= MAX_MODELSHADOWS)
4711 r_shadow_modelshadows[r_shadow_nummodelshadows++] = ent;
4712 R_AnimCache_GetEntity(ent, false, false);
4720 size = 2*r_shadow_shadowmapmaxsize;
4721 scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
4722 radius = 0.5f * size / scale;
4724 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
4725 VectorCopy(prvmshadowdir, shadowdir);
4726 VectorNormalize(shadowdir);
4727 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4728 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4729 if (fabs(dot1) <= fabs(dot2))
4730 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4732 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4733 VectorNormalize(shadowforward);
4734 CrossProduct(shadowdir, shadowforward, shadowright);
4735 Math_atov(r_shadows_focus.string, prvmshadowfocus);
4736 VectorCopy(prvmshadowfocus, shadowfocus);
4737 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4738 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4739 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4740 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4741 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4743 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4745 shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4746 shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4747 shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4748 shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4749 shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4750 shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4752 for (i = 0;i < r_refdef.scene.numentities;i++)
4754 ent = r_refdef.scene.entities[i];
4755 if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
4757 // cast shadows from anything of the map (submodels are optional)
4758 if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4760 if (r_shadow_nummodelshadows >= MAX_MODELSHADOWS)
4762 r_shadow_modelshadows[r_shadow_nummodelshadows++] = ent;
4763 R_AnimCache_GetEntity(ent, false, false);
4768 void R_DrawModelShadowMaps(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture)
4771 float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
4772 entity_render_t *ent;
4773 vec3_t relativelightorigin;
4774 vec3_t relativelightdirection, relativeforward, relativeright;
4775 vec3_t relativeshadowmins, relativeshadowmaxs;
4776 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
4777 prvm_vec3_t prvmshadowdir, prvmshadowfocus;
4779 matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
4780 r_viewport_t viewport;
4781 GLuint shadowfbo = 0;
4782 float clearcolor[4];
4784 if (!r_shadow_nummodelshadows)
4787 switch (r_shadow_shadowmode)
4789 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4795 r_shadow_fb_fbo = fbo;
4796 r_shadow_fb_depthtexture = depthtexture;
4797 r_shadow_fb_colortexture = colortexture;
4799 R_ResetViewRendering3D(fbo, depthtexture, colortexture);
4800 R_Shadow_RenderMode_Begin();
4801 R_Shadow_RenderMode_ActiveLight(NULL);
4803 switch (r_shadow_shadowmode)
4805 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4806 if (!r_shadow_shadowmap2ddepthtexture)
4807 R_Shadow_MakeShadowMap(0, r_shadow_shadowmapmaxsize);
4808 shadowfbo = r_shadow_fbo2d;
4809 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2ddepthtexture);
4810 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2ddepthtexture);
4811 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
4817 size = 2*r_shadow_shadowmapmaxsize;
4818 scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
4819 radius = 0.5f / scale;
4820 nearclip = -r_shadows_throwdistance.value;
4821 farclip = r_shadows_throwdistance.value;
4822 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);
4824 r_shadow_shadowmap_parameters[0] = size;
4825 r_shadow_shadowmap_parameters[1] = size;
4826 r_shadow_shadowmap_parameters[2] = 1.0;
4827 r_shadow_shadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
4829 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
4830 VectorCopy(prvmshadowdir, shadowdir);
4831 VectorNormalize(shadowdir);
4832 Math_atov(r_shadows_focus.string, prvmshadowfocus);
4833 VectorCopy(prvmshadowfocus, shadowfocus);
4834 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4835 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4836 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4837 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4838 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4839 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4840 if (fabs(dot1) <= fabs(dot2))
4841 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4843 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4844 VectorNormalize(shadowforward);
4845 VectorM(scale, shadowforward, &m[0]);
4846 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4848 m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
4849 CrossProduct(shadowdir, shadowforward, shadowright);
4850 VectorM(scale, shadowright, &m[4]);
4851 m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
4852 VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
4853 m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
4854 Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
4855 Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
4856 R_Viewport_InitOrtho(&viewport, &cameramatrix, 0, 0, size, size, 0, 0, 1, 1, 0, -1, NULL);
4858 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4860 if (r_shadow_shadowmap2ddepthbuffer)
4861 R_Mesh_SetRenderTargets(shadowfbo, r_shadow_shadowmap2ddepthbuffer, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL);
4863 R_Mesh_SetRenderTargets(shadowfbo, r_shadow_shadowmap2ddepthtexture, NULL, NULL, NULL, NULL);
4864 R_SetupShader_DepthOrShadow(true, r_shadow_shadowmap2ddepthbuffer != NULL, false); // FIXME test if we have a skeletal model?
4865 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
4868 R_SetViewport(&viewport);
4869 GL_Scissor(viewport.x, viewport.y, min(viewport.width + r_shadow_shadowmapborder, 2*r_shadow_shadowmapmaxsize), viewport.height + r_shadow_shadowmapborder);
4870 Vector4Set(clearcolor, 1,1,1,1);
4871 // in D3D9 we have to render to a color texture shadowmap
4872 // in GL we render directly to a depth texture only
4873 if (r_shadow_shadowmap2ddepthbuffer)
4874 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4876 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4877 // render into a slightly restricted region so that the borders of the
4878 // shadowmap area fade away, rather than streaking across everything
4879 // outside the usable area
4880 GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
4882 for (i = 0;i < r_shadow_nummodelshadows;i++)
4884 ent = r_shadow_modelshadows[i];
4885 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4886 Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
4887 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4888 Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
4889 Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
4890 relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4891 relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4892 relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4893 relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4894 relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4895 relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4896 RSurf_ActiveModelEntity(ent, false, false, false);
4897 ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
4898 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4904 unsigned char *rawpixels = Z_Malloc(viewport.width*viewport.height*4);
4906 qglReadPixels(viewport.x, viewport.y, viewport.width, viewport.height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, rawpixels);
4908 Image_WriteTGABGRA("r_shadows_2.tga", viewport.width, viewport.height, rawpixels);
4909 Cvar_SetValueQuick(&r_test, 0);
4914 R_Shadow_RenderMode_End();
4916 Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
4917 Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
4918 Matrix4x4_CreateScale3(&scalematrix, size, -size, 1);
4919 Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
4920 Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
4921 Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
4923 switch (vid.renderpath)
4925 case RENDERPATH_GL11:
4926 case RENDERPATH_GL13:
4927 case RENDERPATH_GL20:
4928 case RENDERPATH_SOFT:
4929 case RENDERPATH_GLES1:
4930 case RENDERPATH_GLES2:
4932 case RENDERPATH_D3D9:
4933 case RENDERPATH_D3D10:
4934 case RENDERPATH_D3D11:
4935 #ifdef MATRIX4x4_OPENGLORIENTATION
4936 r_shadow_shadowmapmatrix.m[0][0] *= -1.0f;
4937 r_shadow_shadowmapmatrix.m[0][1] *= -1.0f;
4938 r_shadow_shadowmapmatrix.m[0][2] *= -1.0f;
4939 r_shadow_shadowmapmatrix.m[0][3] *= -1.0f;
4941 r_shadow_shadowmapmatrix.m[0][0] *= -1.0f;
4942 r_shadow_shadowmapmatrix.m[1][0] *= -1.0f;
4943 r_shadow_shadowmapmatrix.m[2][0] *= -1.0f;
4944 r_shadow_shadowmapmatrix.m[3][0] *= -1.0f;
4949 r_shadow_usingshadowmaportho = true;
4950 switch (r_shadow_shadowmode)
4952 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4953 r_shadow_usingshadowmap2d = true;
4960 void R_DrawModelShadows(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture)
4963 float relativethrowdistance;
4964 entity_render_t *ent;
4965 vec3_t relativelightorigin;
4966 vec3_t relativelightdirection;
4967 vec3_t relativeshadowmins, relativeshadowmaxs;
4968 vec3_t tmp, shadowdir;
4969 prvm_vec3_t prvmshadowdir;
4971 if (!r_shadow_nummodelshadows || (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL && r_shadows.integer != 1))
4974 r_shadow_fb_fbo = fbo;
4975 r_shadow_fb_depthtexture = depthtexture;
4976 r_shadow_fb_colortexture = colortexture;
4978 R_ResetViewRendering3D(fbo, depthtexture, colortexture);
4979 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4980 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4981 R_Shadow_RenderMode_Begin();
4982 R_Shadow_RenderMode_ActiveLight(NULL);
4983 r_shadow_lightscissor[0] = r_refdef.view.x;
4984 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
4985 r_shadow_lightscissor[2] = r_refdef.view.width;
4986 r_shadow_lightscissor[3] = r_refdef.view.height;
4987 R_Shadow_RenderMode_StencilShadowVolumes(false);
4990 if (r_shadows.integer == 2)
4992 Math_atov(r_shadows_throwdirection.string, prvmshadowdir);
4993 VectorCopy(prvmshadowdir, shadowdir);
4994 VectorNormalize(shadowdir);
4997 R_Shadow_ClearStencil();
4999 for (i = 0;i < r_shadow_nummodelshadows;i++)
5001 ent = r_shadow_modelshadows[i];
5003 // cast shadows from anything of the map (submodels are optional)
5004 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
5005 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
5006 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
5007 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
5008 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
5011 if(ent->entitynumber != 0)
5013 if(ent->entitynumber >= MAX_EDICTS) // csqc entity
5015 // FIXME handle this
5016 VectorNegate(ent->modellight_lightdir, relativelightdirection);
5020 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
5021 int entnum, entnum2, recursion;
5022 entnum = entnum2 = ent->entitynumber;
5023 for(recursion = 32; recursion > 0; --recursion)
5025 entnum2 = cl.entities[entnum].state_current.tagentity;
5026 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
5031 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
5033 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
5034 // transform into modelspace of OUR entity
5035 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
5036 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
5039 VectorNegate(ent->modellight_lightdir, relativelightdirection);
5043 VectorNegate(ent->modellight_lightdir, relativelightdirection);
5046 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
5047 RSurf_ActiveModelEntity(ent, false, false, false);
5048 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
5049 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
5052 // not really the right mode, but this will disable any silly stencil features
5053 R_Shadow_RenderMode_End();
5055 // set up ortho view for rendering this pass
5056 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
5057 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5058 //GL_ScissorTest(true);
5059 //R_EntityMatrix(&identitymatrix);
5060 //R_Mesh_ResetTextureState();
5061 R_ResetViewRendering2D(fbo, depthtexture, colortexture);
5063 // set up a darkening blend on shadowed areas
5064 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5065 //GL_DepthRange(0, 1);
5066 //GL_DepthTest(false);
5067 //GL_DepthMask(false);
5068 //GL_PolygonOffset(0, 0);CHECKGLERROR
5069 GL_Color(0, 0, 0, r_shadows_darken.value);
5070 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5071 //GL_DepthFunc(GL_ALWAYS);
5072 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_NOTEQUAL, 128, 255);
5074 // apply the blend to the shadowed areas
5075 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, NULL);
5076 R_SetupShader_Generic_NoTexture(false, true);
5077 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5079 // restore the viewport
5080 R_SetViewport(&r_refdef.view.viewport);
5082 // restore other state to normal
5083 //R_Shadow_RenderMode_End();
5086 static void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
5089 vec3_t centerorigin;
5090 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5093 // if it's too close, skip it
5094 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
5096 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
5099 if (usequery && r_numqueries + 2 <= r_maxqueries)
5101 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
5102 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
5103 // 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
5104 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
5106 switch(vid.renderpath)
5108 case RENDERPATH_GL11:
5109 case RENDERPATH_GL13:
5110 case RENDERPATH_GL20:
5111 case RENDERPATH_GLES1:
5112 case RENDERPATH_GLES2:
5113 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5115 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use GL_DepthFunc instead
5116 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
5117 GL_DepthFunc(GL_ALWAYS);
5118 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5119 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
5120 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5121 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
5122 GL_DepthFunc(GL_LEQUAL);
5123 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
5124 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5125 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL, 0);
5126 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5127 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
5131 case RENDERPATH_D3D9:
5132 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5134 case RENDERPATH_D3D10:
5135 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5137 case RENDERPATH_D3D11:
5138 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5140 case RENDERPATH_SOFT:
5141 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5145 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
5148 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
5150 static void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
5153 unsigned int occlude = 0;
5154 GLint allpixels = 0, visiblepixels = 0;
5156 // now we have to check the query result
5157 if (rtlight->corona_queryindex_visiblepixels)
5159 switch(vid.renderpath)
5161 case RENDERPATH_GL11:
5162 case RENDERPATH_GL13:
5163 case RENDERPATH_GL20:
5164 case RENDERPATH_GLES1:
5165 case RENDERPATH_GLES2:
5166 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5168 // See if we can use the GPU-side method to prevent implicit sync
5169 if (vid.support.arb_query_buffer_object) {
5170 #define BUFFER_OFFSET(i) ((void*)NULL + (i))
5171 if (!r_shadow_occlusion_buf) {
5172 qglGenBuffersARB(1, &r_shadow_occlusion_buf);
5173 qglBindBufferARB(GL_QUERY_BUFFER_ARB, r_shadow_occlusion_buf);
5174 qglBufferDataARB(GL_QUERY_BUFFER_ARB, 8, NULL, GL_DYNAMIC_COPY);
5176 qglBindBufferARB(GL_QUERY_BUFFER_ARB, r_shadow_occlusion_buf);
5178 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, BUFFER_OFFSET(0));
5179 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, BUFFER_OFFSET(4));
5180 qglBindBufferBase(GL_UNIFORM_BUFFER, 0, r_shadow_occlusion_buf);
5181 occlude = MATERIALFLAG_OCCLUDE;
5183 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
5184 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
5185 if (visiblepixels < 1 || allpixels < 1)
5187 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
5189 cscale *= rtlight->corona_visibility;
5195 case RENDERPATH_D3D9:
5196 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5198 case RENDERPATH_D3D10:
5199 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5201 case RENDERPATH_D3D11:
5202 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5204 case RENDERPATH_SOFT:
5205 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5213 // FIXME: these traces should scan all render entities instead of cl.world
5214 if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, collision_extendmovelength.value, true, false, NULL, false, true).fraction < 1)
5217 VectorScale(rtlight->currentcolor, cscale, color);
5218 if (VectorLength(color) > (1.0f / 256.0f))
5221 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
5224 VectorNegate(color, color);
5225 GL_BlendEquationSubtract(true);
5227 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
5228 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);
5229 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE | MATERIALFLAG_NODEPTHTEST | occlude, 0, 4, 0, 2, false, false);
5231 GL_BlendEquationSubtract(false);
5235 void R_Shadow_DrawCoronas(void)
5238 qboolean usequery = false;
5243 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
5245 if (r_fb.water.renderingscene)
5247 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
5248 R_EntityMatrix(&identitymatrix);
5250 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5252 // check occlusion of coronas
5253 // use GL_ARB_occlusion_query if available
5254 // otherwise use raytraces
5256 switch (vid.renderpath)
5258 case RENDERPATH_GL11:
5259 case RENDERPATH_GL13:
5260 case RENDERPATH_GL20:
5261 case RENDERPATH_GLES1:
5262 case RENDERPATH_GLES2:
5263 usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
5264 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
5267 GL_ColorMask(0,0,0,0);
5268 if (r_maxqueries < ((unsigned int)range + r_refdef.scene.numlights) * 2)
5269 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
5272 r_maxqueries = ((unsigned int)range + r_refdef.scene.numlights) * 4;
5273 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
5275 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
5278 RSurf_ActiveWorldEntity();
5279 GL_BlendFunc(GL_ONE, GL_ZERO);
5280 GL_CullFace(GL_NONE);
5281 GL_DepthMask(false);
5282 GL_DepthRange(0, 1);
5283 GL_PolygonOffset(0, 0);
5285 R_Mesh_ResetTextureState();
5286 R_SetupShader_Generic_NoTexture(false, false);
5290 case RENDERPATH_D3D9:
5292 //Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5294 case RENDERPATH_D3D10:
5295 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5297 case RENDERPATH_D3D11:
5298 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5300 case RENDERPATH_SOFT:
5302 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5305 for (lightindex = 0;lightindex < range;lightindex++)
5307 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5310 rtlight = &light->rtlight;
5311 rtlight->corona_visibility = 0;
5312 rtlight->corona_queryindex_visiblepixels = 0;
5313 rtlight->corona_queryindex_allpixels = 0;
5314 if (!(rtlight->flags & flag))
5316 if (rtlight->corona <= 0)
5318 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
5320 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
5322 for (i = 0;i < r_refdef.scene.numlights;i++)
5324 rtlight = r_refdef.scene.lights[i];
5325 rtlight->corona_visibility = 0;
5326 rtlight->corona_queryindex_visiblepixels = 0;
5327 rtlight->corona_queryindex_allpixels = 0;
5328 if (!(rtlight->flags & flag))
5330 if (rtlight->corona <= 0)
5332 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
5335 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5337 // now draw the coronas using the query data for intensity info
5338 for (lightindex = 0;lightindex < range;lightindex++)
5340 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5343 rtlight = &light->rtlight;
5344 if (rtlight->corona_visibility <= 0)
5346 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
5348 for (i = 0;i < r_refdef.scene.numlights;i++)
5350 rtlight = r_refdef.scene.lights[i];
5351 if (rtlight->corona_visibility <= 0)
5353 if (gl_flashblend.integer)
5354 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
5356 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
5362 static dlight_t *R_Shadow_NewWorldLight(void)
5364 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
5367 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)
5371 // 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
5373 // validate parameters
5377 // copy to light properties
5378 VectorCopy(origin, light->origin);
5379 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
5380 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
5381 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
5383 light->color[0] = max(color[0], 0);
5384 light->color[1] = max(color[1], 0);
5385 light->color[2] = max(color[2], 0);
5387 light->color[0] = color[0];
5388 light->color[1] = color[1];
5389 light->color[2] = color[2];
5390 light->radius = max(radius, 0);
5391 light->style = style;
5392 light->shadow = shadowenable;
5393 light->corona = corona;
5394 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
5395 light->coronasizescale = coronasizescale;
5396 light->ambientscale = ambientscale;
5397 light->diffusescale = diffusescale;
5398 light->specularscale = specularscale;
5399 light->flags = flags;
5401 // update renderable light data
5402 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
5403 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);
5406 static void R_Shadow_FreeWorldLight(dlight_t *light)
5408 if (r_shadow_selectedlight == light)
5409 r_shadow_selectedlight = NULL;
5410 R_RTLight_Uncompile(&light->rtlight);
5411 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
5414 void R_Shadow_ClearWorldLights(void)
5418 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5419 for (lightindex = 0;lightindex < range;lightindex++)
5421 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5423 R_Shadow_FreeWorldLight(light);
5425 r_shadow_selectedlight = NULL;
5428 static void R_Shadow_SelectLight(dlight_t *light)
5430 if (r_shadow_selectedlight)
5431 r_shadow_selectedlight->selected = false;
5432 r_shadow_selectedlight = light;
5433 if (r_shadow_selectedlight)
5434 r_shadow_selectedlight->selected = true;
5437 static void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
5439 // this is never batched (there can be only one)
5441 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
5442 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
5443 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5446 static void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
5451 skinframe_t *skinframe;
5454 // this is never batched (due to the ent parameter changing every time)
5455 // so numsurfaces == 1 and surfacelist[0] == lightnumber
5456 const dlight_t *light = (dlight_t *)ent;
5459 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
5462 VectorScale(light->color, intensity, spritecolor);
5463 if (VectorLength(spritecolor) < 0.1732f)
5464 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
5465 if (VectorLength(spritecolor) > 1.0f)
5466 VectorNormalize(spritecolor);
5468 // draw light sprite
5469 if (light->cubemapname[0] && !light->shadow)
5470 skinframe = r_editlights_sprcubemapnoshadowlight;
5471 else if (light->cubemapname[0])
5472 skinframe = r_editlights_sprcubemaplight;
5473 else if (!light->shadow)
5474 skinframe = r_editlights_sprnoshadowlight;
5476 skinframe = r_editlights_sprlight;
5478 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);
5479 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5481 // draw selection sprite if light is selected
5482 if (light->selected)
5484 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
5485 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5486 // VorteX todo: add normalmode/realtime mode light overlay sprites?
5490 void R_Shadow_DrawLightSprites(void)
5494 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5495 for (lightindex = 0;lightindex < range;lightindex++)
5497 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5499 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
5501 if (!r_editlights_lockcursor)
5502 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
5505 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
5510 range = (unsigned int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
5511 if (lightindex >= range)
5513 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5516 rtlight = &light->rtlight;
5517 //if (!(rtlight->flags & flag))
5519 VectorCopy(rtlight->shadoworigin, origin);
5520 *radius = rtlight->radius;
5521 VectorCopy(rtlight->color, color);
5525 static void R_Shadow_SelectLightInView(void)
5527 float bestrating, rating, temp[3];
5531 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5535 if (r_editlights_lockcursor)
5537 for (lightindex = 0;lightindex < range;lightindex++)
5539 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5542 VectorSubtract(light->origin, r_refdef.view.origin, temp);
5543 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
5546 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
5547 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)
5549 bestrating = rating;
5554 R_Shadow_SelectLight(best);
5557 void R_Shadow_LoadWorldLights(void)
5559 int n, a, style, shadow, flags;
5560 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
5561 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
5562 if (cl.worldmodel == NULL)
5564 Con_Print("No map loaded.\n");
5567 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
5568 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5578 for (;COM_Parse(t, true) && strcmp(
5579 if (COM_Parse(t, true))
5581 if (com_token[0] == '!')
5584 origin[0] = atof(com_token+1);
5587 origin[0] = atof(com_token);
5592 while (*s && *s != '\n' && *s != '\r')
5598 // check for modifier flags
5605 #if _MSC_VER >= 1400
5606 #define sscanf sscanf_s
5608 cubemapname[sizeof(cubemapname)-1] = 0;
5609 #if MAX_QPATH != 128
5610 #error update this code if MAX_QPATH changes
5612 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
5613 #if _MSC_VER >= 1400
5614 , sizeof(cubemapname)
5616 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
5619 flags = LIGHTFLAG_REALTIMEMODE;
5627 coronasizescale = 0.25f;
5629 VectorClear(angles);
5632 if (a < 9 || !strcmp(cubemapname, "\"\""))
5634 // remove quotes on cubemapname
5635 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
5638 namelen = strlen(cubemapname) - 2;
5639 memmove(cubemapname, cubemapname + 1, namelen);
5640 cubemapname[namelen] = '\0';
5644 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);
5647 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5655 Con_Printf("invalid rtlights file \"%s\"\n", name);
5656 Mem_Free(lightsstring);
5660 void R_Shadow_SaveWorldLights(void)
5664 size_t bufchars, bufmaxchars;
5666 char name[MAX_QPATH];
5667 char line[MAX_INPUTLINE];
5668 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
5669 // I hate lines which are 3 times my screen size :( --blub
5672 if (cl.worldmodel == NULL)
5674 Con_Print("No map loaded.\n");
5677 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
5678 bufchars = bufmaxchars = 0;
5680 for (lightindex = 0;lightindex < range;lightindex++)
5682 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5685 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
5686 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);
5687 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
5688 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]);
5690 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);
5691 if (bufchars + strlen(line) > bufmaxchars)
5693 bufmaxchars = bufchars + strlen(line) + 2048;
5695 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
5699 memcpy(buf, oldbuf, bufchars);
5705 memcpy(buf + bufchars, line, strlen(line));
5706 bufchars += strlen(line);
5710 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
5715 void R_Shadow_LoadLightsFile(void)
5718 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
5719 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
5720 if (cl.worldmodel == NULL)
5722 Con_Print("No map loaded.\n");
5725 dpsnprintf(name, sizeof(name), "%s.lights", cl.worldnamenoextension);
5726 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5734 while (*s && *s != '\n' && *s != '\r')
5740 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);
5744 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);
5747 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
5748 radius = bound(15, radius, 4096);
5749 VectorScale(color, (2.0f / (8388608.0f)), color);
5750 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5758 Con_Printf("invalid lights file \"%s\"\n", name);
5759 Mem_Free(lightsstring);
5763 // tyrlite/hmap2 light types in the delay field
5764 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
5766 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
5778 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
5779 char key[256], value[MAX_INPUTLINE];
5782 if (cl.worldmodel == NULL)
5784 Con_Print("No map loaded.\n");
5787 // try to load a .ent file first
5788 dpsnprintf(key, sizeof(key), "%s.ent", cl.worldnamenoextension);
5789 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
5790 // and if that is not found, fall back to the bsp file entity string
5792 data = cl.worldmodel->brush.entities;
5795 for (entnum = 0;COM_ParseToken_Simple(&data, false, false, true) && com_token[0] == '{';entnum++)
5797 type = LIGHTTYPE_MINUSX;
5798 origin[0] = origin[1] = origin[2] = 0;
5799 originhack[0] = originhack[1] = originhack[2] = 0;
5800 angles[0] = angles[1] = angles[2] = 0;
5801 color[0] = color[1] = color[2] = 1;
5802 light[0] = light[1] = light[2] = 1;light[3] = 300;
5803 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
5813 if (!COM_ParseToken_Simple(&data, false, false, true))
5815 if (com_token[0] == '}')
5816 break; // end of entity
5817 if (com_token[0] == '_')
5818 strlcpy(key, com_token + 1, sizeof(key));
5820 strlcpy(key, com_token, sizeof(key));
5821 while (key[strlen(key)-1] == ' ') // remove trailing spaces
5822 key[strlen(key)-1] = 0;
5823 if (!COM_ParseToken_Simple(&data, false, false, true))
5825 strlcpy(value, com_token, sizeof(value));
5827 // now that we have the key pair worked out...
5828 if (!strcmp("light", key))
5830 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5834 light[0] = vec[0] * (1.0f / 256.0f);
5835 light[1] = vec[0] * (1.0f / 256.0f);
5836 light[2] = vec[0] * (1.0f / 256.0f);
5842 light[0] = vec[0] * (1.0f / 255.0f);
5843 light[1] = vec[1] * (1.0f / 255.0f);
5844 light[2] = vec[2] * (1.0f / 255.0f);
5848 else if (!strcmp("delay", key))
5850 else if (!strcmp("origin", key))
5851 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5852 else if (!strcmp("angle", key))
5853 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5854 else if (!strcmp("angles", key))
5855 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5856 else if (!strcmp("color", key))
5857 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5858 else if (!strcmp("wait", key))
5859 fadescale = atof(value);
5860 else if (!strcmp("classname", key))
5862 if (!strncmp(value, "light", 5))
5865 if (!strcmp(value, "light_fluoro"))
5870 overridecolor[0] = 1;
5871 overridecolor[1] = 1;
5872 overridecolor[2] = 1;
5874 if (!strcmp(value, "light_fluorospark"))
5879 overridecolor[0] = 1;
5880 overridecolor[1] = 1;
5881 overridecolor[2] = 1;
5883 if (!strcmp(value, "light_globe"))
5888 overridecolor[0] = 1;
5889 overridecolor[1] = 0.8;
5890 overridecolor[2] = 0.4;
5892 if (!strcmp(value, "light_flame_large_yellow"))
5897 overridecolor[0] = 1;
5898 overridecolor[1] = 0.5;
5899 overridecolor[2] = 0.1;
5901 if (!strcmp(value, "light_flame_small_yellow"))
5906 overridecolor[0] = 1;
5907 overridecolor[1] = 0.5;
5908 overridecolor[2] = 0.1;
5910 if (!strcmp(value, "light_torch_small_white"))
5915 overridecolor[0] = 1;
5916 overridecolor[1] = 0.5;
5917 overridecolor[2] = 0.1;
5919 if (!strcmp(value, "light_torch_small_walltorch"))
5924 overridecolor[0] = 1;
5925 overridecolor[1] = 0.5;
5926 overridecolor[2] = 0.1;
5930 else if (!strcmp("style", key))
5931 style = atoi(value);
5932 else if (!strcmp("skin", key))
5933 skin = (int)atof(value);
5934 else if (!strcmp("pflags", key))
5935 pflags = (int)atof(value);
5936 //else if (!strcmp("effects", key))
5937 // effects = (int)atof(value);
5938 else if (cl.worldmodel->type == mod_brushq3)
5940 if (!strcmp("scale", key))
5941 lightscale = atof(value);
5942 if (!strcmp("fade", key))
5943 fadescale = atof(value);
5948 if (lightscale <= 0)
5952 if (color[0] == color[1] && color[0] == color[2])
5954 color[0] *= overridecolor[0];
5955 color[1] *= overridecolor[1];
5956 color[2] *= overridecolor[2];
5958 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5959 color[0] = color[0] * light[0];
5960 color[1] = color[1] * light[1];
5961 color[2] = color[2] * light[2];
5964 case LIGHTTYPE_MINUSX:
5966 case LIGHTTYPE_RECIPX:
5968 VectorScale(color, (1.0f / 16.0f), color);
5970 case LIGHTTYPE_RECIPXX:
5972 VectorScale(color, (1.0f / 16.0f), color);
5975 case LIGHTTYPE_NONE:
5979 case LIGHTTYPE_MINUSXX:
5982 VectorAdd(origin, originhack, origin);
5984 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);
5987 Mem_Free(entfiledata);
5991 static void R_Shadow_SetCursorLocationForView(void)
5994 vec3_t dest, endpos;
5996 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5997 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, collision_extendmovelength.value, true, false, NULL, false, true);
5998 if (trace.fraction < 1)
6000 dist = trace.fraction * r_editlights_cursordistance.value;
6001 push = r_editlights_cursorpushback.value;
6005 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
6006 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
6010 VectorClear( endpos );
6012 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
6013 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
6014 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
6017 void R_Shadow_UpdateWorldLightSelection(void)
6019 if (r_editlights.integer)
6021 R_Shadow_SetCursorLocationForView();
6022 R_Shadow_SelectLightInView();
6025 R_Shadow_SelectLight(NULL);
6028 static void R_Shadow_EditLights_Clear_f(void)
6030 R_Shadow_ClearWorldLights();
6033 void R_Shadow_EditLights_Reload_f(void)
6037 strlcpy(r_shadow_mapname, cl.worldname, sizeof(r_shadow_mapname));
6038 R_Shadow_ClearWorldLights();
6039 R_Shadow_LoadWorldLights();
6040 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
6042 R_Shadow_LoadLightsFile();
6043 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
6044 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
6048 static void R_Shadow_EditLights_Save_f(void)
6052 R_Shadow_SaveWorldLights();
6055 static void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
6057 R_Shadow_ClearWorldLights();
6058 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
6061 static void R_Shadow_EditLights_ImportLightsFile_f(void)
6063 R_Shadow_ClearWorldLights();
6064 R_Shadow_LoadLightsFile();
6067 static void R_Shadow_EditLights_Spawn_f(void)
6070 if (!r_editlights.integer)
6072 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6075 if (Cmd_Argc() != 1)
6077 Con_Print("r_editlights_spawn does not take parameters\n");
6080 color[0] = color[1] = color[2] = 1;
6081 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
6084 static void R_Shadow_EditLights_Edit_f(void)
6086 vec3_t origin, angles, color;
6087 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
6088 int style, shadows, flags, normalmode, realtimemode;
6089 char cubemapname[MAX_INPUTLINE];
6090 if (!r_editlights.integer)
6092 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6095 if (!r_shadow_selectedlight)
6097 Con_Print("No selected light.\n");
6100 VectorCopy(r_shadow_selectedlight->origin, origin);
6101 VectorCopy(r_shadow_selectedlight->angles, angles);
6102 VectorCopy(r_shadow_selectedlight->color, color);
6103 radius = r_shadow_selectedlight->radius;
6104 style = r_shadow_selectedlight->style;
6105 if (r_shadow_selectedlight->cubemapname)
6106 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
6109 shadows = r_shadow_selectedlight->shadow;
6110 corona = r_shadow_selectedlight->corona;
6111 coronasizescale = r_shadow_selectedlight->coronasizescale;
6112 ambientscale = r_shadow_selectedlight->ambientscale;
6113 diffusescale = r_shadow_selectedlight->diffusescale;
6114 specularscale = r_shadow_selectedlight->specularscale;
6115 flags = r_shadow_selectedlight->flags;
6116 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
6117 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
6118 if (!strcmp(Cmd_Argv(1), "origin"))
6120 if (Cmd_Argc() != 5)
6122 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6125 origin[0] = atof(Cmd_Argv(2));
6126 origin[1] = atof(Cmd_Argv(3));
6127 origin[2] = atof(Cmd_Argv(4));
6129 else if (!strcmp(Cmd_Argv(1), "originscale"))
6131 if (Cmd_Argc() != 5)
6133 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6136 origin[0] *= atof(Cmd_Argv(2));
6137 origin[1] *= atof(Cmd_Argv(3));
6138 origin[2] *= atof(Cmd_Argv(4));
6140 else if (!strcmp(Cmd_Argv(1), "originx"))
6142 if (Cmd_Argc() != 3)
6144 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6147 origin[0] = atof(Cmd_Argv(2));
6149 else if (!strcmp(Cmd_Argv(1), "originy"))
6151 if (Cmd_Argc() != 3)
6153 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6156 origin[1] = atof(Cmd_Argv(2));
6158 else if (!strcmp(Cmd_Argv(1), "originz"))
6160 if (Cmd_Argc() != 3)
6162 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6165 origin[2] = atof(Cmd_Argv(2));
6167 else if (!strcmp(Cmd_Argv(1), "move"))
6169 if (Cmd_Argc() != 5)
6171 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6174 origin[0] += atof(Cmd_Argv(2));
6175 origin[1] += atof(Cmd_Argv(3));
6176 origin[2] += atof(Cmd_Argv(4));
6178 else if (!strcmp(Cmd_Argv(1), "movex"))
6180 if (Cmd_Argc() != 3)
6182 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6185 origin[0] += atof(Cmd_Argv(2));
6187 else if (!strcmp(Cmd_Argv(1), "movey"))
6189 if (Cmd_Argc() != 3)
6191 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6194 origin[1] += atof(Cmd_Argv(2));
6196 else if (!strcmp(Cmd_Argv(1), "movez"))
6198 if (Cmd_Argc() != 3)
6200 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6203 origin[2] += atof(Cmd_Argv(2));
6205 else if (!strcmp(Cmd_Argv(1), "angles"))
6207 if (Cmd_Argc() != 5)
6209 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
6212 angles[0] = atof(Cmd_Argv(2));
6213 angles[1] = atof(Cmd_Argv(3));
6214 angles[2] = atof(Cmd_Argv(4));
6216 else if (!strcmp(Cmd_Argv(1), "anglesx"))
6218 if (Cmd_Argc() != 3)
6220 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6223 angles[0] = atof(Cmd_Argv(2));
6225 else if (!strcmp(Cmd_Argv(1), "anglesy"))
6227 if (Cmd_Argc() != 3)
6229 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6232 angles[1] = atof(Cmd_Argv(2));
6234 else if (!strcmp(Cmd_Argv(1), "anglesz"))
6236 if (Cmd_Argc() != 3)
6238 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6241 angles[2] = atof(Cmd_Argv(2));
6243 else if (!strcmp(Cmd_Argv(1), "color"))
6245 if (Cmd_Argc() != 5)
6247 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
6250 color[0] = atof(Cmd_Argv(2));
6251 color[1] = atof(Cmd_Argv(3));
6252 color[2] = atof(Cmd_Argv(4));
6254 else if (!strcmp(Cmd_Argv(1), "radius"))
6256 if (Cmd_Argc() != 3)
6258 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6261 radius = atof(Cmd_Argv(2));
6263 else if (!strcmp(Cmd_Argv(1), "colorscale"))
6265 if (Cmd_Argc() == 3)
6267 double scale = atof(Cmd_Argv(2));
6274 if (Cmd_Argc() != 5)
6276 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
6279 color[0] *= atof(Cmd_Argv(2));
6280 color[1] *= atof(Cmd_Argv(3));
6281 color[2] *= atof(Cmd_Argv(4));
6284 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
6286 if (Cmd_Argc() != 3)
6288 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6291 radius *= atof(Cmd_Argv(2));
6293 else if (!strcmp(Cmd_Argv(1), "style"))
6295 if (Cmd_Argc() != 3)
6297 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6300 style = atoi(Cmd_Argv(2));
6302 else if (!strcmp(Cmd_Argv(1), "cubemap"))
6306 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6309 if (Cmd_Argc() == 3)
6310 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
6314 else if (!strcmp(Cmd_Argv(1), "shadows"))
6316 if (Cmd_Argc() != 3)
6318 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6321 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
6323 else if (!strcmp(Cmd_Argv(1), "corona"))
6325 if (Cmd_Argc() != 3)
6327 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6330 corona = atof(Cmd_Argv(2));
6332 else if (!strcmp(Cmd_Argv(1), "coronasize"))
6334 if (Cmd_Argc() != 3)
6336 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6339 coronasizescale = atof(Cmd_Argv(2));
6341 else if (!strcmp(Cmd_Argv(1), "ambient"))
6343 if (Cmd_Argc() != 3)
6345 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6348 ambientscale = atof(Cmd_Argv(2));
6350 else if (!strcmp(Cmd_Argv(1), "diffuse"))
6352 if (Cmd_Argc() != 3)
6354 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6357 diffusescale = atof(Cmd_Argv(2));
6359 else if (!strcmp(Cmd_Argv(1), "specular"))
6361 if (Cmd_Argc() != 3)
6363 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6366 specularscale = atof(Cmd_Argv(2));
6368 else if (!strcmp(Cmd_Argv(1), "normalmode"))
6370 if (Cmd_Argc() != 3)
6372 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6375 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
6377 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
6379 if (Cmd_Argc() != 3)
6381 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6384 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
6388 Con_Print("usage: r_editlights_edit [property] [value]\n");
6389 Con_Print("Selected light's properties:\n");
6390 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
6391 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
6392 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
6393 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
6394 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
6395 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
6396 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
6397 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
6398 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
6399 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
6400 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
6401 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
6402 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
6403 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
6406 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
6407 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
6410 static void R_Shadow_EditLights_EditAll_f(void)
6413 dlight_t *light, *oldselected;
6416 if (!r_editlights.integer)
6418 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
6422 oldselected = r_shadow_selectedlight;
6423 // EditLights doesn't seem to have a "remove" command or something so:
6424 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6425 for (lightindex = 0;lightindex < range;lightindex++)
6427 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6430 R_Shadow_SelectLight(light);
6431 R_Shadow_EditLights_Edit_f();
6433 // return to old selected (to not mess editing once selection is locked)
6434 R_Shadow_SelectLight(oldselected);
6437 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
6439 int lightnumber, lightcount;
6440 size_t lightindex, range;
6445 if (!r_editlights.integer)
6448 // update cvars so QC can query them
6449 if (r_shadow_selectedlight)
6451 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
6452 Cvar_SetQuick(&r_editlights_current_origin, temp);
6453 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
6454 Cvar_SetQuick(&r_editlights_current_angles, temp);
6455 dpsnprintf(temp, sizeof(temp), "%f %f %f", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
6456 Cvar_SetQuick(&r_editlights_current_color, temp);
6457 Cvar_SetValueQuick(&r_editlights_current_radius, r_shadow_selectedlight->radius);
6458 Cvar_SetValueQuick(&r_editlights_current_corona, r_shadow_selectedlight->corona);
6459 Cvar_SetValueQuick(&r_editlights_current_coronasize, r_shadow_selectedlight->coronasizescale);
6460 Cvar_SetValueQuick(&r_editlights_current_style, r_shadow_selectedlight->style);
6461 Cvar_SetValueQuick(&r_editlights_current_shadows, r_shadow_selectedlight->shadow);
6462 Cvar_SetQuick(&r_editlights_current_cubemap, r_shadow_selectedlight->cubemapname);
6463 Cvar_SetValueQuick(&r_editlights_current_ambient, r_shadow_selectedlight->ambientscale);
6464 Cvar_SetValueQuick(&r_editlights_current_diffuse, r_shadow_selectedlight->diffusescale);
6465 Cvar_SetValueQuick(&r_editlights_current_specular, r_shadow_selectedlight->specularscale);
6466 Cvar_SetValueQuick(&r_editlights_current_normalmode, (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? 1 : 0);
6467 Cvar_SetValueQuick(&r_editlights_current_realtimemode, (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? 1 : 0);
6470 // draw properties on screen
6471 if (!r_editlights_drawproperties.integer)
6473 x = vid_conwidth.value - 240;
6475 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
6478 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6479 for (lightindex = 0;lightindex < range;lightindex++)
6481 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6484 if (light == r_shadow_selectedlight)
6485 lightnumber = (int)lightindex;
6488 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;
6489 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;
6491 if (r_shadow_selectedlight == NULL)
6493 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;
6494 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;
6495 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;
6496 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;
6497 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;
6498 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;
6499 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;
6500 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;
6501 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;
6502 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;
6503 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;
6504 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;
6505 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;
6506 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;
6507 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;
6510 static void R_Shadow_EditLights_ToggleShadow_f(void)
6512 if (!r_editlights.integer)
6514 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6517 if (!r_shadow_selectedlight)
6519 Con_Print("No selected light.\n");
6522 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);
6525 static void R_Shadow_EditLights_ToggleCorona_f(void)
6527 if (!r_editlights.integer)
6529 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6532 if (!r_shadow_selectedlight)
6534 Con_Print("No selected light.\n");
6537 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);
6540 static void R_Shadow_EditLights_Remove_f(void)
6542 if (!r_editlights.integer)
6544 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
6547 if (!r_shadow_selectedlight)
6549 Con_Print("No selected light.\n");
6552 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
6553 r_shadow_selectedlight = NULL;
6556 static void R_Shadow_EditLights_Help_f(void)
6559 "Documentation on r_editlights system:\n"
6561 "r_editlights : enable/disable editing mode\n"
6562 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
6563 "r_editlights_cursorpushback : push back cursor this far from surface\n"
6564 "r_editlights_cursorpushoff : push cursor off surface this far\n"
6565 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
6566 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
6568 "r_editlights_help : this help\n"
6569 "r_editlights_clear : remove all lights\n"
6570 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
6571 "r_editlights_lock : lock selection to current light, if already locked - unlock\n"
6572 "r_editlights_save : save to .rtlights file\n"
6573 "r_editlights_spawn : create a light with default settings\n"
6574 "r_editlights_edit command : edit selected light - more documentation below\n"
6575 "r_editlights_remove : remove selected light\n"
6576 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
6577 "r_editlights_importlightentitiesfrommap : reload light entities\n"
6578 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
6580 "origin x y z : set light location\n"
6581 "originx x: set x component of light location\n"
6582 "originy y: set y component of light location\n"
6583 "originz z: set z component of light location\n"
6584 "move x y z : adjust light location\n"
6585 "movex x: adjust x component of light location\n"
6586 "movey y: adjust y component of light location\n"
6587 "movez z: adjust z component of light location\n"
6588 "angles x y z : set light angles\n"
6589 "anglesx x: set x component of light angles\n"
6590 "anglesy y: set y component of light angles\n"
6591 "anglesz z: set z component of light angles\n"
6592 "color r g b : set color of light (can be brighter than 1 1 1)\n"
6593 "radius radius : set radius (size) of light\n"
6594 "colorscale grey : multiply color of light (1 does nothing)\n"
6595 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
6596 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
6597 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
6598 "originscale x y z : multiply origin of light (1 1 1 does nothing)\n"
6599 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
6600 "cubemap basename : set filter cubemap of light\n"
6601 "shadows 1/0 : turn on/off shadows\n"
6602 "corona n : set corona intensity\n"
6603 "coronasize n : set corona size (0-1)\n"
6604 "ambient n : set ambient intensity (0-1)\n"
6605 "diffuse n : set diffuse intensity (0-1)\n"
6606 "specular n : set specular intensity (0-1)\n"
6607 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
6608 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
6609 "<nothing> : print light properties to console\n"
6613 static void R_Shadow_EditLights_CopyInfo_f(void)
6615 if (!r_editlights.integer)
6617 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
6620 if (!r_shadow_selectedlight)
6622 Con_Print("No selected light.\n");
6625 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
6626 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
6627 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
6628 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
6629 if (r_shadow_selectedlight->cubemapname)
6630 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
6632 r_shadow_bufferlight.cubemapname[0] = 0;
6633 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
6634 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
6635 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
6636 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
6637 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
6638 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
6639 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
6642 static void R_Shadow_EditLights_PasteInfo_f(void)
6644 if (!r_editlights.integer)
6646 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
6649 if (!r_shadow_selectedlight)
6651 Con_Print("No selected light.\n");
6654 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);
6657 static void R_Shadow_EditLights_Lock_f(void)
6659 if (!r_editlights.integer)
6661 Con_Print("Cannot lock on light when not in editing mode. Set r_editlights to 1.\n");
6664 if (r_editlights_lockcursor)
6666 r_editlights_lockcursor = false;
6669 if (!r_shadow_selectedlight)
6671 Con_Print("No selected light to lock on.\n");
6674 r_editlights_lockcursor = true;
6677 static void R_Shadow_EditLights_Init(void)
6679 Cvar_RegisterVariable(&r_editlights);
6680 Cvar_RegisterVariable(&r_editlights_cursordistance);
6681 Cvar_RegisterVariable(&r_editlights_cursorpushback);
6682 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
6683 Cvar_RegisterVariable(&r_editlights_cursorgrid);
6684 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
6685 Cvar_RegisterVariable(&r_editlights_drawproperties);
6686 Cvar_RegisterVariable(&r_editlights_current_origin);
6687 Cvar_RegisterVariable(&r_editlights_current_angles);
6688 Cvar_RegisterVariable(&r_editlights_current_color);
6689 Cvar_RegisterVariable(&r_editlights_current_radius);
6690 Cvar_RegisterVariable(&r_editlights_current_corona);
6691 Cvar_RegisterVariable(&r_editlights_current_coronasize);
6692 Cvar_RegisterVariable(&r_editlights_current_style);
6693 Cvar_RegisterVariable(&r_editlights_current_shadows);
6694 Cvar_RegisterVariable(&r_editlights_current_cubemap);
6695 Cvar_RegisterVariable(&r_editlights_current_ambient);
6696 Cvar_RegisterVariable(&r_editlights_current_diffuse);
6697 Cvar_RegisterVariable(&r_editlights_current_specular);
6698 Cvar_RegisterVariable(&r_editlights_current_normalmode);
6699 Cvar_RegisterVariable(&r_editlights_current_realtimemode);
6700 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
6701 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
6702 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)");
6703 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
6704 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
6705 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
6706 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)");
6707 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
6708 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
6709 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
6710 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
6711 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
6712 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
6713 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)");
6714 Cmd_AddCommand("r_editlights_lock", R_Shadow_EditLights_Lock_f, "lock selection to current light, if already locked - unlock");
6720 =============================================================================
6724 =============================================================================
6727 void R_LightPoint(float *color, const vec3_t p, const int flags)
6729 int i, numlights, flag;
6730 float f, relativepoint[3], dist, dist2, lightradius2;
6735 if (r_fullbright.integer)
6737 VectorSet(color, 1, 1, 1);
6743 if (flags & LP_LIGHTMAP)
6745 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
6747 VectorClear(diffuse);
6748 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, color, diffuse, n);
6749 VectorAdd(color, diffuse, color);
6752 VectorSet(color, 1, 1, 1);
6753 color[0] += r_refdef.scene.ambient;
6754 color[1] += r_refdef.scene.ambient;
6755 color[2] += r_refdef.scene.ambient;
6758 if (flags & LP_RTWORLD)
6760 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
6761 numlights = (int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
6762 for (i = 0; i < numlights; i++)
6764 dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
6767 light = &dlight->rtlight;
6768 if (!(light->flags & flag))
6771 lightradius2 = light->radius * light->radius;
6772 VectorSubtract(light->shadoworigin, p, relativepoint);
6773 dist2 = VectorLength2(relativepoint);
6774 if (dist2 >= lightradius2)
6776 dist = sqrt(dist2) / light->radius;
6777 f = dist < 1 ? (r_shadow_lightintensityscale.value * ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist))) : 0;
6780 // todo: add to both ambient and diffuse
6781 if (!light->shadow || CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, collision_extendmovelength.value, true, false, NULL, false, true).fraction == 1)
6782 VectorMA(color, f, light->currentcolor, color);
6785 if (flags & LP_DYNLIGHT)
6788 for (i = 0;i < r_refdef.scene.numlights;i++)
6790 light = r_refdef.scene.lights[i];
6792 lightradius2 = light->radius * light->radius;
6793 VectorSubtract(light->shadoworigin, p, relativepoint);
6794 dist2 = VectorLength2(relativepoint);
6795 if (dist2 >= lightradius2)
6797 dist = sqrt(dist2) / light->radius;
6798 f = dist < 1 ? (r_shadow_lightintensityscale.value * ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist))) : 0;
6801 // todo: add to both ambient and diffuse
6802 if (!light->shadow || CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, collision_extendmovelength.value, true, false, NULL, false, true).fraction == 1)
6803 VectorMA(color, f, light->color, color);
6808 void R_CompleteLightPoint(vec3_t ambient, vec3_t diffuse, vec3_t lightdir, const vec3_t p, const int flags)
6810 int i, numlights, flag;
6813 float relativepoint[3];
6822 if (r_fullbright.integer)
6824 VectorSet(ambient, 1, 1, 1);
6825 VectorClear(diffuse);
6826 VectorClear(lightdir);
6830 if (flags == LP_LIGHTMAP)
6832 VectorSet(ambient, r_refdef.scene.ambient, r_refdef.scene.ambient, r_refdef.scene.ambient);
6833 VectorClear(diffuse);
6834 VectorClear(lightdir);
6835 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
6836 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambient, diffuse, lightdir);
6838 VectorSet(ambient, 1, 1, 1);
6842 memset(sample, 0, sizeof(sample));
6843 VectorSet(sample, r_refdef.scene.ambient, r_refdef.scene.ambient, r_refdef.scene.ambient);
6845 if ((flags & LP_LIGHTMAP) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->lit && r_refdef.scene.worldmodel->brush.LightPoint)
6848 VectorClear(tempambient);
6850 VectorClear(relativepoint);
6851 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, tempambient, color, relativepoint);
6852 VectorScale(tempambient, r_refdef.lightmapintensity, tempambient);
6853 VectorScale(color, r_refdef.lightmapintensity, color);
6854 VectorAdd(sample, tempambient, sample);
6855 VectorMA(sample , 0.5f , color, sample );
6856 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
6857 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
6858 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
6859 // calculate a weighted average light direction as well
6860 intensity = VectorLength(color);
6861 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
6864 if (flags & LP_RTWORLD)
6866 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
6867 numlights = (int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
6868 for (i = 0; i < numlights; i++)
6870 dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
6873 light = &dlight->rtlight;
6874 if (!(light->flags & flag))
6877 lightradius2 = light->radius * light->radius;
6878 VectorSubtract(light->shadoworigin, p, relativepoint);
6879 dist2 = VectorLength2(relativepoint);
6880 if (dist2 >= lightradius2)
6882 dist = sqrt(dist2) / light->radius;
6883 intensity = min(1.0f, (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) * r_shadow_lightintensityscale.value;
6884 if (intensity <= 0.0f)
6886 if (light->shadow && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, collision_extendmovelength.value, true, false, NULL, false, true).fraction < 1)
6888 // scale down intensity to add to both ambient and diffuse
6889 //intensity *= 0.5f;
6890 VectorNormalize(relativepoint);
6891 VectorScale(light->currentcolor, intensity, color);
6892 VectorMA(sample , 0.5f , color, sample );
6893 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
6894 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
6895 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
6896 // calculate a weighted average light direction as well
6897 intensity *= VectorLength(color);
6898 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
6900 // FIXME: sample bouncegrid too!
6903 if (flags & LP_DYNLIGHT)
6906 for (i = 0;i < r_refdef.scene.numlights;i++)
6908 light = r_refdef.scene.lights[i];
6910 lightradius2 = light->radius * light->radius;
6911 VectorSubtract(light->shadoworigin, p, relativepoint);
6912 dist2 = VectorLength2(relativepoint);
6913 if (dist2 >= lightradius2)
6915 dist = sqrt(dist2) / light->radius;
6916 intensity = (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist) * r_shadow_lightintensityscale.value;
6917 if (intensity <= 0.0f)
6919 if (light->shadow && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, collision_extendmovelength.value, true, false, NULL, false, true).fraction < 1)
6921 // scale down intensity to add to both ambient and diffuse
6922 //intensity *= 0.5f;
6923 VectorNormalize(relativepoint);
6924 VectorScale(light->currentcolor, intensity, color);
6925 VectorMA(sample , 0.5f , color, sample );
6926 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
6927 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
6928 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
6929 // calculate a weighted average light direction as well
6930 intensity *= VectorLength(color);
6931 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
6935 // calculate the direction we'll use to reduce the sample to a directional light source
6936 VectorCopy(sample + 12, dir);
6937 //VectorSet(dir, sample[3] + sample[4] + sample[5], sample[6] + sample[7] + sample[8], sample[9] + sample[10] + sample[11]);
6938 VectorNormalize(dir);
6939 // extract the diffuse color along the chosen direction and scale it
6940 diffuse[0] = (dir[0]*sample[3] + dir[1]*sample[6] + dir[2]*sample[ 9] + sample[ 0]);
6941 diffuse[1] = (dir[0]*sample[4] + dir[1]*sample[7] + dir[2]*sample[10] + sample[ 1]);
6942 diffuse[2] = (dir[0]*sample[5] + dir[1]*sample[8] + dir[2]*sample[11] + sample[ 2]);
6943 // subtract some of diffuse from ambient
6944 VectorMA(sample, -0.333f, diffuse, ambient);
6945 // store the normalized lightdir
6946 VectorCopy(dir, lightdir);