3 Terminology: Stencil Shadow Volume (sometimes called Stencil Shadows)
4 An extrusion of the lit faces, beginning at the original geometry and ending
5 further from the light source than the original geometry (presumably at least
6 as far as the light's radius, if the light has a radius at all), capped at
7 both front and back to avoid any problems (extrusion from dark faces also
8 works but has a different set of problems)
10 This is normally rendered using Carmack's Reverse technique, in which
11 backfaces behind zbuffer (zfail) increment the stencil, and frontfaces behind
12 zbuffer (zfail) decrement the stencil, the result is a stencil value of zero
13 where shadows did not intersect the visible geometry, suitable as a stencil
14 mask for rendering lighting everywhere but shadow.
16 In our case to hopefully avoid the Creative Labs patent, we draw the backfaces
17 as decrement and the frontfaces as increment, and we redefine the DepthFunc to
18 GL_LESS (the patent uses GL_GEQUAL) which causes zfail when behind surfaces
19 and zpass when infront (the patent draws where zpass with a GL_GEQUAL test),
20 additionally we clear stencil to 128 to avoid the need for the unclamped
21 incr/decr extension (not related to patent).
24 This algorithm may be covered by Creative's patent (US Patent #6384822),
25 however that patent is quite specific about increment on backfaces and
26 decrement on frontfaces where zpass with GL_GEQUAL depth test, which is
27 opposite this implementation and partially opposite Carmack's Reverse paper
28 (which uses GL_LESS, but increments on backfaces and decrements on frontfaces).
32 Terminology: Stencil Light Volume (sometimes called Light Volumes)
33 Similar to a Stencil Shadow Volume, but inverted; rather than containing the
34 areas in shadow it contains the areas in light, this can only be built
35 quickly for certain limited cases (such as portal visibility from a point),
36 but is quite useful for some effects (sunlight coming from sky polygons is
37 one possible example, translucent occluders is another example).
41 Terminology: Optimized Stencil Shadow Volume
42 A Stencil Shadow Volume that has been processed sufficiently to ensure it has
43 no duplicate coverage of areas (no need to shadow an area twice), often this
44 greatly improves performance but is an operation too costly to use on moving
45 lights (however completely optimal Stencil Light Volumes can be constructed
50 Terminology: Per Pixel Lighting (sometimes abbreviated PPL)
51 Per pixel evaluation of lighting equations, at a bare minimum this involves
52 DOT3 shading of diffuse lighting (per pixel dotproduct of negated incidence
53 vector and surface normal, using a texture of the surface bumps, called a
54 NormalMap) if supported by hardware; in our case there is support for cards
55 which are incapable of DOT3, the quality is quite poor however. Additionally
56 it is desirable to have specular evaluation per pixel, per vertex
57 normalization of specular halfangle vectors causes noticable distortion but
58 is unavoidable on hardware without GL_ARB_fragment_program or
59 GL_ARB_fragment_shader.
63 Terminology: Normalization CubeMap
64 A cubemap containing normalized dot3-encoded (vectors of length 1 or less
65 encoded as RGB colors) for any possible direction, this technique allows per
66 pixel calculation of incidence vector for per pixel lighting purposes, which
67 would not otherwise be possible per pixel without GL_ARB_fragment_program or
68 GL_ARB_fragment_shader.
72 Terminology: 2D+1D Attenuation Texturing
73 A very crude approximation of light attenuation with distance which results
74 in cylindrical light shapes which fade vertically as a streak (some games
75 such as Doom3 allow this to be rotated to be less noticable in specific
76 cases), the technique is simply modulating lighting by two 2D textures (which
77 can be the same) on different axes of projection (XY and Z, typically), this
78 is the second best technique available without 3D Attenuation Texturing,
79 GL_ARB_fragment_program or GL_ARB_fragment_shader technology.
83 Terminology: 2D+1D Inverse Attenuation Texturing
84 A clever method described in papers on the Abducted engine, this has a squared
85 distance texture (bright on the outside, black in the middle), which is used
86 twice using GL_ADD blending, the result of this is used in an inverse modulate
87 (GL_ONE_MINUS_DST_ALPHA, GL_ZERO) to implement the equation
88 lighting*=(1-((X*X+Y*Y)+(Z*Z))) which is spherical (unlike 2D+1D attenuation
93 Terminology: 3D Attenuation Texturing
94 A slightly crude approximation of light attenuation with distance, its flaws
95 are limited radius and resolution (performance tradeoffs).
99 Terminology: 3D Attenuation-Normalization Texturing
100 A 3D Attenuation Texture merged with a Normalization CubeMap, by making the
101 vectors shorter the lighting becomes darker, a very effective optimization of
102 diffuse lighting if 3D Attenuation Textures are already used.
106 Terminology: Light Cubemap Filtering
107 A technique for modeling non-uniform light distribution according to
108 direction, for example a lantern may use a cubemap to describe the light
109 emission pattern of the cage around the lantern (as well as soot buildup
110 discoloring the light in certain areas), often also used for softened grate
111 shadows and light shining through a stained glass window (done crudely by
112 texturing the lighting with a cubemap), another good example would be a disco
113 light. This technique is used heavily in many games (Doom3 does not support
118 Terminology: Light Projection Filtering
119 A technique for modeling shadowing of light passing through translucent
120 surfaces, allowing stained glass windows and other effects to be done more
121 elegantly than possible with Light Cubemap Filtering by applying an occluder
122 texture to the lighting combined with a stencil light volume to limit the lit
123 area, this technique is used by Doom3 for spotlights and flashlights, among
124 other things, this can also be used more generally to render light passing
125 through multiple translucent occluders in a scene (using a light volume to
126 describe the area beyond the occluder, and thus mask off rendering of all
131 Terminology: Doom3 Lighting
132 A combination of Stencil Shadow Volume, Per Pixel Lighting, Normalization
133 CubeMap, 2D+1D Attenuation Texturing, and Light Projection Filtering, as
134 demonstrated by the game Doom3.
137 #include "quakedef.h"
138 #include "r_shadow.h"
139 #include "cl_collision.h"
142 #include "dpsoftrast.h"
146 extern LPDIRECT3DDEVICE9 vid_d3d9dev;
149 extern void R_Shadow_EditLights_Init(void);
151 typedef enum r_shadow_rendermode_e
153 R_SHADOW_RENDERMODE_NONE,
154 R_SHADOW_RENDERMODE_ZPASS_STENCIL,
155 R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL,
156 R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE,
157 R_SHADOW_RENDERMODE_ZFAIL_STENCIL,
158 R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL,
159 R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE,
160 R_SHADOW_RENDERMODE_LIGHT_VERTEX,
161 R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN,
162 R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN,
163 R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN,
164 R_SHADOW_RENDERMODE_LIGHT_GLSL,
165 R_SHADOW_RENDERMODE_VISIBLEVOLUMES,
166 R_SHADOW_RENDERMODE_VISIBLELIGHTING,
167 R_SHADOW_RENDERMODE_SHADOWMAP2D
169 r_shadow_rendermode_t;
171 typedef enum r_shadow_shadowmode_e
173 R_SHADOW_SHADOWMODE_STENCIL,
174 R_SHADOW_SHADOWMODE_SHADOWMAP2D
176 r_shadow_shadowmode_t;
178 r_shadow_rendermode_t r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
179 r_shadow_rendermode_t r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_NONE;
180 r_shadow_rendermode_t r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_NONE;
181 r_shadow_rendermode_t r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_NONE;
182 qboolean r_shadow_usingshadowmap2d;
183 qboolean r_shadow_usingshadowmaportho;
184 int r_shadow_shadowmapside;
185 float r_shadow_shadowmap_texturescale[2];
186 float r_shadow_shadowmap_parameters[4];
188 int r_shadow_drawbuffer;
189 int r_shadow_readbuffer;
191 int r_shadow_cullface_front, r_shadow_cullface_back;
192 GLuint r_shadow_fbo2d;
193 r_shadow_shadowmode_t r_shadow_shadowmode;
194 int r_shadow_shadowmapfilterquality;
195 int r_shadow_shadowmapdepthbits;
196 int r_shadow_shadowmapmaxsize;
197 qboolean r_shadow_shadowmapvsdct;
198 qboolean r_shadow_shadowmapsampler;
199 int r_shadow_shadowmappcf;
200 int r_shadow_shadowmapborder;
201 matrix4x4_t r_shadow_shadowmapmatrix;
202 int r_shadow_lightscissor[4];
203 qboolean r_shadow_usingdeferredprepass;
205 int maxshadowtriangles;
208 int maxshadowvertices;
209 float *shadowvertex3f;
219 unsigned char *shadowsides;
220 int *shadowsideslist;
227 int r_shadow_buffer_numleafpvsbytes;
228 unsigned char *r_shadow_buffer_visitingleafpvs;
229 unsigned char *r_shadow_buffer_leafpvs;
230 int *r_shadow_buffer_leaflist;
232 int r_shadow_buffer_numsurfacepvsbytes;
233 unsigned char *r_shadow_buffer_surfacepvs;
234 int *r_shadow_buffer_surfacelist;
235 unsigned char *r_shadow_buffer_surfacesides;
237 int r_shadow_buffer_numshadowtrispvsbytes;
238 unsigned char *r_shadow_buffer_shadowtrispvs;
239 int r_shadow_buffer_numlighttrispvsbytes;
240 unsigned char *r_shadow_buffer_lighttrispvs;
242 rtexturepool_t *r_shadow_texturepool;
243 rtexture_t *r_shadow_attenuationgradienttexture;
244 rtexture_t *r_shadow_attenuation2dtexture;
245 rtexture_t *r_shadow_attenuation3dtexture;
246 skinframe_t *r_shadow_lightcorona;
247 rtexture_t *r_shadow_shadowmap2dtexture;
248 rtexture_t *r_shadow_shadowmap2dcolortexture;
249 rtexture_t *r_shadow_shadowmapvsdcttexture;
250 int r_shadow_shadowmapsize; // changes for each light based on distance
251 int r_shadow_shadowmaplod; // changes for each light based on distance
253 GLuint r_shadow_prepassgeometryfbo;
254 GLuint r_shadow_prepasslightingdiffusespecularfbo;
255 GLuint r_shadow_prepasslightingdiffusefbo;
256 int r_shadow_prepass_width;
257 int r_shadow_prepass_height;
258 rtexture_t *r_shadow_prepassgeometrydepthtexture;
259 rtexture_t *r_shadow_prepassgeometrydepthcolortexture;
260 rtexture_t *r_shadow_prepassgeometrynormalmaptexture;
261 rtexture_t *r_shadow_prepasslightingdiffusetexture;
262 rtexture_t *r_shadow_prepasslightingspeculartexture;
264 // lights are reloaded when this changes
265 char r_shadow_mapname[MAX_QPATH];
267 // used only for light filters (cubemaps)
268 rtexturepool_t *r_shadow_filters_texturepool;
270 static const GLenum r_shadow_prepasslightingdrawbuffers[2] = {GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT};
272 cvar_t r_shadow_bumpscale_basetexture = {0, "r_shadow_bumpscale_basetexture", "0", "generate fake bumpmaps from diffuse textures at this bumpyness, try 4 to match tenebrae, higher values increase depth, requires r_restart to take effect"};
273 cvar_t r_shadow_bumpscale_bumpmap = {0, "r_shadow_bumpscale_bumpmap", "4", "what magnitude to interpret _bump.tga textures as, higher values increase depth, requires r_restart to take effect"};
274 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
275 cvar_t r_shadow_deferred = {CVAR_SAVE, "r_shadow_deferred", "0", "uses image-based lighting instead of geometry-based lighting, the method used renders a depth image and a normalmap image, renders lights into separate diffuse and specular images, and then combines this into the normal rendering, requires r_shadow_shadowmapping"};
276 cvar_t r_shadow_deferred_8bitrange = {CVAR_SAVE, "r_shadow_deferred_8bitrange", "2", "dynamic range of image-based lighting when using 32bit color (does not apply to fp)"};
277 //cvar_t r_shadow_deferred_fp = {CVAR_SAVE, "r_shadow_deferred_fp", "0", "use 16bit (1) or 32bit (2) floating point for accumulation of image-based lighting"};
278 cvar_t r_shadow_usebihculling = {0, "r_shadow_usebihculling", "1", "use BIH (Bounding Interval Hierarchy) for culling lit surfaces instead of BSP (Binary Space Partitioning)"};
279 cvar_t r_shadow_usenormalmap = {CVAR_SAVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"};
280 cvar_t r_shadow_gloss = {CVAR_SAVE, "r_shadow_gloss", "1", "0 disables gloss (specularity) rendering, 1 uses gloss if textures are found, 2 forces a flat metallic specular effect on everything without textures (similar to tenebrae)"};
281 cvar_t r_shadow_gloss2intensity = {0, "r_shadow_gloss2intensity", "0.125", "how bright the forced flat gloss should look if r_shadow_gloss is 2"};
282 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
283 cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
284 cvar_t r_shadow_gloss2exponent = {0, "r_shadow_gloss2exponent", "32", "same as r_shadow_glossexponent but for forced gloss (gloss 2) surfaces"};
285 cvar_t r_shadow_glossexact = {0, "r_shadow_glossexact", "0", "use exact reflection math for gloss (slightly slower, but should look a tad better)"};
286 cvar_t r_shadow_lightattenuationdividebias = {0, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"};
287 cvar_t r_shadow_lightattenuationlinearscale = {0, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"};
288 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
289 cvar_t r_shadow_lightradiusscale = {0, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
290 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "0", "how far to cast shadows"};
291 cvar_t r_shadow_frontsidecasting = {0, "r_shadow_frontsidecasting", "1", "whether to cast shadows from illuminated triangles (front side of model) or unlit triangles (back side of model)"};
292 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
293 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
294 cvar_t r_shadow_realtime_dlight_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
295 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
296 cvar_t r_shadow_realtime_world = {CVAR_SAVE, "r_shadow_realtime_world", "0", "enables rendering of full world lighting (whether loaded from the map, or a .rtlights file, or a .ent file, or a .lights file produced by hlight)"};
297 cvar_t r_shadow_realtime_world_lightmaps = {CVAR_SAVE, "r_shadow_realtime_world_lightmaps", "0", "brightness to render lightmaps when using full world lighting, try 0.5 for a tenebrae-like appearance"};
298 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
299 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
300 cvar_t r_shadow_realtime_world_compileshadow = {0, "r_shadow_realtime_world_compileshadow", "1", "enables compilation of shadows from world lights for higher performance rendering"};
301 cvar_t r_shadow_realtime_world_compilesvbsp = {0, "r_shadow_realtime_world_compilesvbsp", "1", "enables svbsp optimization during compilation (slower than compileportalculling but more exact)"};
302 cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "1", "enables portal-based culling optimization during compilation (overrides compilesvbsp)"};
303 cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1", "use scissor optimization of light rendering (restricts rendering to the portion of the screen affected by the light)"};
304 cvar_t r_shadow_shadowmapping = {CVAR_SAVE, "r_shadow_shadowmapping", "0", "enables use of shadowmapping (depth texture sampling) instead of stencil shadow volumes, requires gl_fbo 1"};
305 cvar_t r_shadow_shadowmapping_filterquality = {CVAR_SAVE, "r_shadow_shadowmapping_filterquality", "-1", "shadowmap filter modes: -1 = auto-select, 0 = no filtering, 1 = bilinear, 2 = bilinear 2x2 blur (fast), 3 = 3x3 blur (moderate), 4 = 4x4 blur (slow)"};
306 cvar_t r_shadow_shadowmapping_depthbits = {CVAR_SAVE, "r_shadow_shadowmapping_depthbits", "24", "requested minimum shadowmap texture depth bits"};
307 cvar_t r_shadow_shadowmapping_vsdct = {CVAR_SAVE, "r_shadow_shadowmapping_vsdct", "1", "enables use of virtual shadow depth cube texture"};
308 cvar_t r_shadow_shadowmapping_minsize = {CVAR_SAVE, "r_shadow_shadowmapping_minsize", "32", "shadowmap size limit"};
309 cvar_t r_shadow_shadowmapping_maxsize = {CVAR_SAVE, "r_shadow_shadowmapping_maxsize", "512", "shadowmap size limit"};
310 cvar_t r_shadow_shadowmapping_precision = {CVAR_SAVE, "r_shadow_shadowmapping_precision", "1", "makes shadowmaps have a maximum resolution of this number of pixels per light source radius unit such that, for example, at precision 0.5 a light with radius 200 will have a maximum resolution of 100 pixels"};
311 //cvar_t r_shadow_shadowmapping_lod_bias = {CVAR_SAVE, "r_shadow_shadowmapping_lod_bias", "16", "shadowmap size bias"};
312 //cvar_t r_shadow_shadowmapping_lod_scale = {CVAR_SAVE, "r_shadow_shadowmapping_lod_scale", "128", "shadowmap size scaling parameter"};
313 cvar_t r_shadow_shadowmapping_bordersize = {CVAR_SAVE, "r_shadow_shadowmapping_bordersize", "4", "shadowmap size bias for filtering"};
314 cvar_t r_shadow_shadowmapping_nearclip = {CVAR_SAVE, "r_shadow_shadowmapping_nearclip", "1", "shadowmap nearclip in world units"};
315 cvar_t r_shadow_shadowmapping_bias = {CVAR_SAVE, "r_shadow_shadowmapping_bias", "0.03", "shadowmap bias parameter (this is multiplied by nearclip * 1024 / lodsize)"};
316 cvar_t r_shadow_shadowmapping_polygonfactor = {CVAR_SAVE, "r_shadow_shadowmapping_polygonfactor", "2", "slope-dependent shadowmapping bias"};
317 cvar_t r_shadow_shadowmapping_polygonoffset = {CVAR_SAVE, "r_shadow_shadowmapping_polygonoffset", "0", "constant shadowmapping bias"};
318 cvar_t r_shadow_sortsurfaces = {0, "r_shadow_sortsurfaces", "1", "improve performance by sorting illuminated surfaces by texture"};
319 cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
320 cvar_t r_shadow_polygonoffset = {0, "r_shadow_polygonoffset", "1", "how much to push shadow volumes into the distance when rendering, to reduce chances of zfighting artifacts (should not be less than 0)"};
321 cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "1", "use 3D voxel textures for spherical attenuation rather than cylindrical (does not affect OpenGL 2.0 render path)"};
322 cvar_t r_shadow_bouncegrid = {CVAR_SAVE, "r_shadow_bouncegrid", "0", "perform particle tracing for indirect lighting (Global Illumination / radiosity) using a 3D texture covering the scene, requires r_shadow_realtime_world 1"};
323 cvar_t r_shadow_bouncegrid_bounceanglediffuse = {CVAR_SAVE, "r_shadow_bouncegrid_bounceanglediffuse", "0", "use random bounce direction rather than true reflection, makes some corner areas dark"};
324 cvar_t r_shadow_bouncegrid_dlightparticlemultiplier = {CVAR_SAVE, "r_shadow_bouncegrid_dlightparticlemultiplier", "0", "if set to a high value like 16 this can make dlights look great, but 0 is recommended for performance reasons"};
325 cvar_t r_shadow_bouncegrid_hitmodels = {CVAR_SAVE, "r_shadow_bouncegrid_hitmodels", "0", "enables hitting character model geometry (SLOW)"};
326 cvar_t r_shadow_bouncegrid_intensity = {CVAR_SAVE, "r_shadow_bouncegrid_intensity", "1", "overall brightness of bouncegrid texture"};
327 cvar_t r_shadow_bouncegrid_lightradiusscale = {CVAR_SAVE, "r_shadow_bouncegrid_lightradiusscale", "2", "particles stop at this fraction of light radius (can be more than 1)"};
328 cvar_t r_shadow_bouncegrid_maxbounce = {CVAR_SAVE, "r_shadow_bouncegrid_maxbounce", "3", "maximum number of bounces for a particle (minimum is 1)"};
329 cvar_t r_shadow_bouncegrid_particlebounceintensity = {CVAR_SAVE, "r_shadow_bouncegrid_particlebounceintensity", "1", "amount of energy carried over after each bounce"};
330 cvar_t r_shadow_bouncegrid_particleintensity = {CVAR_SAVE, "r_shadow_bouncegrid_particleintensity", "4", "brightness of particles contributing to bouncegrid texture"};
331 cvar_t r_shadow_bouncegrid_particlespacing = {CVAR_SAVE, "r_shadow_bouncegrid_particlespacing", "32", "emit one particle per this many units (squared) of radius (squared)"};
332 cvar_t r_shadow_bouncegrid_spacingx = {CVAR_SAVE, "r_shadow_bouncegrid_spacingx", "64", "unit size of bouncegrid pixel on X axis"};
333 cvar_t r_shadow_bouncegrid_spacingy = {CVAR_SAVE, "r_shadow_bouncegrid_spacingy", "64", "unit size of bouncegrid pixel on Y axis"};
334 cvar_t r_shadow_bouncegrid_spacingz = {CVAR_SAVE, "r_shadow_bouncegrid_spacingz", "64", "unit size of bouncegrid pixel on Z axis"};
335 cvar_t r_shadow_bouncegrid_stablerandom = {CVAR_SAVE, "r_shadow_bouncegrid_stablerandom", "1", "make particle distribution consistent from frame to frame"};
336 cvar_t r_shadow_bouncegrid_updateinterval = {CVAR_SAVE, "r_shadow_bouncegrid_updateinterval", "0", "update bouncegrid texture once per this many seconds, useful values are 0, 0.05, or 1000000"};
337 cvar_t r_shadow_bouncegrid_x = {CVAR_SAVE, "r_shadow_bouncegrid_x", "64", "maximum texture size of bouncegrid on X axis"};
338 cvar_t r_shadow_bouncegrid_y = {CVAR_SAVE, "r_shadow_bouncegrid_y", "64", "maximum texture size of bouncegrid on Y axis"};
339 cvar_t r_shadow_bouncegrid_z = {CVAR_SAVE, "r_shadow_bouncegrid_z", "32", "maximum texture size of bouncegrid on Z axis"};
340 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "1", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
341 cvar_t r_coronas_occlusionsizescale = {CVAR_SAVE, "r_coronas_occlusionsizescale", "0.1", "size of light source for corona occlusion checksum the proportion of hidden pixels controls corona intensity"};
342 cvar_t r_coronas_occlusionquery = {CVAR_SAVE, "r_coronas_occlusionquery", "1", "use GL_ARB_occlusion_query extension if supported (fades coronas according to visibility)"};
343 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
344 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
345 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
346 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
347 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
348 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
349 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
350 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
351 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
353 rtexture_t *r_shadow_bouncegridtexture;
354 matrix4x4_t r_shadow_bouncegridmatrix;
355 vec_t r_shadow_bouncegridintensity;
356 static double r_shadow_bouncegridtime;
357 static int r_shadow_bouncegridresolution[3];
358 static int r_shadow_bouncegridnumpixels;
359 static unsigned char *r_shadow_bouncegridpixels;
360 static unsigned short *r_shadow_bouncegridhighpixels;
362 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
363 #define ATTENTABLESIZE 256
364 // 1D gradient, 2D circle and 3D sphere attenuation textures
365 #define ATTEN1DSIZE 32
366 #define ATTEN2DSIZE 64
367 #define ATTEN3DSIZE 32
369 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
370 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
371 static float r_shadow_attentable[ATTENTABLESIZE+1];
373 rtlight_t *r_shadow_compilingrtlight;
374 static memexpandablearray_t r_shadow_worldlightsarray;
375 dlight_t *r_shadow_selectedlight;
376 dlight_t r_shadow_bufferlight;
377 vec3_t r_editlights_cursorlocation;
378 qboolean r_editlights_lockcursor;
380 extern int con_vislines;
382 void R_Shadow_UncompileWorldLights(void);
383 void R_Shadow_ClearWorldLights(void);
384 void R_Shadow_SaveWorldLights(void);
385 void R_Shadow_LoadWorldLights(void);
386 void R_Shadow_LoadLightsFile(void);
387 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
388 void R_Shadow_EditLights_Reload_f(void);
389 void R_Shadow_ValidateCvars(void);
390 static void R_Shadow_MakeTextures(void);
392 #define EDLIGHTSPRSIZE 8
393 skinframe_t *r_editlights_sprcursor;
394 skinframe_t *r_editlights_sprlight;
395 skinframe_t *r_editlights_sprnoshadowlight;
396 skinframe_t *r_editlights_sprcubemaplight;
397 skinframe_t *r_editlights_sprcubemapnoshadowlight;
398 skinframe_t *r_editlights_sprselection;
400 void R_Shadow_SetShadowMode(void)
402 r_shadow_shadowmapmaxsize = bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4);
403 r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20;
404 r_shadow_shadowmapfilterquality = r_shadow_shadowmapping_filterquality.integer;
405 r_shadow_shadowmapdepthbits = r_shadow_shadowmapping_depthbits.integer;
406 r_shadow_shadowmapborder = bound(0, r_shadow_shadowmapping_bordersize.integer, 16);
407 r_shadow_shadowmaplod = -1;
408 r_shadow_shadowmapsize = 0;
409 r_shadow_shadowmapsampler = false;
410 r_shadow_shadowmappcf = 0;
411 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
412 if ((r_shadow_shadowmapping.integer || r_shadow_deferred.integer) && vid.support.ext_framebuffer_object)
414 switch(vid.renderpath)
416 case RENDERPATH_GL20:
417 if(r_shadow_shadowmapfilterquality < 0)
419 if(vid.support.amd_texture_texture4 || vid.support.arb_texture_gather)
420 r_shadow_shadowmappcf = 1;
421 else if(strstr(gl_vendor, "NVIDIA") || strstr(gl_renderer, "Radeon HD"))
423 r_shadow_shadowmapsampler = vid.support.arb_shadow;
424 r_shadow_shadowmappcf = 1;
426 else if(strstr(gl_vendor, "ATI"))
427 r_shadow_shadowmappcf = 1;
429 r_shadow_shadowmapsampler = vid.support.arb_shadow;
433 switch (r_shadow_shadowmapfilterquality)
436 r_shadow_shadowmapsampler = vid.support.arb_shadow;
439 r_shadow_shadowmapsampler = vid.support.arb_shadow;
440 r_shadow_shadowmappcf = 1;
443 r_shadow_shadowmappcf = 1;
446 r_shadow_shadowmappcf = 2;
450 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
452 case RENDERPATH_D3D9:
453 case RENDERPATH_D3D10:
454 case RENDERPATH_D3D11:
455 case RENDERPATH_SOFT:
456 r_shadow_shadowmapsampler = false;
457 r_shadow_shadowmappcf = 1;
458 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
460 case RENDERPATH_GL13:
462 case RENDERPATH_GL11:
464 case RENDERPATH_GLES2:
470 qboolean R_Shadow_ShadowMappingEnabled(void)
472 switch (r_shadow_shadowmode)
474 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
481 void R_Shadow_FreeShadowMaps(void)
483 R_Shadow_SetShadowMode();
485 R_Mesh_DestroyFramebufferObject(r_shadow_fbo2d);
489 if (r_shadow_shadowmap2dtexture)
490 R_FreeTexture(r_shadow_shadowmap2dtexture);
491 r_shadow_shadowmap2dtexture = NULL;
493 if (r_shadow_shadowmap2dcolortexture)
494 R_FreeTexture(r_shadow_shadowmap2dcolortexture);
495 r_shadow_shadowmap2dcolortexture = NULL;
497 if (r_shadow_shadowmapvsdcttexture)
498 R_FreeTexture(r_shadow_shadowmapvsdcttexture);
499 r_shadow_shadowmapvsdcttexture = NULL;
502 void r_shadow_start(void)
504 // allocate vertex processing arrays
505 r_shadow_bouncegridpixels = NULL;
506 r_shadow_bouncegridhighpixels = NULL;
507 r_shadow_bouncegridnumpixels = 0;
508 r_shadow_bouncegridtexture = NULL;
509 r_shadow_attenuationgradienttexture = NULL;
510 r_shadow_attenuation2dtexture = NULL;
511 r_shadow_attenuation3dtexture = NULL;
512 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
513 r_shadow_shadowmap2dtexture = NULL;
514 r_shadow_shadowmap2dcolortexture = NULL;
515 r_shadow_shadowmapvsdcttexture = NULL;
516 r_shadow_shadowmapmaxsize = 0;
517 r_shadow_shadowmapsize = 0;
518 r_shadow_shadowmaplod = 0;
519 r_shadow_shadowmapfilterquality = -1;
520 r_shadow_shadowmapdepthbits = 0;
521 r_shadow_shadowmapvsdct = false;
522 r_shadow_shadowmapsampler = false;
523 r_shadow_shadowmappcf = 0;
526 R_Shadow_FreeShadowMaps();
528 r_shadow_texturepool = NULL;
529 r_shadow_filters_texturepool = NULL;
530 R_Shadow_ValidateCvars();
531 R_Shadow_MakeTextures();
532 maxshadowtriangles = 0;
533 shadowelements = NULL;
534 maxshadowvertices = 0;
535 shadowvertex3f = NULL;
543 shadowmarklist = NULL;
548 shadowsideslist = NULL;
549 r_shadow_buffer_numleafpvsbytes = 0;
550 r_shadow_buffer_visitingleafpvs = NULL;
551 r_shadow_buffer_leafpvs = NULL;
552 r_shadow_buffer_leaflist = NULL;
553 r_shadow_buffer_numsurfacepvsbytes = 0;
554 r_shadow_buffer_surfacepvs = NULL;
555 r_shadow_buffer_surfacelist = NULL;
556 r_shadow_buffer_surfacesides = NULL;
557 r_shadow_buffer_numshadowtrispvsbytes = 0;
558 r_shadow_buffer_shadowtrispvs = NULL;
559 r_shadow_buffer_numlighttrispvsbytes = 0;
560 r_shadow_buffer_lighttrispvs = NULL;
562 r_shadow_usingdeferredprepass = false;
563 r_shadow_prepass_width = r_shadow_prepass_height = 0;
566 static void R_Shadow_FreeDeferred(void);
567 void r_shadow_shutdown(void)
570 R_Shadow_UncompileWorldLights();
572 R_Shadow_FreeShadowMaps();
574 r_shadow_usingdeferredprepass = false;
575 if (r_shadow_prepass_width)
576 R_Shadow_FreeDeferred();
577 r_shadow_prepass_width = r_shadow_prepass_height = 0;
580 r_shadow_bouncegridtexture = NULL;
581 r_shadow_bouncegridpixels = NULL;
582 r_shadow_bouncegridhighpixels = NULL;
583 r_shadow_bouncegridnumpixels = 0;
584 r_shadow_attenuationgradienttexture = NULL;
585 r_shadow_attenuation2dtexture = NULL;
586 r_shadow_attenuation3dtexture = NULL;
587 R_FreeTexturePool(&r_shadow_texturepool);
588 R_FreeTexturePool(&r_shadow_filters_texturepool);
589 maxshadowtriangles = 0;
591 Mem_Free(shadowelements);
592 shadowelements = NULL;
594 Mem_Free(shadowvertex3f);
595 shadowvertex3f = NULL;
598 Mem_Free(vertexupdate);
601 Mem_Free(vertexremap);
607 Mem_Free(shadowmark);
610 Mem_Free(shadowmarklist);
611 shadowmarklist = NULL;
616 Mem_Free(shadowsides);
619 Mem_Free(shadowsideslist);
620 shadowsideslist = NULL;
621 r_shadow_buffer_numleafpvsbytes = 0;
622 if (r_shadow_buffer_visitingleafpvs)
623 Mem_Free(r_shadow_buffer_visitingleafpvs);
624 r_shadow_buffer_visitingleafpvs = NULL;
625 if (r_shadow_buffer_leafpvs)
626 Mem_Free(r_shadow_buffer_leafpvs);
627 r_shadow_buffer_leafpvs = NULL;
628 if (r_shadow_buffer_leaflist)
629 Mem_Free(r_shadow_buffer_leaflist);
630 r_shadow_buffer_leaflist = NULL;
631 r_shadow_buffer_numsurfacepvsbytes = 0;
632 if (r_shadow_buffer_surfacepvs)
633 Mem_Free(r_shadow_buffer_surfacepvs);
634 r_shadow_buffer_surfacepvs = NULL;
635 if (r_shadow_buffer_surfacelist)
636 Mem_Free(r_shadow_buffer_surfacelist);
637 r_shadow_buffer_surfacelist = NULL;
638 if (r_shadow_buffer_surfacesides)
639 Mem_Free(r_shadow_buffer_surfacesides);
640 r_shadow_buffer_surfacesides = NULL;
641 r_shadow_buffer_numshadowtrispvsbytes = 0;
642 if (r_shadow_buffer_shadowtrispvs)
643 Mem_Free(r_shadow_buffer_shadowtrispvs);
644 r_shadow_buffer_numlighttrispvsbytes = 0;
645 if (r_shadow_buffer_lighttrispvs)
646 Mem_Free(r_shadow_buffer_lighttrispvs);
649 void r_shadow_newmap(void)
651 if (r_shadow_bouncegridtexture) R_FreeTexture(r_shadow_bouncegridtexture);r_shadow_bouncegridtexture = NULL;
652 if (r_shadow_lightcorona) R_SkinFrame_MarkUsed(r_shadow_lightcorona);
653 if (r_editlights_sprcursor) R_SkinFrame_MarkUsed(r_editlights_sprcursor);
654 if (r_editlights_sprlight) R_SkinFrame_MarkUsed(r_editlights_sprlight);
655 if (r_editlights_sprnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprnoshadowlight);
656 if (r_editlights_sprcubemaplight) R_SkinFrame_MarkUsed(r_editlights_sprcubemaplight);
657 if (r_editlights_sprcubemapnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprcubemapnoshadowlight);
658 if (r_editlights_sprselection) R_SkinFrame_MarkUsed(r_editlights_sprselection);
659 if (strncmp(cl.worldname, r_shadow_mapname, sizeof(r_shadow_mapname)))
660 R_Shadow_EditLights_Reload_f();
663 void R_Shadow_Init(void)
665 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
666 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
667 Cvar_RegisterVariable(&r_shadow_usebihculling);
668 Cvar_RegisterVariable(&r_shadow_usenormalmap);
669 Cvar_RegisterVariable(&r_shadow_debuglight);
670 Cvar_RegisterVariable(&r_shadow_deferred);
671 Cvar_RegisterVariable(&r_shadow_deferred_8bitrange);
672 // Cvar_RegisterVariable(&r_shadow_deferred_fp);
673 Cvar_RegisterVariable(&r_shadow_gloss);
674 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
675 Cvar_RegisterVariable(&r_shadow_glossintensity);
676 Cvar_RegisterVariable(&r_shadow_glossexponent);
677 Cvar_RegisterVariable(&r_shadow_gloss2exponent);
678 Cvar_RegisterVariable(&r_shadow_glossexact);
679 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
680 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
681 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
682 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
683 Cvar_RegisterVariable(&r_shadow_projectdistance);
684 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
685 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
686 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
687 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
688 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
689 Cvar_RegisterVariable(&r_shadow_realtime_world);
690 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
691 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
692 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
693 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
694 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
695 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
696 Cvar_RegisterVariable(&r_shadow_scissor);
697 Cvar_RegisterVariable(&r_shadow_shadowmapping);
698 Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
699 Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
700 Cvar_RegisterVariable(&r_shadow_shadowmapping_depthbits);
701 Cvar_RegisterVariable(&r_shadow_shadowmapping_precision);
702 Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
703 Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
704 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
705 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
706 Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
707 Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
708 Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
709 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonfactor);
710 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonoffset);
711 Cvar_RegisterVariable(&r_shadow_sortsurfaces);
712 Cvar_RegisterVariable(&r_shadow_polygonfactor);
713 Cvar_RegisterVariable(&r_shadow_polygonoffset);
714 Cvar_RegisterVariable(&r_shadow_texture3d);
715 Cvar_RegisterVariable(&r_shadow_bouncegrid);
716 Cvar_RegisterVariable(&r_shadow_bouncegrid_bounceanglediffuse);
717 Cvar_RegisterVariable(&r_shadow_bouncegrid_dlightparticlemultiplier);
718 Cvar_RegisterVariable(&r_shadow_bouncegrid_hitmodels);
719 Cvar_RegisterVariable(&r_shadow_bouncegrid_intensity);
720 Cvar_RegisterVariable(&r_shadow_bouncegrid_lightradiusscale);
721 Cvar_RegisterVariable(&r_shadow_bouncegrid_maxbounce);
722 Cvar_RegisterVariable(&r_shadow_bouncegrid_particlebounceintensity);
723 Cvar_RegisterVariable(&r_shadow_bouncegrid_particleintensity);
724 Cvar_RegisterVariable(&r_shadow_bouncegrid_particlespacing);
725 Cvar_RegisterVariable(&r_shadow_bouncegrid_spacingx);
726 Cvar_RegisterVariable(&r_shadow_bouncegrid_spacingy);
727 Cvar_RegisterVariable(&r_shadow_bouncegrid_spacingz);
728 Cvar_RegisterVariable(&r_shadow_bouncegrid_stablerandom);
729 Cvar_RegisterVariable(&r_shadow_bouncegrid_updateinterval);
730 Cvar_RegisterVariable(&r_shadow_bouncegrid_x);
731 Cvar_RegisterVariable(&r_shadow_bouncegrid_y);
732 Cvar_RegisterVariable(&r_shadow_bouncegrid_z);
733 Cvar_RegisterVariable(&r_coronas);
734 Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
735 Cvar_RegisterVariable(&r_coronas_occlusionquery);
736 Cvar_RegisterVariable(&gl_flashblend);
737 Cvar_RegisterVariable(&gl_ext_separatestencil);
738 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
739 R_Shadow_EditLights_Init();
740 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
741 maxshadowtriangles = 0;
742 shadowelements = NULL;
743 maxshadowvertices = 0;
744 shadowvertex3f = NULL;
752 shadowmarklist = NULL;
757 shadowsideslist = NULL;
758 r_shadow_buffer_numleafpvsbytes = 0;
759 r_shadow_buffer_visitingleafpvs = NULL;
760 r_shadow_buffer_leafpvs = NULL;
761 r_shadow_buffer_leaflist = NULL;
762 r_shadow_buffer_numsurfacepvsbytes = 0;
763 r_shadow_buffer_surfacepvs = NULL;
764 r_shadow_buffer_surfacelist = NULL;
765 r_shadow_buffer_surfacesides = NULL;
766 r_shadow_buffer_shadowtrispvs = NULL;
767 r_shadow_buffer_lighttrispvs = NULL;
768 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap, NULL, NULL);
771 matrix4x4_t matrix_attenuationxyz =
774 {0.5, 0.0, 0.0, 0.5},
775 {0.0, 0.5, 0.0, 0.5},
776 {0.0, 0.0, 0.5, 0.5},
781 matrix4x4_t matrix_attenuationz =
784 {0.0, 0.0, 0.5, 0.5},
785 {0.0, 0.0, 0.0, 0.5},
786 {0.0, 0.0, 0.0, 0.5},
791 void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles, int vertscale, int triscale)
793 numvertices = ((numvertices + 255) & ~255) * vertscale;
794 numtriangles = ((numtriangles + 255) & ~255) * triscale;
795 // make sure shadowelements is big enough for this volume
796 if (maxshadowtriangles < numtriangles)
798 maxshadowtriangles = numtriangles;
800 Mem_Free(shadowelements);
801 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[3]));
803 // make sure shadowvertex3f is big enough for this volume
804 if (maxshadowvertices < numvertices)
806 maxshadowvertices = numvertices;
808 Mem_Free(shadowvertex3f);
809 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[3]));
813 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
815 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
816 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
817 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
818 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
819 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
821 if (r_shadow_buffer_visitingleafpvs)
822 Mem_Free(r_shadow_buffer_visitingleafpvs);
823 if (r_shadow_buffer_leafpvs)
824 Mem_Free(r_shadow_buffer_leafpvs);
825 if (r_shadow_buffer_leaflist)
826 Mem_Free(r_shadow_buffer_leaflist);
827 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
828 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
829 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
830 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
832 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
834 if (r_shadow_buffer_surfacepvs)
835 Mem_Free(r_shadow_buffer_surfacepvs);
836 if (r_shadow_buffer_surfacelist)
837 Mem_Free(r_shadow_buffer_surfacelist);
838 if (r_shadow_buffer_surfacesides)
839 Mem_Free(r_shadow_buffer_surfacesides);
840 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
841 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
842 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
843 r_shadow_buffer_surfacesides = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
845 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
847 if (r_shadow_buffer_shadowtrispvs)
848 Mem_Free(r_shadow_buffer_shadowtrispvs);
849 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
850 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
852 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
854 if (r_shadow_buffer_lighttrispvs)
855 Mem_Free(r_shadow_buffer_lighttrispvs);
856 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
857 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
861 void R_Shadow_PrepareShadowMark(int numtris)
863 // make sure shadowmark is big enough for this volume
864 if (maxshadowmark < numtris)
866 maxshadowmark = numtris;
868 Mem_Free(shadowmark);
870 Mem_Free(shadowmarklist);
871 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
872 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
876 // if shadowmarkcount wrapped we clear the array and adjust accordingly
877 if (shadowmarkcount == 0)
880 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
885 void R_Shadow_PrepareShadowSides(int numtris)
887 if (maxshadowsides < numtris)
889 maxshadowsides = numtris;
891 Mem_Free(shadowsides);
893 Mem_Free(shadowsideslist);
894 shadowsides = (unsigned char *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsides));
895 shadowsideslist = (int *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsideslist));
900 static int R_Shadow_ConstructShadowVolume_ZFail(int innumvertices, int innumtris, const int *inelement3i, const int *inneighbor3i, const float *invertex3f, int *outnumvertices, int *outelement3i, float *outvertex3f, const float *projectorigin, const float *projectdirection, float projectdistance, int numshadowmarktris, const int *shadowmarktris)
903 int outtriangles = 0, outvertices = 0;
906 float ratio, direction[3], projectvector[3];
908 if (projectdirection)
909 VectorScale(projectdirection, projectdistance, projectvector);
911 VectorClear(projectvector);
913 // create the vertices
914 if (projectdirection)
916 for (i = 0;i < numshadowmarktris;i++)
918 element = inelement3i + shadowmarktris[i] * 3;
919 for (j = 0;j < 3;j++)
921 if (vertexupdate[element[j]] != vertexupdatenum)
923 vertexupdate[element[j]] = vertexupdatenum;
924 vertexremap[element[j]] = outvertices;
925 vertex = invertex3f + element[j] * 3;
926 // project one copy of the vertex according to projectvector
927 VectorCopy(vertex, outvertex3f);
928 VectorAdd(vertex, projectvector, (outvertex3f + 3));
937 for (i = 0;i < numshadowmarktris;i++)
939 element = inelement3i + shadowmarktris[i] * 3;
940 for (j = 0;j < 3;j++)
942 if (vertexupdate[element[j]] != vertexupdatenum)
944 vertexupdate[element[j]] = vertexupdatenum;
945 vertexremap[element[j]] = outvertices;
946 vertex = invertex3f + element[j] * 3;
947 // project one copy of the vertex to the sphere radius of the light
948 // (FIXME: would projecting it to the light box be better?)
949 VectorSubtract(vertex, projectorigin, direction);
950 ratio = projectdistance / VectorLength(direction);
951 VectorCopy(vertex, outvertex3f);
952 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
960 if (r_shadow_frontsidecasting.integer)
962 for (i = 0;i < numshadowmarktris;i++)
964 int remappedelement[3];
966 const int *neighbortriangle;
968 markindex = shadowmarktris[i] * 3;
969 element = inelement3i + markindex;
970 neighbortriangle = inneighbor3i + markindex;
971 // output the front and back triangles
972 outelement3i[0] = vertexremap[element[0]];
973 outelement3i[1] = vertexremap[element[1]];
974 outelement3i[2] = vertexremap[element[2]];
975 outelement3i[3] = vertexremap[element[2]] + 1;
976 outelement3i[4] = vertexremap[element[1]] + 1;
977 outelement3i[5] = vertexremap[element[0]] + 1;
981 // output the sides (facing outward from this triangle)
982 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
984 remappedelement[0] = vertexremap[element[0]];
985 remappedelement[1] = vertexremap[element[1]];
986 outelement3i[0] = remappedelement[1];
987 outelement3i[1] = remappedelement[0];
988 outelement3i[2] = remappedelement[0] + 1;
989 outelement3i[3] = remappedelement[1];
990 outelement3i[4] = remappedelement[0] + 1;
991 outelement3i[5] = remappedelement[1] + 1;
996 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
998 remappedelement[1] = vertexremap[element[1]];
999 remappedelement[2] = vertexremap[element[2]];
1000 outelement3i[0] = remappedelement[2];
1001 outelement3i[1] = remappedelement[1];
1002 outelement3i[2] = remappedelement[1] + 1;
1003 outelement3i[3] = remappedelement[2];
1004 outelement3i[4] = remappedelement[1] + 1;
1005 outelement3i[5] = remappedelement[2] + 1;
1010 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1012 remappedelement[0] = vertexremap[element[0]];
1013 remappedelement[2] = vertexremap[element[2]];
1014 outelement3i[0] = remappedelement[0];
1015 outelement3i[1] = remappedelement[2];
1016 outelement3i[2] = remappedelement[2] + 1;
1017 outelement3i[3] = remappedelement[0];
1018 outelement3i[4] = remappedelement[2] + 1;
1019 outelement3i[5] = remappedelement[0] + 1;
1028 for (i = 0;i < numshadowmarktris;i++)
1030 int remappedelement[3];
1032 const int *neighbortriangle;
1034 markindex = shadowmarktris[i] * 3;
1035 element = inelement3i + markindex;
1036 neighbortriangle = inneighbor3i + markindex;
1037 // output the front and back triangles
1038 outelement3i[0] = vertexremap[element[2]];
1039 outelement3i[1] = vertexremap[element[1]];
1040 outelement3i[2] = vertexremap[element[0]];
1041 outelement3i[3] = vertexremap[element[0]] + 1;
1042 outelement3i[4] = vertexremap[element[1]] + 1;
1043 outelement3i[5] = vertexremap[element[2]] + 1;
1047 // output the sides (facing outward from this triangle)
1048 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
1050 remappedelement[0] = vertexremap[element[0]];
1051 remappedelement[1] = vertexremap[element[1]];
1052 outelement3i[0] = remappedelement[0];
1053 outelement3i[1] = remappedelement[1];
1054 outelement3i[2] = remappedelement[1] + 1;
1055 outelement3i[3] = remappedelement[0];
1056 outelement3i[4] = remappedelement[1] + 1;
1057 outelement3i[5] = remappedelement[0] + 1;
1062 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1064 remappedelement[1] = vertexremap[element[1]];
1065 remappedelement[2] = vertexremap[element[2]];
1066 outelement3i[0] = remappedelement[1];
1067 outelement3i[1] = remappedelement[2];
1068 outelement3i[2] = remappedelement[2] + 1;
1069 outelement3i[3] = remappedelement[1];
1070 outelement3i[4] = remappedelement[2] + 1;
1071 outelement3i[5] = remappedelement[1] + 1;
1076 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1078 remappedelement[0] = vertexremap[element[0]];
1079 remappedelement[2] = vertexremap[element[2]];
1080 outelement3i[0] = remappedelement[2];
1081 outelement3i[1] = remappedelement[0];
1082 outelement3i[2] = remappedelement[0] + 1;
1083 outelement3i[3] = remappedelement[2];
1084 outelement3i[4] = remappedelement[0] + 1;
1085 outelement3i[5] = remappedelement[2] + 1;
1093 *outnumvertices = outvertices;
1094 return outtriangles;
1097 static int R_Shadow_ConstructShadowVolume_ZPass(int innumvertices, int innumtris, const int *inelement3i, const int *inneighbor3i, const float *invertex3f, int *outnumvertices, int *outelement3i, float *outvertex3f, const float *projectorigin, const float *projectdirection, float projectdistance, int numshadowmarktris, const int *shadowmarktris)
1100 int outtriangles = 0, outvertices = 0;
1102 const float *vertex;
1103 float ratio, direction[3], projectvector[3];
1106 if (projectdirection)
1107 VectorScale(projectdirection, projectdistance, projectvector);
1109 VectorClear(projectvector);
1111 for (i = 0;i < numshadowmarktris;i++)
1113 int remappedelement[3];
1115 const int *neighbortriangle;
1117 markindex = shadowmarktris[i] * 3;
1118 neighbortriangle = inneighbor3i + markindex;
1119 side[0] = shadowmark[neighbortriangle[0]] == shadowmarkcount;
1120 side[1] = shadowmark[neighbortriangle[1]] == shadowmarkcount;
1121 side[2] = shadowmark[neighbortriangle[2]] == shadowmarkcount;
1122 if (side[0] + side[1] + side[2] == 0)
1126 element = inelement3i + markindex;
1128 // create the vertices
1129 for (j = 0;j < 3;j++)
1131 if (side[j] + side[j+1] == 0)
1134 if (vertexupdate[k] != vertexupdatenum)
1136 vertexupdate[k] = vertexupdatenum;
1137 vertexremap[k] = outvertices;
1138 vertex = invertex3f + k * 3;
1139 VectorCopy(vertex, outvertex3f);
1140 if (projectdirection)
1142 // project one copy of the vertex according to projectvector
1143 VectorAdd(vertex, projectvector, (outvertex3f + 3));
1147 // project one copy of the vertex to the sphere radius of the light
1148 // (FIXME: would projecting it to the light box be better?)
1149 VectorSubtract(vertex, projectorigin, direction);
1150 ratio = projectdistance / VectorLength(direction);
1151 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1158 // output the sides (facing outward from this triangle)
1161 remappedelement[0] = vertexremap[element[0]];
1162 remappedelement[1] = vertexremap[element[1]];
1163 outelement3i[0] = remappedelement[1];
1164 outelement3i[1] = remappedelement[0];
1165 outelement3i[2] = remappedelement[0] + 1;
1166 outelement3i[3] = remappedelement[1];
1167 outelement3i[4] = remappedelement[0] + 1;
1168 outelement3i[5] = remappedelement[1] + 1;
1175 remappedelement[1] = vertexremap[element[1]];
1176 remappedelement[2] = vertexremap[element[2]];
1177 outelement3i[0] = remappedelement[2];
1178 outelement3i[1] = remappedelement[1];
1179 outelement3i[2] = remappedelement[1] + 1;
1180 outelement3i[3] = remappedelement[2];
1181 outelement3i[4] = remappedelement[1] + 1;
1182 outelement3i[5] = remappedelement[2] + 1;
1189 remappedelement[0] = vertexremap[element[0]];
1190 remappedelement[2] = vertexremap[element[2]];
1191 outelement3i[0] = remappedelement[0];
1192 outelement3i[1] = remappedelement[2];
1193 outelement3i[2] = remappedelement[2] + 1;
1194 outelement3i[3] = remappedelement[0];
1195 outelement3i[4] = remappedelement[2] + 1;
1196 outelement3i[5] = remappedelement[0] + 1;
1203 *outnumvertices = outvertices;
1204 return outtriangles;
1207 void R_Shadow_MarkVolumeFromBox(int firsttriangle, int numtris, const float *invertex3f, const int *elements, const vec3_t projectorigin, const vec3_t projectdirection, const vec3_t lightmins, const vec3_t lightmaxs, const vec3_t surfacemins, const vec3_t surfacemaxs)
1213 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1215 tend = firsttriangle + numtris;
1216 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1218 // surface box entirely inside light box, no box cull
1219 if (projectdirection)
1221 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1223 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
1224 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1225 shadowmarklist[numshadowmark++] = t;
1230 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1231 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
1232 shadowmarklist[numshadowmark++] = t;
1237 // surface box not entirely inside light box, cull each triangle
1238 if (projectdirection)
1240 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1242 v[0] = invertex3f + e[0] * 3;
1243 v[1] = invertex3f + e[1] * 3;
1244 v[2] = invertex3f + e[2] * 3;
1245 TriangleNormal(v[0], v[1], v[2], normal);
1246 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1247 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1248 shadowmarklist[numshadowmark++] = t;
1253 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1255 v[0] = invertex3f + e[0] * 3;
1256 v[1] = invertex3f + e[1] * 3;
1257 v[2] = invertex3f + e[2] * 3;
1258 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1259 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1260 shadowmarklist[numshadowmark++] = t;
1266 qboolean R_Shadow_UseZPass(vec3_t mins, vec3_t maxs)
1271 if (r_shadow_compilingrtlight || !r_shadow_frontsidecasting.integer || !r_shadow_usezpassifpossible.integer)
1273 // check if the shadow volume intersects the near plane
1275 // a ray between the eye and light origin may intersect the caster,
1276 // indicating that the shadow may touch the eye location, however we must
1277 // test the near plane (a polygon), not merely the eye location, so it is
1278 // easiest to enlarge the caster bounding shape slightly for this.
1284 void R_Shadow_VolumeFromList(int numverts, int numtris, const float *invertex3f, const int *elements, const int *neighbors, const vec3_t projectorigin, const vec3_t projectdirection, float projectdistance, int nummarktris, const int *marktris, vec3_t trismins, vec3_t trismaxs)
1286 int i, tris, outverts;
1287 if (projectdistance < 0.1)
1289 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
1292 if (!numverts || !nummarktris)
1294 // make sure shadowelements is big enough for this volume
1295 if (maxshadowtriangles < nummarktris*8 || maxshadowvertices < numverts*2)
1296 R_Shadow_ResizeShadowArrays(numverts, nummarktris, 2, 8);
1298 if (maxvertexupdate < numverts)
1300 maxvertexupdate = numverts;
1302 Mem_Free(vertexupdate);
1304 Mem_Free(vertexremap);
1305 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1306 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1307 vertexupdatenum = 0;
1310 if (vertexupdatenum == 0)
1312 vertexupdatenum = 1;
1313 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
1314 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
1317 for (i = 0;i < nummarktris;i++)
1318 shadowmark[marktris[i]] = shadowmarkcount;
1320 if (r_shadow_compilingrtlight)
1322 // if we're compiling an rtlight, capture the mesh
1323 //tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1324 //Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zpass, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1325 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1326 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zfail, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1328 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
1330 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1331 R_Mesh_PrepareVertices_Vertex3f(outverts, shadowvertex3f, NULL);
1332 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1336 // decide which type of shadow to generate and set stencil mode
1337 R_Shadow_RenderMode_StencilShadowVolumes(R_Shadow_UseZPass(trismins, trismaxs));
1338 // generate the sides or a solid volume, depending on type
1339 if (r_shadow_rendermode >= R_SHADOW_RENDERMODE_ZPASS_STENCIL && r_shadow_rendermode <= R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE)
1340 tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1342 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1343 r_refdef.stats.lights_dynamicshadowtriangles += tris;
1344 r_refdef.stats.lights_shadowtriangles += tris;
1345 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
1347 // increment stencil if frontface is infront of depthbuffer
1348 GL_CullFace(r_refdef.view.cullface_front);
1349 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
1350 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1351 // decrement stencil if backface is infront of depthbuffer
1352 GL_CullFace(r_refdef.view.cullface_back);
1353 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
1355 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
1357 // decrement stencil if backface is behind depthbuffer
1358 GL_CullFace(r_refdef.view.cullface_front);
1359 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
1360 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1361 // increment stencil if frontface is behind depthbuffer
1362 GL_CullFace(r_refdef.view.cullface_back);
1363 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
1365 R_Mesh_PrepareVertices_Vertex3f(outverts, shadowvertex3f, NULL);
1366 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1370 int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias)
1372 // p1, p2, p3 are in the cubemap's local coordinate system
1373 // bias = border/(size - border)
1376 float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1377 dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2),
1378 dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3);
1379 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1381 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1382 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1383 | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1384 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1386 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1387 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1388 | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1390 dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1391 dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2),
1392 dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3);
1393 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1395 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1396 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1397 | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1398 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1400 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1401 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1402 | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1404 dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1405 dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2),
1406 dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3);
1407 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1409 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1410 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1411 | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1412 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1414 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1415 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1416 | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1421 int R_Shadow_CalcBBoxSideMask(const vec3_t mins, const vec3_t maxs, const matrix4x4_t *worldtolight, const matrix4x4_t *radiustolight, float bias)
1423 vec3_t center, radius, lightcenter, lightradius, pmin, pmax;
1424 float dp1, dn1, ap1, an1, dp2, dn2, ap2, an2;
1427 VectorSubtract(maxs, mins, radius);
1428 VectorScale(radius, 0.5f, radius);
1429 VectorAdd(mins, radius, center);
1430 Matrix4x4_Transform(worldtolight, center, lightcenter);
1431 Matrix4x4_Transform3x3(radiustolight, radius, lightradius);
1432 VectorSubtract(lightcenter, lightradius, pmin);
1433 VectorAdd(lightcenter, lightradius, pmax);
1435 dp1 = pmax[0] + pmax[1], dn1 = pmax[0] - pmin[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1436 dp2 = pmin[0] + pmin[1], dn2 = pmin[0] - pmax[1], ap2 = fabs(dp2), an2 = fabs(dn2);
1437 if(ap1 > bias*an1 && ap2 > bias*an2)
1439 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1440 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1441 if(an1 > bias*ap1 && an2 > bias*ap2)
1443 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1444 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1446 dp1 = pmax[1] + pmax[2], dn1 = pmax[1] - pmin[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1447 dp2 = pmin[1] + pmin[2], dn2 = pmin[1] - pmax[2], ap2 = fabs(dp2), an2 = fabs(dn2);
1448 if(ap1 > bias*an1 && ap2 > bias*an2)
1450 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1451 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1452 if(an1 > bias*ap1 && an2 > bias*ap2)
1454 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1455 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1457 dp1 = pmax[2] + pmax[0], dn1 = pmax[2] - pmin[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1458 dp2 = pmin[2] + pmin[0], dn2 = pmin[2] - pmax[0], ap2 = fabs(dp2), an2 = fabs(dn2);
1459 if(ap1 > bias*an1 && ap2 > bias*an2)
1461 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1462 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1463 if(an1 > bias*ap1 && an2 > bias*ap2)
1465 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1466 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1471 #define R_Shadow_CalcEntitySideMask(ent, worldtolight, radiustolight, bias) R_Shadow_CalcBBoxSideMask((ent)->mins, (ent)->maxs, worldtolight, radiustolight, bias)
1473 int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
1475 // p is in the cubemap's local coordinate system
1476 // bias = border/(size - border)
1477 float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn);
1478 float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn);
1479 float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn);
1481 if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
1482 if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
1483 if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
1484 if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
1485 if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
1486 if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
1490 int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
1494 int sides = 0x3F, masks[6] = { 3<<4, 3<<4, 3<<0, 3<<0, 3<<2, 3<<2 };
1495 float scale = (size - 2*border)/size, len;
1496 float bias = border / (float)(size - border), dp, dn, ap, an;
1497 // check if cone enclosing side would cross frustum plane
1498 scale = 2 / (scale*scale + 2);
1499 for (i = 0;i < 5;i++)
1501 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) > -0.03125)
1503 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[i].normal, n);
1504 len = scale*VectorLength2(n);
1505 if(n[0]*n[0] > len) sides &= n[0] < 0 ? ~(1<<0) : ~(2 << 0);
1506 if(n[1]*n[1] > len) sides &= n[1] < 0 ? ~(1<<2) : ~(2 << 2);
1507 if(n[2]*n[2] > len) sides &= n[2] < 0 ? ~(1<<4) : ~(2 << 4);
1509 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[4]) >= r_refdef.farclip - r_refdef.nearclip + 0.03125)
1511 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[4].normal, n);
1512 len = scale*VectorLength(n);
1513 if(n[0]*n[0] > len) sides &= n[0] >= 0 ? ~(1<<0) : ~(2 << 0);
1514 if(n[1]*n[1] > len) sides &= n[1] >= 0 ? ~(1<<2) : ~(2 << 2);
1515 if(n[2]*n[2] > len) sides &= n[2] >= 0 ? ~(1<<4) : ~(2 << 4);
1517 // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results
1518 // check if frustum corners/origin cross plane sides
1520 // infinite version, assumes frustum corners merely give direction and extend to infinite distance
1521 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.origin, p);
1522 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1523 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1524 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1525 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1526 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1527 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1528 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1529 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1530 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1531 for (i = 0;i < 4;i++)
1533 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.frustumcorner[i], n);
1534 VectorSubtract(n, p, n);
1535 dp = n[0] + n[1], dn = n[0] - n[1], ap = fabs(dp), an = fabs(dn);
1536 if(ap > 0) masks[0] |= dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2);
1537 if(an > 0) masks[1] |= dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2);
1538 dp = n[1] + n[2], dn = n[1] - n[2], ap = fabs(dp), an = fabs(dn);
1539 if(ap > 0) masks[2] |= dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4);
1540 if(an > 0) masks[3] |= dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4);
1541 dp = n[2] + n[0], dn = n[2] - n[0], ap = fabs(dp), an = fabs(dn);
1542 if(ap > 0) masks[4] |= dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0);
1543 if(an > 0) masks[5] |= dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0);
1546 // finite version, assumes corners are a finite distance from origin dependent on far plane
1547 for (i = 0;i < 5;i++)
1549 Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p);
1550 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1551 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1552 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1553 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1554 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1555 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1556 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1557 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1558 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1561 return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5];
1564 int R_Shadow_ChooseSidesFromBox(int firsttriangle, int numtris, const float *invertex3f, const int *elements, const matrix4x4_t *worldtolight, const vec3_t projectorigin, const vec3_t projectdirection, const vec3_t lightmins, const vec3_t lightmaxs, const vec3_t surfacemins, const vec3_t surfacemaxs, int *totals)
1572 int mask, surfacemask = 0;
1573 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1575 bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
1576 tend = firsttriangle + numtris;
1577 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1579 // surface box entirely inside light box, no box cull
1580 if (projectdirection)
1582 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1584 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1585 TriangleNormal(v[0], v[1], v[2], normal);
1586 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1588 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1589 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1590 surfacemask |= mask;
1593 totals[0] += mask&1, totals[1] += (mask>>1)&1, totals[2] += (mask>>2)&1, totals[3] += (mask>>3)&1, totals[4] += (mask>>4)&1, totals[5] += mask>>5;
1594 shadowsides[numshadowsides] = mask;
1595 shadowsideslist[numshadowsides++] = t;
1602 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1604 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1605 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]))
1607 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1608 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1609 surfacemask |= mask;
1612 totals[0] += mask&1, totals[1] += (mask>>1)&1, totals[2] += (mask>>2)&1, totals[3] += (mask>>3)&1, totals[4] += (mask>>4)&1, totals[5] += mask>>5;
1613 shadowsides[numshadowsides] = mask;
1614 shadowsideslist[numshadowsides++] = t;
1622 // surface box not entirely inside light box, cull each triangle
1623 if (projectdirection)
1625 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1627 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1628 TriangleNormal(v[0], v[1], v[2], normal);
1629 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1630 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1632 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1633 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1634 surfacemask |= mask;
1637 totals[0] += mask&1, totals[1] += (mask>>1)&1, totals[2] += (mask>>2)&1, totals[3] += (mask>>3)&1, totals[4] += (mask>>4)&1, totals[5] += mask>>5;
1638 shadowsides[numshadowsides] = mask;
1639 shadowsideslist[numshadowsides++] = t;
1646 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1648 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1649 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1650 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1652 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1653 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1654 surfacemask |= mask;
1657 totals[0] += mask&1, totals[1] += (mask>>1)&1, totals[2] += (mask>>2)&1, totals[3] += (mask>>3)&1, totals[4] += (mask>>4)&1, totals[5] += mask>>5;
1658 shadowsides[numshadowsides] = mask;
1659 shadowsideslist[numshadowsides++] = t;
1668 void R_Shadow_ShadowMapFromList(int numverts, int numtris, const float *vertex3f, const int *elements, int numsidetris, const int *sidetotals, const unsigned char *sides, const int *sidetris)
1670 int i, j, outtriangles = 0;
1671 int *outelement3i[6];
1672 if (!numverts || !numsidetris || !r_shadow_compilingrtlight)
1674 outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5];
1675 // make sure shadowelements is big enough for this mesh
1676 if (maxshadowtriangles < outtriangles)
1677 R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1);
1679 // compute the offset and size of the separate index lists for each cubemap side
1681 for (i = 0;i < 6;i++)
1683 outelement3i[i] = shadowelements + outtriangles * 3;
1684 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles;
1685 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i];
1686 outtriangles += sidetotals[i];
1689 // gather up the (sparse) triangles into separate index lists for each cubemap side
1690 for (i = 0;i < numsidetris;i++)
1692 const int *element = elements + sidetris[i] * 3;
1693 for (j = 0;j < 6;j++)
1695 if (sides[i] & (1 << j))
1697 outelement3i[j][0] = element[0];
1698 outelement3i[j][1] = element[1];
1699 outelement3i[j][2] = element[2];
1700 outelement3i[j] += 3;
1705 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, outtriangles, shadowelements);
1708 static void R_Shadow_MakeTextures_MakeCorona(void)
1712 unsigned char pixels[32][32][4];
1713 for (y = 0;y < 32;y++)
1715 dy = (y - 15.5f) * (1.0f / 16.0f);
1716 for (x = 0;x < 32;x++)
1718 dx = (x - 15.5f) * (1.0f / 16.0f);
1719 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1720 a = bound(0, a, 255);
1721 pixels[y][x][0] = a;
1722 pixels[y][x][1] = a;
1723 pixels[y][x][2] = a;
1724 pixels[y][x][3] = 255;
1727 r_shadow_lightcorona = R_SkinFrame_LoadInternalBGRA("lightcorona", TEXF_FORCELINEAR, &pixels[0][0][0], 32, 32);
1730 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1732 float dist = sqrt(x*x+y*y+z*z);
1733 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1734 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1735 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1738 static void R_Shadow_MakeTextures(void)
1741 float intensity, dist;
1743 R_Shadow_FreeShadowMaps();
1744 R_FreeTexturePool(&r_shadow_texturepool);
1745 r_shadow_texturepool = R_AllocTexturePool();
1746 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1747 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1748 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1749 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1750 for (x = 0;x <= ATTENTABLESIZE;x++)
1752 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1753 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1754 r_shadow_attentable[x] = bound(0, intensity, 1);
1756 // 1D gradient texture
1757 for (x = 0;x < ATTEN1DSIZE;x++)
1758 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1759 r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1760 // 2D circle texture
1761 for (y = 0;y < ATTEN2DSIZE;y++)
1762 for (x = 0;x < ATTEN2DSIZE;x++)
1763 data[y*ATTEN2DSIZE+x] = R_Shadow_MakeTextures_SamplePoint(((x + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375), ((y + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375), 0);
1764 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1765 // 3D sphere texture
1766 if (r_shadow_texture3d.integer && vid.support.ext_texture_3d)
1768 for (z = 0;z < ATTEN3DSIZE;z++)
1769 for (y = 0;y < ATTEN3DSIZE;y++)
1770 for (x = 0;x < ATTEN3DSIZE;x++)
1771 data[(z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x] = R_Shadow_MakeTextures_SamplePoint(((x + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375), ((y + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375), ((z + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375));
1772 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1775 r_shadow_attenuation3dtexture = NULL;
1778 R_Shadow_MakeTextures_MakeCorona();
1780 // Editor light sprites
1781 r_editlights_sprcursor = R_SkinFrame_LoadInternal8bit("gfx/editlights/cursor", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1798 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1799 r_editlights_sprlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/light", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1816 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1817 r_editlights_sprnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/noshadow", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1834 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1835 r_editlights_sprcubemaplight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemaplight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1852 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1853 r_editlights_sprcubemapnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemapnoshadowlight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1870 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1871 r_editlights_sprselection = R_SkinFrame_LoadInternal8bit("gfx/editlights/selection", TEXF_ALPHA | TEXF_CLAMP, (unsigned char *)
1888 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1891 void R_Shadow_ValidateCvars(void)
1893 if (r_shadow_texture3d.integer && !vid.support.ext_texture_3d)
1894 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1895 if (gl_ext_separatestencil.integer && !vid.support.ati_separate_stencil)
1896 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
1897 if (gl_ext_stenciltwoside.integer && !vid.support.ext_stencil_two_side)
1898 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1901 void R_Shadow_RenderMode_Begin(void)
1907 R_Shadow_ValidateCvars();
1909 if (!r_shadow_attenuation2dtexture
1910 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1911 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1912 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1913 R_Shadow_MakeTextures();
1916 R_Mesh_ResetTextureState();
1917 GL_BlendFunc(GL_ONE, GL_ZERO);
1918 GL_DepthRange(0, 1);
1919 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1921 GL_DepthMask(false);
1922 GL_Color(0, 0, 0, 1);
1923 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1925 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1927 if (gl_ext_separatestencil.integer && vid.support.ati_separate_stencil)
1929 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
1930 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
1932 else if (gl_ext_stenciltwoside.integer && vid.support.ext_stencil_two_side)
1934 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
1935 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
1939 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
1940 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
1943 switch(vid.renderpath)
1945 case RENDERPATH_GL20:
1946 case RENDERPATH_D3D9:
1947 case RENDERPATH_D3D10:
1948 case RENDERPATH_D3D11:
1949 case RENDERPATH_SOFT:
1950 case RENDERPATH_GLES2:
1951 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1953 case RENDERPATH_GL13:
1954 case RENDERPATH_GL11:
1955 if (r_textureunits.integer >= 2 && vid.texunits >= 2 && r_shadow_texture3d.integer && r_shadow_attenuation3dtexture)
1956 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN;
1957 else if (r_textureunits.integer >= 3 && vid.texunits >= 3)
1958 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN;
1959 else if (r_textureunits.integer >= 2 && vid.texunits >= 2)
1960 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN;
1962 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1968 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
1969 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
1970 r_shadow_drawbuffer = drawbuffer;
1971 r_shadow_readbuffer = readbuffer;
1973 r_shadow_cullface_front = r_refdef.view.cullface_front;
1974 r_shadow_cullface_back = r_refdef.view.cullface_back;
1977 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
1979 rsurface.rtlight = rtlight;
1982 void R_Shadow_RenderMode_Reset(void)
1984 R_Mesh_ResetRenderTargets();
1985 R_SetViewport(&r_refdef.view.viewport);
1986 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
1987 R_Mesh_ResetTextureState();
1988 GL_DepthRange(0, 1);
1990 GL_DepthMask(false);
1991 GL_DepthFunc(GL_LEQUAL);
1992 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1993 r_refdef.view.cullface_front = r_shadow_cullface_front;
1994 r_refdef.view.cullface_back = r_shadow_cullface_back;
1995 GL_CullFace(r_refdef.view.cullface_back);
1996 GL_Color(1, 1, 1, 1);
1997 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
1998 GL_BlendFunc(GL_ONE, GL_ZERO);
1999 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
2000 r_shadow_usingshadowmap2d = false;
2001 r_shadow_usingshadowmaportho = false;
2002 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
2005 void R_Shadow_ClearStencil(void)
2007 GL_Clear(GL_STENCIL_BUFFER_BIT, NULL, 1.0f, 128);
2008 r_refdef.stats.lights_clears++;
2011 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
2013 r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
2014 if (r_shadow_rendermode == mode)
2016 R_Shadow_RenderMode_Reset();
2017 GL_DepthFunc(GL_LESS);
2018 GL_ColorMask(0, 0, 0, 0);
2019 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2020 GL_CullFace(GL_NONE);
2021 R_SetupShader_DepthOrShadow();
2022 r_shadow_rendermode = mode;
2027 case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
2028 case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
2029 R_SetStencilSeparate(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, GL_ALWAYS, 128, 255);
2031 case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
2032 case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
2033 R_SetStencilSeparate(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, GL_ALWAYS, 128, 255);
2038 static void R_Shadow_MakeVSDCT(void)
2040 // maps to a 2x3 texture rectangle with normalized coordinates
2045 // stores abs(dir.xy), offset.xy/2.5
2046 unsigned char data[4*6] =
2048 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
2049 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
2050 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
2051 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
2052 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
2053 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
2055 r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
2058 static void R_Shadow_MakeShadowMap(int side, int size)
2060 switch (r_shadow_shadowmode)
2062 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2063 if (r_shadow_shadowmap2dtexture) return;
2064 r_shadow_shadowmap2dtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "shadowmap", size*2, size*(vid.support.arb_texture_non_power_of_two ? 3 : 4), r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
2065 r_shadow_shadowmap2dcolortexture = NULL;
2066 switch(vid.renderpath)
2069 case RENDERPATH_D3D9:
2070 r_shadow_shadowmap2dcolortexture = R_LoadTexture2D(r_shadow_texturepool, "shadowmaprendertarget", size*2, size*(vid.support.arb_texture_non_power_of_two ? 3 : 4), NULL, TEXTYPE_BGRA, TEXF_RENDERTARGET | TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
2071 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
2075 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2dtexture, NULL, NULL, NULL, NULL);
2083 // render depth into the fbo, do not render color at all
2084 // validate the fbo now
2088 qglDrawBuffer(GL_NONE);CHECKGLERROR
2089 qglReadBuffer(GL_NONE);CHECKGLERROR
2090 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2091 if (status != GL_FRAMEBUFFER_COMPLETE_EXT && (r_shadow_shadowmapping.integer || r_shadow_deferred.integer))
2093 Con_Printf("R_Shadow_MakeShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2094 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2095 Cvar_SetValueQuick(&r_shadow_deferred, 0);
2100 void R_Shadow_RenderMode_ShadowMap(int side, int clear, int size)
2102 float nearclip, farclip, bias;
2103 r_viewport_t viewport;
2106 float clearcolor[4];
2107 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
2109 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
2110 r_shadow_shadowmap_parameters[1] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
2111 r_shadow_shadowmap_parameters[3] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
2112 r_shadow_shadowmapside = side;
2113 r_shadow_shadowmapsize = size;
2115 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2116 r_shadow_shadowmap_parameters[2] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2117 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
2118 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D) goto init_done;
2120 // complex unrolled cube approach (more flexible)
2121 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2122 R_Shadow_MakeVSDCT();
2123 if (!r_shadow_shadowmap2dtexture)
2124 R_Shadow_MakeShadowMap(side, r_shadow_shadowmapmaxsize);
2125 if (r_shadow_shadowmap2dtexture) fbo = r_shadow_fbo2d;
2126 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
2127 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
2128 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
2130 R_Mesh_ResetTextureState();
2131 R_Mesh_ResetRenderTargets();
2132 R_Shadow_RenderMode_Reset();
2135 R_Mesh_SetRenderTargets(fbo, r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
2136 R_SetupShader_DepthOrShadow();
2139 R_SetupShader_ShowDepth();
2140 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
2145 R_SetViewport(&viewport);
2146 flipped = (side & 1) ^ (side >> 2);
2147 r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
2148 r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
2149 switch(vid.renderpath)
2151 case RENDERPATH_GL11:
2152 case RENDERPATH_GL13:
2153 case RENDERPATH_GL20:
2154 case RENDERPATH_SOFT:
2155 case RENDERPATH_GLES2:
2156 GL_CullFace(r_refdef.view.cullface_back);
2157 // OpenGL lets us scissor larger than the viewport, so go ahead and clear all views at once
2158 if ((clear & ((2 << side) - 1)) == (1 << side)) // only clear if the side is the first in the mask
2160 // get tightest scissor rectangle that encloses all viewports in the clear mask
2161 int x1 = clear & 0x15 ? 0 : size;
2162 int x2 = clear & 0x2A ? 2 * size : size;
2163 int y1 = clear & 0x03 ? 0 : (clear & 0xC ? size : 2 * size);
2164 int y2 = clear & 0x30 ? 3 * size : (clear & 0xC ? 2 * size : size);
2165 GL_Scissor(x1, y1, x2 - x1, y2 - y1);
2166 GL_Clear(GL_DEPTH_BUFFER_BIT, NULL, 1.0f, 0);
2168 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2170 case RENDERPATH_D3D9:
2171 case RENDERPATH_D3D10:
2172 case RENDERPATH_D3D11:
2173 Vector4Set(clearcolor, 1,1,1,1);
2174 // completely different meaning than in OpenGL path
2175 r_shadow_shadowmap_parameters[1] = 0;
2176 r_shadow_shadowmap_parameters[3] = -bias;
2177 // we invert the cull mode because we flip the projection matrix
2178 // NOTE: this actually does nothing because the DrawShadowMap code sets it to doublesided...
2179 GL_CullFace(r_refdef.view.cullface_front);
2180 // D3D considers it an error to use a scissor larger than the viewport... clear just this view
2181 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2182 if (r_shadow_shadowmapsampler)
2184 GL_ColorMask(0,0,0,0);
2186 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
2190 GL_ColorMask(1,1,1,1);
2192 GL_Clear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
2198 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
2200 R_Mesh_ResetTextureState();
2201 R_Mesh_ResetRenderTargets();
2204 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2205 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2206 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2207 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2209 R_Shadow_RenderMode_Reset();
2210 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2212 GL_DepthFunc(GL_EQUAL);
2213 // do global setup needed for the chosen lighting mode
2214 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2215 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2216 r_shadow_usingshadowmap2d = shadowmapping;
2217 r_shadow_rendermode = r_shadow_lightingrendermode;
2218 // only draw light where this geometry was already rendered AND the
2219 // stencil is 128 (values other than this mean shadow)
2221 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2223 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
2226 static const unsigned short bboxelements[36] =
2236 static const float bboxpoints[8][3] =
2248 void R_Shadow_RenderMode_DrawDeferredLight(qboolean stenciltest, qboolean shadowmapping)
2251 float vertex3f[8*3];
2252 const matrix4x4_t *matrix = &rsurface.rtlight->matrix_lighttoworld;
2253 // do global setup needed for the chosen lighting mode
2254 R_Shadow_RenderMode_Reset();
2255 r_shadow_rendermode = r_shadow_lightingrendermode;
2256 R_EntityMatrix(&identitymatrix);
2257 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2258 // only draw light where this geometry was already rendered AND the
2259 // stencil is 128 (values other than this mean shadow)
2260 R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2261 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
2263 r_shadow_usingshadowmap2d = shadowmapping;
2265 // render the lighting
2266 R_SetupShader_DeferredLight(rsurface.rtlight);
2267 for (i = 0;i < 8;i++)
2268 Matrix4x4_Transform(matrix, bboxpoints[i], vertex3f + i*3);
2269 GL_ColorMask(1,1,1,1);
2270 GL_DepthMask(false);
2271 GL_DepthRange(0, 1);
2272 GL_PolygonOffset(0, 0);
2274 GL_DepthFunc(GL_GREATER);
2275 GL_CullFace(r_refdef.view.cullface_back);
2276 R_Mesh_PrepareVertices_Vertex3f(8, vertex3f, NULL);
2277 R_Mesh_Draw(0, 8, 0, 12, NULL, NULL, 0, bboxelements, NULL, 0);
2280 static void R_Shadow_UpdateBounceGridTexture(void)
2282 #define MAXBOUNCEGRIDPARTICLESPERLIGHT 1048576
2284 int flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
2287 int hitsupercontentsmask;
2296 unsigned char *pixel;
2297 unsigned char *pixels;
2298 unsigned short *highpixel;
2299 unsigned short *highpixels;
2300 unsigned int lightindex;
2302 unsigned int range1;
2303 unsigned int range2;
2304 unsigned int seed = (unsigned int)(realtime * 1000.0f);
2306 vec3_t baseshotcolor;
2318 vec_t lightintensity;
2320 qboolean isstatic = r_shadow_bouncegrid_updateinterval.value > 1.0f;
2322 if (!r_shadow_bouncegrid.integer || !vid.support.ext_texture_3d)
2324 if (r_shadow_bouncegridtexture)
2326 R_FreeTexture(r_shadow_bouncegridtexture);
2327 r_shadow_bouncegridtexture = NULL;
2329 if (r_shadow_bouncegridpixels)
2330 Mem_Free(r_shadow_bouncegridpixels);
2331 r_shadow_bouncegridpixels = NULL;
2332 if (r_shadow_bouncegridhighpixels)
2333 Mem_Free(r_shadow_bouncegridhighpixels);
2334 r_shadow_bouncegridhighpixels = NULL;
2335 r_shadow_bouncegridnumpixels = 0;
2338 if (r_refdef.scene.worldmodel && isstatic)
2340 VectorSet(spacing, bound(1, r_shadow_bouncegrid_spacingx.value, 512), bound(1, r_shadow_bouncegrid_spacingy.value, 512), bound(1, r_shadow_bouncegrid_spacingz.value, 512));
2341 VectorMA(r_refdef.scene.worldmodel->normalmins, -2.0f, spacing, mins);
2342 VectorMA(r_refdef.scene.worldmodel->normalmaxs, 2.0f, spacing, maxs);
2343 VectorSubtract(maxs, mins, size);
2344 resolution[0] = (int)floor(size[0] / spacing[0] + 0.5f);
2345 resolution[1] = (int)floor(size[1] / spacing[1] + 0.5f);
2346 resolution[2] = (int)floor(size[2] / spacing[2] + 0.5f);
2347 resolution[0] = min(resolution[0], bound(4, r_shadow_bouncegrid_x.integer, (int)vid.maxtexturesize_3d));
2348 resolution[1] = min(resolution[1], bound(4, r_shadow_bouncegrid_y.integer, (int)vid.maxtexturesize_3d));
2349 resolution[2] = min(resolution[2], bound(4, r_shadow_bouncegrid_z.integer, (int)vid.maxtexturesize_3d));
2350 spacing[0] = size[0] / resolution[0];
2351 spacing[1] = size[1] / resolution[1];
2352 spacing[2] = size[2] / resolution[2];
2353 ispacing[0] = 1.0f / spacing[0];
2354 ispacing[1] = 1.0f / spacing[1];
2355 ispacing[2] = 1.0f / spacing[2];
2359 VectorSet(resolution, bound(4, r_shadow_bouncegrid_x.integer, (int)vid.maxtexturesize_3d), bound(4, r_shadow_bouncegrid_y.integer, (int)vid.maxtexturesize_3d), bound(4, r_shadow_bouncegrid_z.integer, (int)vid.maxtexturesize_3d));
2360 VectorSet(spacing, bound(1, r_shadow_bouncegrid_spacingx.value, 512), bound(1, r_shadow_bouncegrid_spacingy.value, 512), bound(1, r_shadow_bouncegrid_spacingz.value, 512));
2361 VectorMultiply(resolution, spacing, size);
2362 ispacing[0] = 1.0f / spacing[0];
2363 ispacing[1] = 1.0f / spacing[1];
2364 ispacing[2] = 1.0f / spacing[2];
2365 mins[0] = floor(r_refdef.view.origin[0] * ispacing[0] + 0.5f) * spacing[0] - 0.5f * size[0];
2366 mins[1] = floor(r_refdef.view.origin[1] * ispacing[1] + 0.5f) * spacing[1] - 0.5f * size[1];
2367 mins[2] = floor(r_refdef.view.origin[2] * ispacing[2] + 0.5f) * spacing[2] - 0.5f * size[2];
2368 VectorAdd(mins, size, maxs);
2370 r_shadow_bouncegridintensity = r_shadow_bouncegrid_intensity.value;
2371 if (r_shadow_bouncegridtexture && realtime < r_shadow_bouncegridtime + r_shadow_bouncegrid_updateinterval.value && resolution[0] == r_shadow_bouncegridresolution[0] && resolution[1] == r_shadow_bouncegridresolution[1] && resolution[2] == r_shadow_bouncegridresolution[2])
2373 // we're going to update the bouncegrid, update the matrix...
2374 memset(m, 0, sizeof(m));
2375 m[0] = 1.0f / size[0];
2376 m[3] = -mins[0] * m[0];
2377 m[5] = 1.0f / size[1];
2378 m[7] = -mins[1] * m[5];
2379 m[10] = 1.0f / size[2];
2380 m[11] = -mins[2] * m[10];
2382 Matrix4x4_FromArrayFloatD3D(&r_shadow_bouncegridmatrix, m);
2383 numpixels = resolution[0]*resolution[1]*resolution[2];
2384 // reallocate pixels for this update if needed...
2385 if (r_shadow_bouncegridnumpixels != numpixels || !r_shadow_bouncegridpixels || !r_shadow_bouncegridhighpixels)
2387 r_shadow_bouncegridpixels = (unsigned char *)Mem_Realloc(r_main_mempool, r_shadow_bouncegridpixels, numpixels * sizeof(unsigned char[4]));
2388 r_shadow_bouncegridhighpixels = (unsigned short *)Mem_Realloc(r_main_mempool, r_shadow_bouncegridhighpixels, numpixels * sizeof(unsigned short[4]));
2390 r_shadow_bouncegridnumpixels = numpixels;
2391 pixels = r_shadow_bouncegridpixels;
2392 highpixels = r_shadow_bouncegridhighpixels;
2393 memset(pixels, 0, numpixels * sizeof(unsigned char[4]));
2394 memset(highpixels, 0, numpixels * sizeof(unsigned short[3]));
2395 // figure out what we want to interact with
2396 if (r_shadow_bouncegrid_hitmodels.integer)
2397 hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_LIQUIDSMASK;
2399 hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_LIQUIDSMASK;
2400 maxbounce = bound(1, r_shadow_bouncegrid_maxbounce.integer, 16);
2401 // iterate world rtlights
2402 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
2403 range1 = isstatic ? 0 : r_refdef.scene.numlights;
2404 range2 = range + range1;
2405 for (lightindex = 0;lightindex < range2;lightindex++)
2409 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2410 if (!light || !(light->flags & flag))
2412 rtlight = &light->rtlight;
2413 // when static, we skip styled lights because they tend to change...
2414 if (rtlight->style > 0)
2416 VectorScale(rtlight->color, (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) * (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1), lightcolor);
2420 if (lightindex < range)
2422 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2423 rtlight = &light->rtlight;
2426 rtlight = r_refdef.scene.lights[lightindex - range];
2427 // draw only visible lights (major speedup)
2430 VectorScale(rtlight->currentcolor, rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale, lightcolor);
2432 if (!VectorLength2(lightcolor))
2434 // shoot particles from this light
2435 // use a calculation for the number of particles that will not
2436 // vary with lightstyle, otherwise we get randomized particle
2437 // distribution, the seeded random is only consistent for a
2438 // consistent number of particles on this light...
2439 radius = rtlight->radius * bound(0.0001f, r_shadow_bouncegrid_lightradiusscale.value, 1024.0f);
2440 s = rtlight->radius / bound(1.0f, r_shadow_bouncegrid_particlespacing.value, 1048576.0f);
2441 lightintensity = VectorLength(rtlight->color) * rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale;
2442 if (lightindex >= range)
2443 lightintensity *= r_shadow_bouncegrid_dlightparticlemultiplier.value;
2444 shootparticles = (int)bound(0, lightintensity * s *s, MAXBOUNCEGRIDPARTICLESPERLIGHT);
2445 if (!shootparticles)
2447 s = 65535.0f * r_shadow_bouncegrid_particleintensity.value / shootparticles;
2448 VectorScale(lightcolor, s, baseshotcolor);
2449 if (VectorLength2(baseshotcolor) < 3.0f)
2451 r_refdef.stats.bouncegrid_lights++;
2452 r_refdef.stats.bouncegrid_particles += shootparticles;
2453 for (shotparticles = 0;shotparticles < shootparticles;shotparticles++)
2455 if (r_shadow_bouncegrid_stablerandom.integer > 0)
2456 seed = lightindex * 11937 + shotparticles;
2457 VectorCopy(baseshotcolor, shotcolor);
2458 VectorCopy(rtlight->shadoworigin, clipstart);
2459 if (r_shadow_bouncegrid_stablerandom.integer < 0)
2460 VectorRandom(clipend);
2462 VectorCheeseRandom(clipend);
2463 VectorMA(clipstart, radius, clipend, clipend);
2464 for (bouncecount = 0;;bouncecount++)
2466 r_refdef.stats.bouncegrid_traces++;
2467 cliptrace = CL_TraceLine(clipstart, clipend, r_shadow_bouncegrid_hitmodels.integer ? MOVE_HITMODEL : MOVE_NOMONSTERS, NULL, hitsupercontentsmask, true, false, NULL, true);
2468 //Collision_ClipLineToWorld(&cliptrace, cl.worldmodel, clipstart, clipend, hitsupercontentsmask);
2469 if (cliptrace.fraction >= 1.0f)
2471 r_refdef.stats.bouncegrid_hits++;
2472 if (bouncecount > 0)
2474 r_refdef.stats.bouncegrid_splats++;
2475 // figure out which texture pixel this is in
2476 tex[0] = (int)((cliptrace.endpos[0] - mins[0]) * ispacing[0]);
2477 tex[1] = (int)((cliptrace.endpos[1] - mins[1]) * ispacing[1]);
2478 tex[2] = (int)((cliptrace.endpos[2] - mins[2]) * ispacing[2]);
2479 if (tex[0] >= 1 && tex[1] >= 1 && tex[2] >= 1 && tex[0] < resolution[0] - 1 && tex[1] < resolution[1] - 1 && tex[2] < resolution[2] - 1)
2481 // it is within bounds...
2482 pixelindex = ((tex[2]*resolution[1]+tex[1])*resolution[0]+tex[0]);
2483 pixel = pixels + 4 * pixelindex;
2484 highpixel = highpixels + 3 * pixelindex;
2485 // add to the high precision pixel color
2486 c[0] = highpixel[0] + (int)shotcolor[2];
2487 c[1] = highpixel[1] + (int)shotcolor[1];
2488 c[2] = highpixel[2] + (int)shotcolor[0];
2489 highpixel[0] = (unsigned short)min(c[0], 65535);
2490 highpixel[1] = (unsigned short)min(c[1], 65535);
2491 highpixel[2] = (unsigned short)min(c[2], 65535);
2492 // update the low precision pixel color
2493 pixel[0] = highpixel[0] >> 8;
2494 pixel[1] = highpixel[1] >> 8;
2495 pixel[2] = highpixel[2] >> 8;
2499 if (bouncecount >= maxbounce)
2501 // scale down shot color by bounce intensity and texture color (or 50% if no texture reported)
2502 VectorScale(shotcolor, r_shadow_bouncegrid_particlebounceintensity.value, shotcolor);
2503 if (cliptrace.hittexture && cliptrace.hittexture->currentskinframe)
2504 VectorMultiply(shotcolor, cliptrace.hittexture->currentskinframe->avgcolor, shotcolor);
2506 VectorScale(shotcolor, 0.5f, shotcolor);
2507 if (VectorLength2(shotcolor) < 3.0f)
2509 r_refdef.stats.bouncegrid_bounces++;
2510 if (r_shadow_bouncegrid_bounceanglediffuse.integer)
2512 // random direction, primarily along plane normal
2513 s = VectorDistance(cliptrace.endpos, clipend);
2514 if (r_shadow_bouncegrid_stablerandom.integer < 0)
2515 VectorRandom(clipend);
2517 VectorCheeseRandom(clipend);
2518 VectorMA(cliptrace.plane.normal, 0.95f, clipend, clipend);
2519 VectorNormalize(clipend);
2520 VectorScale(clipend, s, clipend);
2524 // reflect the remaining portion of the line across plane normal
2525 VectorSubtract(clipend, cliptrace.endpos, clipdiff);
2526 VectorReflect(clipdiff, 1.0, cliptrace.plane.normal, clipend);
2528 // calculate the new line start and end
2529 VectorCopy(cliptrace.endpos, clipstart);
2530 VectorAdd(clipstart, clipend, clipend);
2534 if (r_shadow_bouncegridtexture && r_shadow_bouncegridresolution[0] == resolution[0] && r_shadow_bouncegridresolution[1] == resolution[1] && r_shadow_bouncegridresolution[2] == resolution[2])
2535 R_UpdateTexture(r_shadow_bouncegridtexture, pixels, 0, 0, 0, resolution[0], resolution[1], resolution[2]);
2538 VectorCopy(resolution, r_shadow_bouncegridresolution);
2539 if (r_shadow_bouncegridtexture)
2540 R_FreeTexture(r_shadow_bouncegridtexture);
2541 r_shadow_bouncegridtexture = R_LoadTexture3D(r_shadow_texturepool, "bouncegrid", resolution[0], resolution[1], resolution[2], pixels, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, 0, NULL);
2543 r_shadow_bouncegridtime = realtime;
2546 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
2548 R_Shadow_RenderMode_Reset();
2549 GL_BlendFunc(GL_ONE, GL_ONE);
2550 GL_DepthRange(0, 1);
2551 GL_DepthTest(r_showshadowvolumes.integer < 2);
2552 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
2553 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2554 GL_CullFace(GL_NONE);
2555 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
2558 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
2560 R_Shadow_RenderMode_Reset();
2561 GL_BlendFunc(GL_ONE, GL_ONE);
2562 GL_DepthRange(0, 1);
2563 GL_DepthTest(r_showlighting.integer < 2);
2564 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2566 GL_DepthFunc(GL_EQUAL);
2567 R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2568 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2571 void R_Shadow_RenderMode_End(void)
2573 R_Shadow_RenderMode_Reset();
2574 R_Shadow_RenderMode_ActiveLight(NULL);
2576 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2577 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2580 int bboxedges[12][2] =
2599 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2601 if (!r_shadow_scissor.integer)
2603 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2604 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2605 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2606 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2609 if(R_ScissorForBBox(mins, maxs, r_shadow_lightscissor))
2610 return true; // invisible
2611 if(r_shadow_lightscissor[0] != r_refdef.view.viewport.x
2612 || r_shadow_lightscissor[1] != r_refdef.view.viewport.y
2613 || r_shadow_lightscissor[2] != r_refdef.view.viewport.width
2614 || r_shadow_lightscissor[3] != r_refdef.view.viewport.height)
2615 r_refdef.stats.lights_scissored++;
2619 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, const float *diffusecolor, const float *ambientcolor)
2622 const float *vertex3f;
2623 const float *normal3f;
2625 float dist, dot, distintensity, shadeintensity, v[3], n[3];
2626 switch (r_shadow_rendermode)
2628 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2629 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2630 if (VectorLength2(diffusecolor) > 0)
2632 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)
2634 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2635 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2636 if ((dot = DotProduct(n, v)) < 0)
2638 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2639 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
2642 VectorCopy(ambientcolor, color4f);
2643 if (r_refdef.fogenabled)
2646 f = RSurf_FogVertex(vertex3f);
2647 VectorScale(color4f, f, color4f);
2654 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
2656 VectorCopy(ambientcolor, color4f);
2657 if (r_refdef.fogenabled)
2660 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2661 f = RSurf_FogVertex(vertex3f);
2662 VectorScale(color4f + 4*i, f, color4f);
2668 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2669 if (VectorLength2(diffusecolor) > 0)
2671 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)
2673 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2674 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2676 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2677 if ((dot = DotProduct(n, v)) < 0)
2679 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2680 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2681 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2682 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2686 color4f[0] = ambientcolor[0] * distintensity;
2687 color4f[1] = ambientcolor[1] * distintensity;
2688 color4f[2] = ambientcolor[2] * distintensity;
2690 if (r_refdef.fogenabled)
2693 f = RSurf_FogVertex(vertex3f);
2694 VectorScale(color4f, f, color4f);
2698 VectorClear(color4f);
2704 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
2706 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2707 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2709 color4f[0] = ambientcolor[0] * distintensity;
2710 color4f[1] = ambientcolor[1] * distintensity;
2711 color4f[2] = ambientcolor[2] * distintensity;
2712 if (r_refdef.fogenabled)
2715 f = RSurf_FogVertex(vertex3f);
2716 VectorScale(color4f, f, color4f);
2720 VectorClear(color4f);
2725 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2726 if (VectorLength2(diffusecolor) > 0)
2728 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)
2730 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2731 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2733 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2734 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2735 if ((dot = DotProduct(n, v)) < 0)
2737 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2738 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2739 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2740 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2744 color4f[0] = ambientcolor[0] * distintensity;
2745 color4f[1] = ambientcolor[1] * distintensity;
2746 color4f[2] = ambientcolor[2] * distintensity;
2748 if (r_refdef.fogenabled)
2751 f = RSurf_FogVertex(vertex3f);
2752 VectorScale(color4f, f, color4f);
2756 VectorClear(color4f);
2762 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
2764 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2765 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2767 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2768 color4f[0] = ambientcolor[0] * distintensity;
2769 color4f[1] = ambientcolor[1] * distintensity;
2770 color4f[2] = ambientcolor[2] * distintensity;
2771 if (r_refdef.fogenabled)
2774 f = RSurf_FogVertex(vertex3f);
2775 VectorScale(color4f, f, color4f);
2779 VectorClear(color4f);
2789 static void R_Shadow_RenderLighting_VisibleLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
2791 // used to display how many times a surface is lit for level design purposes
2792 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
2793 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
2797 static void R_Shadow_RenderLighting_Light_GLSL(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale, float specularscale)
2799 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2800 R_SetupShader_Surface(lightcolor, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT, texturenumsurfaces, texturesurfacelist, NULL);
2801 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2802 GL_DepthFunc(GL_EQUAL);
2804 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2805 GL_DepthFunc(GL_LEQUAL);
2808 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
2815 int newnumtriangles;
2819 int maxtriangles = 4096;
2820 static int newelements[4096*3];
2821 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, diffusecolor2, ambientcolor2);
2822 for (renders = 0;renders < 4;renders++)
2827 newnumtriangles = 0;
2829 // due to low fillrate on the cards this vertex lighting path is
2830 // designed for, we manually cull all triangles that do not
2831 // contain a lit vertex
2832 // this builds batches of triangles from multiple surfaces and
2833 // renders them at once
2834 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
2836 if (VectorLength2(rsurface.passcolor4f + e[0] * 4) + VectorLength2(rsurface.passcolor4f + e[1] * 4) + VectorLength2(rsurface.passcolor4f + e[2] * 4) >= 0.01)
2838 if (newnumtriangles)
2840 newfirstvertex = min(newfirstvertex, e[0]);
2841 newlastvertex = max(newlastvertex, e[0]);
2845 newfirstvertex = e[0];
2846 newlastvertex = e[0];
2848 newfirstvertex = min(newfirstvertex, e[1]);
2849 newlastvertex = max(newlastvertex, e[1]);
2850 newfirstvertex = min(newfirstvertex, e[2]);
2851 newlastvertex = max(newlastvertex, e[2]);
2857 if (newnumtriangles >= maxtriangles)
2859 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
2860 newnumtriangles = 0;
2866 if (newnumtriangles >= 1)
2868 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
2871 // if we couldn't find any lit triangles, exit early
2874 // now reduce the intensity for the next overbright pass
2875 // we have to clamp to 0 here incase the drivers have improper
2876 // handling of negative colors
2877 // (some old drivers even have improper handling of >1 color)
2879 for (i = 0, c = rsurface.passcolor4f + 4 * firstvertex;i < numvertices;i++, c += 4)
2881 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
2883 c[0] = max(0, c[0] - 1);
2884 c[1] = max(0, c[1] - 1);
2885 c[2] = max(0, c[2] - 1);
2897 static void R_Shadow_RenderLighting_Light_Vertex(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale)
2899 // OpenGL 1.1 path (anything)
2900 float ambientcolorbase[3], diffusecolorbase[3];
2901 float ambientcolorpants[3], diffusecolorpants[3];
2902 float ambientcolorshirt[3], diffusecolorshirt[3];
2903 const float *surfacecolor = rsurface.texture->dlightcolor;
2904 const float *surfacepants = rsurface.colormap_pantscolor;
2905 const float *surfaceshirt = rsurface.colormap_shirtcolor;
2906 rtexture_t *basetexture = rsurface.texture->basetexture;
2907 rtexture_t *pantstexture = rsurface.texture->pantstexture;
2908 rtexture_t *shirttexture = rsurface.texture->shirttexture;
2909 qboolean dopants = pantstexture && VectorLength2(surfacepants) >= (1.0f / 1048576.0f);
2910 qboolean doshirt = shirttexture && VectorLength2(surfaceshirt) >= (1.0f / 1048576.0f);
2911 ambientscale *= 2 * r_refdef.view.colorscale;
2912 diffusescale *= 2 * r_refdef.view.colorscale;
2913 ambientcolorbase[0] = lightcolor[0] * ambientscale * surfacecolor[0];ambientcolorbase[1] = lightcolor[1] * ambientscale * surfacecolor[1];ambientcolorbase[2] = lightcolor[2] * ambientscale * surfacecolor[2];
2914 diffusecolorbase[0] = lightcolor[0] * diffusescale * surfacecolor[0];diffusecolorbase[1] = lightcolor[1] * diffusescale * surfacecolor[1];diffusecolorbase[2] = lightcolor[2] * diffusescale * surfacecolor[2];
2915 ambientcolorpants[0] = ambientcolorbase[0] * surfacepants[0];ambientcolorpants[1] = ambientcolorbase[1] * surfacepants[1];ambientcolorpants[2] = ambientcolorbase[2] * surfacepants[2];
2916 diffusecolorpants[0] = diffusecolorbase[0] * surfacepants[0];diffusecolorpants[1] = diffusecolorbase[1] * surfacepants[1];diffusecolorpants[2] = diffusecolorbase[2] * surfacepants[2];
2917 ambientcolorshirt[0] = ambientcolorbase[0] * surfaceshirt[0];ambientcolorshirt[1] = ambientcolorbase[1] * surfaceshirt[1];ambientcolorshirt[2] = ambientcolorbase[2] * surfaceshirt[2];
2918 diffusecolorshirt[0] = diffusecolorbase[0] * surfaceshirt[0];diffusecolorshirt[1] = diffusecolorbase[1] * surfaceshirt[1];diffusecolorshirt[2] = diffusecolorbase[2] * surfaceshirt[2];
2919 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | (diffusescale > 0 ? BATCHNEED_ARRAY_NORMAL : 0) | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
2920 rsurface.passcolor4f = (float *)R_FrameData_Alloc((rsurface.batchfirstvertex + rsurface.batchnumvertices) * sizeof(float[4]));
2921 R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
2922 R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.passcolor4f, 0, 0);
2923 R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
2924 R_Mesh_TexBind(0, basetexture);
2925 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
2926 R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
2927 switch(r_shadow_rendermode)
2929 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2930 R_Mesh_TexBind(1, r_shadow_attenuation3dtexture);
2931 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
2932 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
2933 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
2935 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2936 R_Mesh_TexBind(2, r_shadow_attenuation2dtexture);
2937 R_Mesh_TexMatrix(2, &rsurface.entitytoattenuationz);
2938 R_Mesh_TexCombine(2, GL_MODULATE, GL_MODULATE, 1, 1);
2939 R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
2941 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2942 R_Mesh_TexBind(1, r_shadow_attenuation2dtexture);
2943 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
2944 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
2945 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
2947 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2952 //R_Mesh_TexBind(0, basetexture);
2953 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorbase, ambientcolorbase);
2956 R_Mesh_TexBind(0, pantstexture);
2957 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorpants, ambientcolorpants);
2961 R_Mesh_TexBind(0, shirttexture);
2962 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorshirt, ambientcolorshirt);
2966 extern cvar_t gl_lightmaps;
2967 void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
2969 float ambientscale, diffusescale, specularscale;
2971 float lightcolor[3];
2972 VectorCopy(rsurface.rtlight->currentcolor, lightcolor);
2973 ambientscale = rsurface.rtlight->ambientscale;
2974 diffusescale = rsurface.rtlight->diffusescale;
2975 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
2976 if (!r_shadow_usenormalmap.integer)
2978 ambientscale += 1.0f * diffusescale;
2982 if ((ambientscale + diffusescale) * VectorLength2(lightcolor) + specularscale * VectorLength2(lightcolor) < (1.0f / 1048576.0f))
2984 negated = (lightcolor[0] + lightcolor[1] + lightcolor[2] < 0) && vid.support.ext_blend_subtract;
2987 VectorNegate(lightcolor, lightcolor);
2988 switch(vid.renderpath)
2990 case RENDERPATH_GL11:
2991 case RENDERPATH_GL13:
2992 case RENDERPATH_GL20:
2993 case RENDERPATH_GLES2:
2994 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
2996 case RENDERPATH_D3D9:
2998 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_SUBTRACT);
3001 case RENDERPATH_D3D10:
3002 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3004 case RENDERPATH_D3D11:
3005 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3007 case RENDERPATH_SOFT:
3008 DPSOFTRAST_BlendSubtract(true);
3012 RSurf_SetupDepthAndCulling();
3013 switch (r_shadow_rendermode)
3015 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
3016 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
3017 R_Shadow_RenderLighting_VisibleLighting(texturenumsurfaces, texturesurfacelist);
3019 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
3020 R_Shadow_RenderLighting_Light_GLSL(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale, specularscale);
3022 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
3023 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
3024 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
3025 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3026 R_Shadow_RenderLighting_Light_Vertex(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale);
3029 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
3034 switch(vid.renderpath)
3036 case RENDERPATH_GL11:
3037 case RENDERPATH_GL13:
3038 case RENDERPATH_GL20:
3039 case RENDERPATH_GLES2:
3040 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
3042 case RENDERPATH_D3D9:
3044 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_ADD);
3047 case RENDERPATH_D3D10:
3048 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3050 case RENDERPATH_D3D11:
3051 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3053 case RENDERPATH_SOFT:
3054 DPSOFTRAST_BlendSubtract(false);
3060 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)
3062 matrix4x4_t tempmatrix = *matrix;
3063 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
3065 // if this light has been compiled before, free the associated data
3066 R_RTLight_Uncompile(rtlight);
3068 // clear it completely to avoid any lingering data
3069 memset(rtlight, 0, sizeof(*rtlight));
3071 // copy the properties
3072 rtlight->matrix_lighttoworld = tempmatrix;
3073 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
3074 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
3075 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
3076 VectorCopy(color, rtlight->color);
3077 rtlight->cubemapname[0] = 0;
3078 if (cubemapname && cubemapname[0])
3079 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
3080 rtlight->shadow = shadow;
3081 rtlight->corona = corona;
3082 rtlight->style = style;
3083 rtlight->isstatic = isstatic;
3084 rtlight->coronasizescale = coronasizescale;
3085 rtlight->ambientscale = ambientscale;
3086 rtlight->diffusescale = diffusescale;
3087 rtlight->specularscale = specularscale;
3088 rtlight->flags = flags;
3090 // compute derived data
3091 //rtlight->cullradius = rtlight->radius;
3092 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
3093 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3094 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3095 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3096 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3097 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3098 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3101 // compiles rtlight geometry
3102 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
3103 void R_RTLight_Compile(rtlight_t *rtlight)
3106 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
3107 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
3108 entity_render_t *ent = r_refdef.scene.worldentity;
3109 dp_model_t *model = r_refdef.scene.worldmodel;
3110 unsigned char *data;
3113 // compile the light
3114 rtlight->compiled = true;
3115 rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
3116 rtlight->static_numleafs = 0;
3117 rtlight->static_numleafpvsbytes = 0;
3118 rtlight->static_leaflist = NULL;
3119 rtlight->static_leafpvs = NULL;
3120 rtlight->static_numsurfaces = 0;
3121 rtlight->static_surfacelist = NULL;
3122 rtlight->static_shadowmap_receivers = 0x3F;
3123 rtlight->static_shadowmap_casters = 0x3F;
3124 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3125 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3126 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3127 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3128 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3129 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3131 if (model && model->GetLightInfo)
3133 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
3134 r_shadow_compilingrtlight = rtlight;
3135 R_FrameData_SetMark();
3136 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);
3137 R_FrameData_ReturnToMark();
3138 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
3139 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
3140 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3141 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
3142 rtlight->static_numsurfaces = numsurfaces;
3143 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
3144 rtlight->static_numleafs = numleafs;
3145 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
3146 rtlight->static_numleafpvsbytes = numleafpvsbytes;
3147 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
3148 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
3149 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
3150 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
3151 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3152 if (rtlight->static_numsurfaces)
3153 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3154 if (rtlight->static_numleafs)
3155 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3156 if (rtlight->static_numleafpvsbytes)
3157 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3158 if (rtlight->static_numshadowtrispvsbytes)
3159 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3160 if (rtlight->static_numlighttrispvsbytes)
3161 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3162 R_FrameData_SetMark();
3163 switch (rtlight->shadowmode)
3165 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
3166 if (model->CompileShadowMap && rtlight->shadow)
3167 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3170 if (model->CompileShadowVolume && rtlight->shadow)
3171 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3174 R_FrameData_ReturnToMark();
3175 // now we're done compiling the rtlight
3176 r_shadow_compilingrtlight = NULL;
3180 // use smallest available cullradius - box radius or light radius
3181 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3182 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3184 shadowzpasstris = 0;
3185 if (rtlight->static_meshchain_shadow_zpass)
3186 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
3187 shadowzpasstris += mesh->numtriangles;
3189 shadowzfailtris = 0;
3190 if (rtlight->static_meshchain_shadow_zfail)
3191 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
3192 shadowzfailtris += mesh->numtriangles;
3195 if (rtlight->static_numlighttrispvsbytes)
3196 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3197 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3201 if (rtlight->static_numlighttrispvsbytes)
3202 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3203 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3206 if (developer_extra.integer)
3207 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);
3210 void R_RTLight_Uncompile(rtlight_t *rtlight)
3212 if (rtlight->compiled)
3214 if (rtlight->static_meshchain_shadow_zpass)
3215 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
3216 rtlight->static_meshchain_shadow_zpass = NULL;
3217 if (rtlight->static_meshchain_shadow_zfail)
3218 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
3219 rtlight->static_meshchain_shadow_zfail = NULL;
3220 if (rtlight->static_meshchain_shadow_shadowmap)
3221 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
3222 rtlight->static_meshchain_shadow_shadowmap = NULL;
3223 // these allocations are grouped
3224 if (rtlight->static_surfacelist)
3225 Mem_Free(rtlight->static_surfacelist);
3226 rtlight->static_numleafs = 0;
3227 rtlight->static_numleafpvsbytes = 0;
3228 rtlight->static_leaflist = NULL;
3229 rtlight->static_leafpvs = NULL;
3230 rtlight->static_numsurfaces = 0;
3231 rtlight->static_surfacelist = NULL;
3232 rtlight->static_numshadowtrispvsbytes = 0;
3233 rtlight->static_shadowtrispvs = NULL;
3234 rtlight->static_numlighttrispvsbytes = 0;
3235 rtlight->static_lighttrispvs = NULL;
3236 rtlight->compiled = false;
3240 void R_Shadow_UncompileWorldLights(void)
3244 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3245 for (lightindex = 0;lightindex < range;lightindex++)
3247 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3250 R_RTLight_Uncompile(&light->rtlight);
3254 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3258 // reset the count of frustum planes
3259 // see rtlight->cached_frustumplanes definition for how much this array
3261 rtlight->cached_numfrustumplanes = 0;
3263 // haven't implemented a culling path for ortho rendering
3264 if (!r_refdef.view.useperspective)
3266 // check if the light is on screen and copy the 4 planes if it is
3267 for (i = 0;i < 4;i++)
3268 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3271 for (i = 0;i < 4;i++)
3272 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3277 // generate a deformed frustum that includes the light origin, this is
3278 // used to cull shadow casting surfaces that can not possibly cast a
3279 // shadow onto the visible light-receiving surfaces, which can be a
3282 // if the light origin is onscreen the result will be 4 planes exactly
3283 // if the light origin is offscreen on only one axis the result will
3284 // be exactly 5 planes (split-side case)
3285 // if the light origin is offscreen on two axes the result will be
3286 // exactly 4 planes (stretched corner case)
3287 for (i = 0;i < 4;i++)
3289 // quickly reject standard frustum planes that put the light
3290 // origin outside the frustum
3291 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3294 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3296 // if all the standard frustum planes were accepted, the light is onscreen
3297 // otherwise we need to generate some more planes below...
3298 if (rtlight->cached_numfrustumplanes < 4)
3300 // at least one of the stock frustum planes failed, so we need to
3301 // create one or two custom planes to enclose the light origin
3302 for (i = 0;i < 4;i++)
3304 // create a plane using the view origin and light origin, and a
3305 // single point from the frustum corner set
3306 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3307 VectorNormalize(plane.normal);
3308 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3309 // see if this plane is backwards and flip it if so
3310 for (j = 0;j < 4;j++)
3311 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3315 VectorNegate(plane.normal, plane.normal);
3317 // flipped plane, test again to see if it is now valid
3318 for (j = 0;j < 4;j++)
3319 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3321 // if the plane is still not valid, then it is dividing the
3322 // frustum and has to be rejected
3326 // we have created a valid plane, compute extra info
3327 PlaneClassify(&plane);
3329 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3331 // if we've found 5 frustum planes then we have constructed a
3332 // proper split-side case and do not need to keep searching for
3333 // planes to enclose the light origin
3334 if (rtlight->cached_numfrustumplanes == 5)
3342 for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
3344 plane = rtlight->cached_frustumplanes[i];
3345 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));
3350 // now add the light-space box planes if the light box is rotated, as any
3351 // caster outside the oriented light box is irrelevant (even if it passed
3352 // the worldspace light box, which is axial)
3353 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3355 for (i = 0;i < 6;i++)
3359 v[i >> 1] = (i & 1) ? -1 : 1;
3360 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3361 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3362 plane.dist = VectorNormalizeLength(plane.normal);
3363 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3364 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3370 // add the world-space reduced box planes
3371 for (i = 0;i < 6;i++)
3373 VectorClear(plane.normal);
3374 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3375 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
3376 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3385 // reduce all plane distances to tightly fit the rtlight cull box, which
3387 VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3388 VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3389 VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3390 VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3391 VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3392 VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3393 VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3394 VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3395 oldnum = rtlight->cached_numfrustumplanes;
3396 rtlight->cached_numfrustumplanes = 0;
3397 for (j = 0;j < oldnum;j++)
3399 // find the nearest point on the box to this plane
3400 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
3401 for (i = 1;i < 8;i++)
3403 dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
3404 if (bestdist > dist)
3407 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);
3408 // if the nearest point is near or behind the plane, we want this
3409 // plane, otherwise the plane is useless as it won't cull anything
3410 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
3412 PlaneClassify(&rtlight->cached_frustumplanes[j]);
3413 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
3420 void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
3424 RSurf_ActiveWorldEntity();
3426 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3429 GL_CullFace(GL_NONE);
3430 mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3431 for (;mesh;mesh = mesh->next)
3433 if (!mesh->sidetotals[r_shadow_shadowmapside])
3435 r_refdef.stats.lights_shadowtriangles += mesh->sidetotals[r_shadow_shadowmapside];
3436 if (mesh->vertex3fbuffer)
3437 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vertex3fbuffer);
3439 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer);
3440 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);
3444 else if (r_refdef.scene.worldentity->model)
3445 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);
3447 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3450 void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3452 qboolean zpass = false;
3455 int surfacelistindex;
3456 msurface_t *surface;
3458 // if triangle neighbors are disabled, shadowvolumes are disabled
3459 if (r_refdef.scene.worldmodel->brush.shadowmesh ? !r_refdef.scene.worldmodel->brush.shadowmesh->neighbor3i : !r_refdef.scene.worldmodel->surfmesh.data_neighbor3i)
3462 RSurf_ActiveWorldEntity();
3464 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3467 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
3469 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
3470 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
3472 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
3473 for (;mesh;mesh = mesh->next)
3475 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
3476 if (mesh->vertex3fbuffer)
3477 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vertex3fbuffer);
3479 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer);
3480 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
3482 // increment stencil if frontface is infront of depthbuffer
3483 GL_CullFace(r_refdef.view.cullface_back);
3484 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
3485 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);
3486 // decrement stencil if backface is infront of depthbuffer
3487 GL_CullFace(r_refdef.view.cullface_front);
3488 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
3490 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
3492 // decrement stencil if backface is behind depthbuffer
3493 GL_CullFace(r_refdef.view.cullface_front);
3494 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
3495 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);
3496 // increment stencil if frontface is behind depthbuffer
3497 GL_CullFace(r_refdef.view.cullface_back);
3498 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
3500 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);
3504 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh)
3506 // use the shadow trispvs calculated earlier by GetLightInfo to cull world triangles on this dynamic light
3507 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
3508 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
3510 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
3511 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
3512 if (CHECKPVSBIT(trispvs, t))
3513 shadowmarklist[numshadowmark++] = t;
3515 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);
3517 else if (numsurfaces)
3519 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);
3522 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3525 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3527 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3528 vec_t relativeshadowradius;
3529 RSurf_ActiveModelEntity(ent, false, false, false);
3530 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3531 // we need to re-init the shader for each entity because the matrix changed
3532 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3533 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3534 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3535 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3536 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3537 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3538 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3539 switch (r_shadow_rendermode)
3541 case R_SHADOW_RENDERMODE_SHADOWMAP2D:
3542 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
3545 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3548 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3551 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3553 // set up properties for rendering light onto this entity
3554 RSurf_ActiveModelEntity(ent, true, true, false);
3555 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3556 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3557 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3558 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3561 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
3563 if (!r_refdef.scene.worldmodel->DrawLight)
3566 // set up properties for rendering light onto this entity
3567 RSurf_ActiveWorldEntity();
3568 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3569 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3570 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3571 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3573 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
3575 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3578 void R_Shadow_DrawEntityLight(entity_render_t *ent)
3580 dp_model_t *model = ent->model;
3581 if (!model->DrawLight)
3584 R_Shadow_SetupEntityLight(ent);
3586 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3588 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3591 void R_Shadow_PrepareLight(rtlight_t *rtlight)
3595 int numleafs, numsurfaces;
3596 int *leaflist, *surfacelist;
3597 unsigned char *leafpvs;
3598 unsigned char *shadowtrispvs;
3599 unsigned char *lighttrispvs;
3600 //unsigned char *surfacesides;
3601 int numlightentities;
3602 int numlightentities_noselfshadow;
3603 int numshadowentities;
3604 int numshadowentities_noselfshadow;
3605 static entity_render_t *lightentities[MAX_EDICTS];
3606 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3607 static entity_render_t *shadowentities[MAX_EDICTS];
3608 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3611 rtlight->draw = false;
3613 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3614 // skip lights that are basically invisible (color 0 0 0)
3615 nolight = VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f);
3617 // loading is done before visibility checks because loading should happen
3618 // all at once at the start of a level, not when it stalls gameplay.
3619 // (especially important to benchmarks)
3621 if (rtlight->isstatic && !nolight && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
3623 if (rtlight->compiled)
3624 R_RTLight_Uncompile(rtlight);
3625 R_RTLight_Compile(rtlight);
3629 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
3631 // look up the light style value at this time
3632 f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3633 VectorScale(rtlight->color, f, rtlight->currentcolor);
3635 if (rtlight->selected)
3637 f = 2 + sin(realtime * M_PI * 4.0);
3638 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3642 // if lightstyle is currently off, don't draw the light
3643 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3646 // skip processing on corona-only lights
3650 // if the light box is offscreen, skip it
3651 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3654 VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
3655 VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
3657 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3659 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3661 // compiled light, world available and can receive realtime lighting
3662 // retrieve leaf information
3663 numleafs = rtlight->static_numleafs;
3664 leaflist = rtlight->static_leaflist;
3665 leafpvs = rtlight->static_leafpvs;
3666 numsurfaces = rtlight->static_numsurfaces;
3667 surfacelist = rtlight->static_surfacelist;
3668 //surfacesides = NULL;
3669 shadowtrispvs = rtlight->static_shadowtrispvs;
3670 lighttrispvs = rtlight->static_lighttrispvs;
3672 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3674 // dynamic light, world available and can receive realtime lighting
3675 // calculate lit surfaces and leafs
3676 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);
3677 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3678 leaflist = r_shadow_buffer_leaflist;
3679 leafpvs = r_shadow_buffer_leafpvs;
3680 surfacelist = r_shadow_buffer_surfacelist;
3681 //surfacesides = r_shadow_buffer_surfacesides;
3682 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3683 lighttrispvs = r_shadow_buffer_lighttrispvs;
3684 // if the reduced leaf bounds are offscreen, skip it
3685 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3696 //surfacesides = NULL;
3697 shadowtrispvs = NULL;
3698 lighttrispvs = NULL;
3700 // check if light is illuminating any visible leafs
3703 for (i = 0;i < numleafs;i++)
3704 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3710 // make a list of lit entities and shadow casting entities
3711 numlightentities = 0;
3712 numlightentities_noselfshadow = 0;
3713 numshadowentities = 0;
3714 numshadowentities_noselfshadow = 0;
3716 // add dynamic entities that are lit by the light
3717 for (i = 0;i < r_refdef.scene.numentities;i++)
3720 entity_render_t *ent = r_refdef.scene.entities[i];
3722 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3724 // skip the object entirely if it is not within the valid
3725 // shadow-casting region (which includes the lit region)
3726 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
3728 if (!(model = ent->model))
3730 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
3732 // this entity wants to receive light, is visible, and is
3733 // inside the light box
3734 // TODO: check if the surfaces in the model can receive light
3735 // so now check if it's in a leaf seen by the light
3736 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))
3738 if (ent->flags & RENDER_NOSELFSHADOW)
3739 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
3741 lightentities[numlightentities++] = ent;
3742 // since it is lit, it probably also casts a shadow...
3743 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3744 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3745 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3747 // note: exterior models without the RENDER_NOSELFSHADOW
3748 // flag still create a RENDER_NOSELFSHADOW shadow but
3749 // are lit normally, this means that they are
3750 // self-shadowing but do not shadow other
3751 // RENDER_NOSELFSHADOW entities such as the gun
3752 // (very weird, but keeps the player shadow off the gun)
3753 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3754 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3756 shadowentities[numshadowentities++] = ent;
3759 else if (ent->flags & RENDER_SHADOW)
3761 // this entity is not receiving light, but may still need to
3763 // TODO: check if the surfaces in the model can cast shadow
3764 // now check if it is in a leaf seen by the light
3765 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))
3767 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3768 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3769 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3771 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3772 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3774 shadowentities[numshadowentities++] = ent;
3779 // return if there's nothing at all to light
3780 if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
3783 // count this light in the r_speeds
3784 r_refdef.stats.lights++;
3786 // flag it as worth drawing later
3787 rtlight->draw = true;
3789 // cache all the animated entities that cast a shadow but are not visible
3790 for (i = 0;i < numshadowentities;i++)
3791 if (!shadowentities[i]->animcache_vertex3f)
3792 R_AnimCache_GetEntity(shadowentities[i], false, false);
3793 for (i = 0;i < numshadowentities_noselfshadow;i++)
3794 if (!shadowentities_noselfshadow[i]->animcache_vertex3f)
3795 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
3797 // allocate some temporary memory for rendering this light later in the frame
3798 // reusable buffers need to be copied, static data can be used as-is
3799 rtlight->cached_numlightentities = numlightentities;
3800 rtlight->cached_numlightentities_noselfshadow = numlightentities_noselfshadow;
3801 rtlight->cached_numshadowentities = numshadowentities;
3802 rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
3803 rtlight->cached_numsurfaces = numsurfaces;
3804 rtlight->cached_lightentities = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
3805 rtlight->cached_lightentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
3806 rtlight->cached_shadowentities = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
3807 rtlight->cached_shadowentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
3808 if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
3810 int numshadowtrispvsbytes = (((r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles) + 7) >> 3);
3811 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
3812 rtlight->cached_shadowtrispvs = (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
3813 rtlight->cached_lighttrispvs = (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
3814 rtlight->cached_surfacelist = (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
3818 // compiled light data
3819 rtlight->cached_shadowtrispvs = shadowtrispvs;
3820 rtlight->cached_lighttrispvs = lighttrispvs;
3821 rtlight->cached_surfacelist = surfacelist;
3825 void R_Shadow_DrawLight(rtlight_t *rtlight)
3829 unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
3830 int numlightentities;
3831 int numlightentities_noselfshadow;
3832 int numshadowentities;
3833 int numshadowentities_noselfshadow;
3834 entity_render_t **lightentities;
3835 entity_render_t **lightentities_noselfshadow;
3836 entity_render_t **shadowentities;
3837 entity_render_t **shadowentities_noselfshadow;
3839 static unsigned char entitysides[MAX_EDICTS];
3840 static unsigned char entitysides_noselfshadow[MAX_EDICTS];
3841 vec3_t nearestpoint;
3843 qboolean castshadows;
3846 // check if we cached this light this frame (meaning it is worth drawing)
3850 numlightentities = rtlight->cached_numlightentities;
3851 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
3852 numshadowentities = rtlight->cached_numshadowentities;
3853 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
3854 numsurfaces = rtlight->cached_numsurfaces;
3855 lightentities = rtlight->cached_lightentities;
3856 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
3857 shadowentities = rtlight->cached_shadowentities;
3858 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
3859 shadowtrispvs = rtlight->cached_shadowtrispvs;
3860 lighttrispvs = rtlight->cached_lighttrispvs;
3861 surfacelist = rtlight->cached_surfacelist;
3863 // set up a scissor rectangle for this light
3864 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3867 // don't let sound skip if going slow
3868 if (r_refdef.scene.extraupdate)
3871 // make this the active rtlight for rendering purposes
3872 R_Shadow_RenderMode_ActiveLight(rtlight);
3874 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
3876 // optionally draw visible shape of the shadow volumes
3877 // for performance analysis by level designers
3878 R_Shadow_RenderMode_VisibleShadowVolumes();
3880 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
3881 for (i = 0;i < numshadowentities;i++)
3882 R_Shadow_DrawEntityShadow(shadowentities[i]);
3883 for (i = 0;i < numshadowentities_noselfshadow;i++)
3884 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3885 R_Shadow_RenderMode_VisibleLighting(false, false);
3888 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
3890 // optionally draw the illuminated areas
3891 // for performance analysis by level designers
3892 R_Shadow_RenderMode_VisibleLighting(false, false);
3894 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3895 for (i = 0;i < numlightentities;i++)
3896 R_Shadow_DrawEntityLight(lightentities[i]);
3897 for (i = 0;i < numlightentities_noselfshadow;i++)
3898 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3901 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
3903 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
3904 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
3905 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
3906 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
3908 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance/rtlight->radius));
3909 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
3910 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
3912 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
3918 int receivermask = 0;
3919 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
3920 Matrix4x4_Abs(&radiustolight);
3922 r_shadow_shadowmaplod = 0;
3923 for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
3924 if ((r_shadow_shadowmapmaxsize >> i) > lodlinear)
3925 r_shadow_shadowmaplod = i;
3927 size = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
3929 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
3931 surfacesides = NULL;
3934 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3936 castermask = rtlight->static_shadowmap_casters;
3937 receivermask = rtlight->static_shadowmap_receivers;
3941 surfacesides = r_shadow_buffer_surfacesides;
3942 for(i = 0;i < numsurfaces;i++)
3944 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
3945 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3946 castermask |= surfacesides[i];
3947 receivermask |= surfacesides[i];
3951 if (receivermask < 0x3F)
3953 for (i = 0;i < numlightentities;i++)
3954 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3955 if (receivermask < 0x3F)
3956 for(i = 0; i < numlightentities_noselfshadow;i++)
3957 receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3960 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
3964 for (i = 0;i < numshadowentities;i++)
3965 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3966 for (i = 0;i < numshadowentities_noselfshadow;i++)
3967 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3970 //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
3972 // render shadow casters into 6 sided depth texture
3973 for (side = 0;side < 6;side++) if (receivermask & (1 << side))
3975 R_Shadow_RenderMode_ShadowMap(side, receivermask, size);
3976 if (! (castermask & (1 << side))) continue;
3978 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
3979 for (i = 0;i < numshadowentities;i++) if (entitysides[i] & (1 << side))
3980 R_Shadow_DrawEntityShadow(shadowentities[i]);
3983 if (numlightentities_noselfshadow)
3985 // render lighting using the depth texture as shadowmap
3986 // draw lighting in the unmasked areas
3987 R_Shadow_RenderMode_Lighting(false, false, true);
3988 for (i = 0;i < numlightentities_noselfshadow;i++)
3989 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3992 // render shadow casters into 6 sided depth texture
3993 if (numshadowentities_noselfshadow)
3995 for (side = 0;side < 6;side++) if ((receivermask & castermask) & (1 << side))
3997 R_Shadow_RenderMode_ShadowMap(side, 0, size);
3998 for (i = 0;i < numshadowentities_noselfshadow;i++) if (entitysides_noselfshadow[i] & (1 << side))
3999 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
4003 // render lighting using the depth texture as shadowmap
4004 // draw lighting in the unmasked areas
4005 R_Shadow_RenderMode_Lighting(false, false, true);
4006 // draw lighting in the unmasked areas
4008 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4009 for (i = 0;i < numlightentities;i++)
4010 R_Shadow_DrawEntityLight(lightentities[i]);
4012 else if (castshadows && vid.stencil)
4014 // draw stencil shadow volumes to mask off pixels that are in shadow
4015 // so that they won't receive lighting
4016 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
4017 R_Shadow_ClearStencil();
4020 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
4021 for (i = 0;i < numshadowentities;i++)
4022 R_Shadow_DrawEntityShadow(shadowentities[i]);
4024 // draw lighting in the unmasked areas
4025 R_Shadow_RenderMode_Lighting(true, false, false);
4026 for (i = 0;i < numlightentities_noselfshadow;i++)
4027 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4029 for (i = 0;i < numshadowentities_noselfshadow;i++)
4030 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
4032 // draw lighting in the unmasked areas
4033 R_Shadow_RenderMode_Lighting(true, false, false);
4035 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4036 for (i = 0;i < numlightentities;i++)
4037 R_Shadow_DrawEntityLight(lightentities[i]);
4041 // draw lighting in the unmasked areas
4042 R_Shadow_RenderMode_Lighting(false, false, false);
4044 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4045 for (i = 0;i < numlightentities;i++)
4046 R_Shadow_DrawEntityLight(lightentities[i]);
4047 for (i = 0;i < numlightentities_noselfshadow;i++)
4048 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4051 if (r_shadow_usingdeferredprepass)
4053 // when rendering deferred lighting, we simply rasterize the box
4054 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
4055 R_Shadow_RenderMode_DrawDeferredLight(false, true);
4056 else if (castshadows && vid.stencil)
4057 R_Shadow_RenderMode_DrawDeferredLight(true, false);
4059 R_Shadow_RenderMode_DrawDeferredLight(false, false);
4063 static void R_Shadow_FreeDeferred(void)
4065 R_Mesh_DestroyFramebufferObject(r_shadow_prepassgeometryfbo);
4066 r_shadow_prepassgeometryfbo = 0;
4068 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusespecularfbo);
4069 r_shadow_prepasslightingdiffusespecularfbo = 0;
4071 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusefbo);
4072 r_shadow_prepasslightingdiffusefbo = 0;
4074 if (r_shadow_prepassgeometrydepthtexture)
4075 R_FreeTexture(r_shadow_prepassgeometrydepthtexture);
4076 r_shadow_prepassgeometrydepthtexture = NULL;
4078 if (r_shadow_prepassgeometrydepthcolortexture)
4079 R_FreeTexture(r_shadow_prepassgeometrydepthcolortexture);
4080 r_shadow_prepassgeometrydepthcolortexture = NULL;
4082 if (r_shadow_prepassgeometrynormalmaptexture)
4083 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
4084 r_shadow_prepassgeometrynormalmaptexture = NULL;
4086 if (r_shadow_prepasslightingdiffusetexture)
4087 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
4088 r_shadow_prepasslightingdiffusetexture = NULL;
4090 if (r_shadow_prepasslightingspeculartexture)
4091 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
4092 r_shadow_prepasslightingspeculartexture = NULL;
4095 void R_Shadow_DrawPrepass(void)
4103 entity_render_t *ent;
4104 float clearcolor[4];
4106 R_Mesh_ResetTextureState();
4108 GL_ColorMask(1,1,1,1);
4109 GL_BlendFunc(GL_ONE, GL_ZERO);
4112 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, r_shadow_prepassgeometrydepthcolortexture, NULL, NULL);
4113 Vector4Set(clearcolor, 0.5f,0.5f,0.5f,1.0f);
4114 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4115 if (r_timereport_active)
4116 R_TimeReport("prepasscleargeom");
4118 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
4119 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
4120 if (r_timereport_active)
4121 R_TimeReport("prepassworld");
4123 for (i = 0;i < r_refdef.scene.numentities;i++)
4125 if (!r_refdef.viewcache.entityvisible[i])
4127 ent = r_refdef.scene.entities[i];
4128 if (ent->model && ent->model->DrawPrepass != NULL)
4129 ent->model->DrawPrepass(ent);
4132 if (r_timereport_active)
4133 R_TimeReport("prepassmodels");
4135 GL_DepthMask(false);
4136 GL_ColorMask(1,1,1,1);
4139 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4140 Vector4Set(clearcolor, 0, 0, 0, 0);
4141 GL_Clear(GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
4142 if (r_timereport_active)
4143 R_TimeReport("prepassclearlit");
4145 R_Shadow_RenderMode_Begin();
4147 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4148 if (r_shadow_debuglight.integer >= 0)
4150 lightindex = r_shadow_debuglight.integer;
4151 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4152 if (light && (light->flags & flag) && light->rtlight.draw)
4153 R_Shadow_DrawLight(&light->rtlight);
4157 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4158 for (lightindex = 0;lightindex < range;lightindex++)
4160 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4161 if (light && (light->flags & flag) && light->rtlight.draw)
4162 R_Shadow_DrawLight(&light->rtlight);
4165 if (r_refdef.scene.rtdlight)
4166 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4167 if (r_refdef.scene.lights[lnum]->draw)
4168 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4170 R_Mesh_ResetRenderTargets();
4172 R_Shadow_RenderMode_End();
4174 if (r_timereport_active)
4175 R_TimeReport("prepasslights");
4178 void R_Shadow_DrawLightSprites(void);
4179 void R_Shadow_PrepareLights(void)
4189 if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4) ||
4190 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
4191 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20) ||
4192 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
4193 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
4194 r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
4195 R_Shadow_FreeShadowMaps();
4197 r_shadow_usingshadowmaportho = false;
4199 switch (vid.renderpath)
4201 case RENDERPATH_GL20:
4202 case RENDERPATH_D3D9:
4203 case RENDERPATH_D3D10:
4204 case RENDERPATH_D3D11:
4205 case RENDERPATH_SOFT:
4206 case RENDERPATH_GLES2:
4207 if (!r_shadow_deferred.integer || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_STENCIL || !vid.support.ext_framebuffer_object || vid.maxdrawbuffers < 2)
4209 r_shadow_usingdeferredprepass = false;
4210 if (r_shadow_prepass_width)
4211 R_Shadow_FreeDeferred();
4212 r_shadow_prepass_width = r_shadow_prepass_height = 0;
4216 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
4218 R_Shadow_FreeDeferred();
4220 r_shadow_usingdeferredprepass = true;
4221 r_shadow_prepass_width = vid.width;
4222 r_shadow_prepass_height = vid.height;
4223 r_shadow_prepassgeometrydepthtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "prepassgeometrydepthmap", vid.width, vid.height, 24, false);
4224 switch (vid.renderpath)
4226 case RENDERPATH_D3D9:
4227 r_shadow_prepassgeometrydepthcolortexture = R_LoadTexture2D(r_shadow_texturepool, "prepassgeometrydepthcolormap", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, -1, NULL);
4232 r_shadow_prepassgeometrynormalmaptexture = R_LoadTexture2D(r_shadow_texturepool, "prepassgeometrynormalmap", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, -1, NULL);
4233 r_shadow_prepasslightingdiffusetexture = R_LoadTexture2D(r_shadow_texturepool, "prepasslightingdiffuse", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, -1, NULL);
4234 r_shadow_prepasslightingspeculartexture = R_LoadTexture2D(r_shadow_texturepool, "prepasslightingspecular", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, -1, NULL);
4236 // set up the geometry pass fbo (depth + normalmap)
4237 r_shadow_prepassgeometryfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4238 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, r_shadow_prepassgeometrydepthcolortexture, NULL, NULL);
4239 // render depth into one texture and normalmap into the other
4240 if (qglDrawBuffersARB)
4242 qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);CHECKGLERROR
4243 qglReadBuffer(GL_NONE);CHECKGLERROR
4244 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4245 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4247 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4248 Cvar_SetValueQuick(&r_shadow_deferred, 0);
4249 r_shadow_usingdeferredprepass = false;
4253 // set up the lighting pass fbo (diffuse + specular)
4254 r_shadow_prepasslightingdiffusespecularfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4255 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4256 // render diffuse into one texture and specular into another,
4257 // with depth and normalmap bound as textures,
4258 // with depth bound as attachment as well
4259 if (qglDrawBuffersARB)
4261 qglDrawBuffersARB(2, r_shadow_prepasslightingdrawbuffers);CHECKGLERROR
4262 qglReadBuffer(GL_NONE);CHECKGLERROR
4263 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4264 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4266 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4267 Cvar_SetValueQuick(&r_shadow_deferred, 0);
4268 r_shadow_usingdeferredprepass = false;
4272 // set up the lighting pass fbo (diffuse)
4273 r_shadow_prepasslightingdiffusefbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
4274 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
4275 // render diffuse into one texture,
4276 // with depth and normalmap bound as textures,
4277 // with depth bound as attachment as well
4278 if (qglDrawBuffersARB)
4280 qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);CHECKGLERROR
4281 qglReadBuffer(GL_NONE);CHECKGLERROR
4282 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4283 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4285 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4286 Cvar_SetValueQuick(&r_shadow_deferred, 0);
4287 r_shadow_usingdeferredprepass = false;
4292 case RENDERPATH_GL13:
4293 case RENDERPATH_GL11:
4294 r_shadow_usingdeferredprepass = false;
4298 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);
4300 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4301 if (r_shadow_debuglight.integer >= 0)
4303 lightindex = r_shadow_debuglight.integer;
4304 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4305 if (light && (light->flags & flag))
4306 R_Shadow_PrepareLight(&light->rtlight);
4310 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4311 for (lightindex = 0;lightindex < range;lightindex++)
4313 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4314 if (light && (light->flags & flag))
4315 R_Shadow_PrepareLight(&light->rtlight);
4318 if (r_refdef.scene.rtdlight)
4320 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4321 R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
4323 else if(gl_flashblend.integer)
4325 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4327 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
4328 f = (rtlight->style >= 0 ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4329 VectorScale(rtlight->color, f, rtlight->currentcolor);
4333 if (r_editlights.integer)
4334 R_Shadow_DrawLightSprites();
4336 R_Shadow_UpdateBounceGridTexture();
4339 void R_Shadow_DrawLights(void)
4347 R_Shadow_RenderMode_Begin();
4349 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4350 if (r_shadow_debuglight.integer >= 0)
4352 lightindex = r_shadow_debuglight.integer;
4353 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4354 if (light && (light->flags & flag))
4355 R_Shadow_DrawLight(&light->rtlight);
4359 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4360 for (lightindex = 0;lightindex < range;lightindex++)
4362 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4363 if (light && (light->flags & flag))
4364 R_Shadow_DrawLight(&light->rtlight);
4367 if (r_refdef.scene.rtdlight)
4368 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4369 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4371 R_Shadow_RenderMode_End();
4374 extern const float r_screenvertex3f[12];
4375 extern void R_SetupView(qboolean allowwaterclippingplane);
4376 extern void R_ResetViewRendering3D(void);
4377 extern void R_ResetViewRendering2D(void);
4378 extern cvar_t r_shadows;
4379 extern cvar_t r_shadows_darken;
4380 extern cvar_t r_shadows_drawafterrtlighting;
4381 extern cvar_t r_shadows_castfrombmodels;
4382 extern cvar_t r_shadows_throwdistance;
4383 extern cvar_t r_shadows_throwdirection;
4384 extern cvar_t r_shadows_focus;
4385 extern cvar_t r_shadows_shadowmapscale;
4387 void R_Shadow_PrepareModelShadows(void)
4390 float scale, size, radius, dot1, dot2;
4391 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
4392 entity_render_t *ent;
4394 if (!r_refdef.scene.numentities)
4397 switch (r_shadow_shadowmode)
4399 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4400 if (r_shadows.integer >= 2)
4403 case R_SHADOW_SHADOWMODE_STENCIL:
4404 for (i = 0;i < r_refdef.scene.numentities;i++)
4406 ent = r_refdef.scene.entities[i];
4407 if (!ent->animcache_vertex3f && ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4408 R_AnimCache_GetEntity(ent, false, false);
4415 size = 2*r_shadow_shadowmapmaxsize;
4416 scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
4417 radius = 0.5f * size / scale;
4419 Math_atov(r_shadows_throwdirection.string, shadowdir);
4420 VectorNormalize(shadowdir);
4421 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4422 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4423 if (fabs(dot1) <= fabs(dot2))
4424 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4426 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4427 VectorNormalize(shadowforward);
4428 CrossProduct(shadowdir, shadowforward, shadowright);
4429 Math_atov(r_shadows_focus.string, shadowfocus);
4430 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4431 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4432 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4433 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4434 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4436 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4438 shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4439 shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4440 shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4441 shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4442 shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4443 shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4445 for (i = 0;i < r_refdef.scene.numentities;i++)
4447 ent = r_refdef.scene.entities[i];
4448 if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
4450 // cast shadows from anything of the map (submodels are optional)
4451 if (!ent->animcache_vertex3f && ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4452 R_AnimCache_GetEntity(ent, false, false);
4456 void R_DrawModelShadowMaps(void)
4459 float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
4460 entity_render_t *ent;
4461 vec3_t relativelightorigin;
4462 vec3_t relativelightdirection, relativeforward, relativeright;
4463 vec3_t relativeshadowmins, relativeshadowmaxs;
4464 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
4466 matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
4467 r_viewport_t viewport;
4469 float clearcolor[4];
4471 if (!r_refdef.scene.numentities)
4474 switch (r_shadow_shadowmode)
4476 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4482 R_ResetViewRendering3D();
4483 R_Shadow_RenderMode_Begin();
4484 R_Shadow_RenderMode_ActiveLight(NULL);
4486 switch (r_shadow_shadowmode)
4488 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4489 if (!r_shadow_shadowmap2dtexture)
4490 R_Shadow_MakeShadowMap(0, r_shadow_shadowmapmaxsize);
4491 fbo = r_shadow_fbo2d;
4492 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
4493 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
4494 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
4500 size = 2*r_shadow_shadowmapmaxsize;
4501 scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
4502 radius = 0.5f / scale;
4503 nearclip = -r_shadows_throwdistance.value;
4504 farclip = r_shadows_throwdistance.value;
4505 bias = r_shadow_shadowmapping_bias.value * r_shadow_shadowmapping_nearclip.value / (2 * r_shadows_throwdistance.value) * (1024.0f / size);
4507 r_shadow_shadowmap_parameters[0] = size;
4508 r_shadow_shadowmap_parameters[1] = size;
4509 r_shadow_shadowmap_parameters[2] = 1.0;
4510 r_shadow_shadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
4512 Math_atov(r_shadows_throwdirection.string, shadowdir);
4513 VectorNormalize(shadowdir);
4514 Math_atov(r_shadows_focus.string, shadowfocus);
4515 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4516 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4517 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4518 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4519 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4520 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4521 if (fabs(dot1) <= fabs(dot2))
4522 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4524 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4525 VectorNormalize(shadowforward);
4526 VectorM(scale, shadowforward, &m[0]);
4527 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4529 m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
4530 CrossProduct(shadowdir, shadowforward, shadowright);
4531 VectorM(scale, shadowright, &m[4]);
4532 m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
4533 VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
4534 m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
4535 Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
4536 Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
4537 R_Viewport_InitOrtho(&viewport, &cameramatrix, 0, 0, size, size, 0, 0, 1, 1, 0, -1, NULL);
4539 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4541 R_Mesh_SetRenderTargets(fbo, r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
4542 R_SetupShader_DepthOrShadow();
4543 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
4546 R_SetViewport(&viewport);
4547 GL_Scissor(viewport.x, viewport.y, min(viewport.width + r_shadow_shadowmapborder, 2*r_shadow_shadowmapmaxsize), viewport.height + r_shadow_shadowmapborder);
4548 Vector4Set(clearcolor, 1,1,1,1);
4549 // in D3D9 we have to render to a color texture shadowmap
4550 // in GL we render directly to a depth texture only
4551 if (r_shadow_shadowmap2dtexture)
4552 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4554 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4555 // render into a slightly restricted region so that the borders of the
4556 // shadowmap area fade away, rather than streaking across everything
4557 // outside the usable area
4558 GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
4562 R_Mesh_ResetRenderTargets();
4563 R_SetupShader_ShowDepth();
4564 GL_ColorMask(1,1,1,1);
4565 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4568 for (i = 0;i < r_refdef.scene.numentities;i++)
4570 ent = r_refdef.scene.entities[i];
4572 // cast shadows from anything of the map (submodels are optional)
4573 if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4575 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4576 Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
4577 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4578 Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
4579 Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
4580 relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4581 relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4582 relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4583 relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4584 relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4585 relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4586 RSurf_ActiveModelEntity(ent, false, false, false);
4587 ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
4588 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4595 unsigned char *rawpixels = Z_Malloc(viewport.width*viewport.height*4);
4597 qglReadPixels(viewport.x, viewport.y, viewport.width, viewport.height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, rawpixels);
4599 Image_WriteTGABGRA("r_shadows_2.tga", viewport.width, viewport.height, rawpixels);
4600 Cvar_SetValueQuick(&r_test, 0);
4605 R_Shadow_RenderMode_End();
4607 Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
4608 Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
4609 Matrix4x4_CreateScale3(&scalematrix, size, -size, 1);
4610 Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
4611 Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
4612 Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
4614 switch (vid.renderpath)
4616 case RENDERPATH_GL11:
4617 case RENDERPATH_GL13:
4618 case RENDERPATH_GL20:
4619 case RENDERPATH_SOFT:
4620 case RENDERPATH_GLES2:
4622 case RENDERPATH_D3D9:
4623 case RENDERPATH_D3D10:
4624 case RENDERPATH_D3D11:
4625 #ifdef OPENGL_ORIENTATION
4626 r_shadow_shadowmapmatrix.m[0][0] *= -1.0f;
4627 r_shadow_shadowmapmatrix.m[0][1] *= -1.0f;
4628 r_shadow_shadowmapmatrix.m[0][2] *= -1.0f;
4629 r_shadow_shadowmapmatrix.m[0][3] *= -1.0f;
4631 r_shadow_shadowmapmatrix.m[0][0] *= -1.0f;
4632 r_shadow_shadowmapmatrix.m[1][0] *= -1.0f;
4633 r_shadow_shadowmapmatrix.m[2][0] *= -1.0f;
4634 r_shadow_shadowmapmatrix.m[3][0] *= -1.0f;
4639 r_shadow_usingshadowmaportho = true;
4640 switch (r_shadow_shadowmode)
4642 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4643 r_shadow_usingshadowmap2d = true;
4650 void R_DrawModelShadows(void)
4653 float relativethrowdistance;
4654 entity_render_t *ent;
4655 vec3_t relativelightorigin;
4656 vec3_t relativelightdirection;
4657 vec3_t relativeshadowmins, relativeshadowmaxs;
4658 vec3_t tmp, shadowdir;
4660 if (!r_refdef.scene.numentities || !vid.stencil || (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL && r_shadows.integer != 1))
4663 R_ResetViewRendering3D();
4664 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4665 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4666 R_Shadow_RenderMode_Begin();
4667 R_Shadow_RenderMode_ActiveLight(NULL);
4668 r_shadow_lightscissor[0] = r_refdef.view.x;
4669 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
4670 r_shadow_lightscissor[2] = r_refdef.view.width;
4671 r_shadow_lightscissor[3] = r_refdef.view.height;
4672 R_Shadow_RenderMode_StencilShadowVolumes(false);
4675 if (r_shadows.integer == 2)
4677 Math_atov(r_shadows_throwdirection.string, shadowdir);
4678 VectorNormalize(shadowdir);
4681 R_Shadow_ClearStencil();
4683 for (i = 0;i < r_refdef.scene.numentities;i++)
4685 ent = r_refdef.scene.entities[i];
4687 // cast shadows from anything of the map (submodels are optional)
4688 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4690 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4691 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
4692 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
4693 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
4694 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4697 if(ent->entitynumber != 0)
4699 if(ent->entitynumber >= MAX_EDICTS) // csqc entity
4701 // FIXME handle this
4702 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4706 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
4707 int entnum, entnum2, recursion;
4708 entnum = entnum2 = ent->entitynumber;
4709 for(recursion = 32; recursion > 0; --recursion)
4711 entnum2 = cl.entities[entnum].state_current.tagentity;
4712 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
4717 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
4719 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
4720 // transform into modelspace of OUR entity
4721 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
4722 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
4725 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4729 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4732 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
4733 RSurf_ActiveModelEntity(ent, false, false, false);
4734 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4735 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4739 // not really the right mode, but this will disable any silly stencil features
4740 R_Shadow_RenderMode_End();
4742 // set up ortho view for rendering this pass
4743 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4744 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4745 //GL_ScissorTest(true);
4746 //R_EntityMatrix(&identitymatrix);
4747 //R_Mesh_ResetTextureState();
4748 R_ResetViewRendering2D();
4750 // set up a darkening blend on shadowed areas
4751 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4752 //GL_DepthRange(0, 1);
4753 //GL_DepthTest(false);
4754 //GL_DepthMask(false);
4755 //GL_PolygonOffset(0, 0);CHECKGLERROR
4756 GL_Color(0, 0, 0, r_shadows_darken.value);
4757 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4758 //GL_DepthFunc(GL_ALWAYS);
4759 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_NOTEQUAL, 128, 255);
4761 // apply the blend to the shadowed areas
4762 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, NULL);
4763 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
4764 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4766 // restore the viewport
4767 R_SetViewport(&r_refdef.view.viewport);
4769 // restore other state to normal
4770 //R_Shadow_RenderMode_End();
4773 void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4776 vec3_t centerorigin;
4778 // if it's too close, skip it
4779 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
4781 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4784 if (usequery && r_numqueries + 2 <= r_maxqueries)
4786 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4787 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4788 // 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
4789 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4791 switch(vid.renderpath)
4793 case RENDERPATH_GL20:
4794 case RENDERPATH_GL13:
4795 case RENDERPATH_GL11:
4796 case RENDERPATH_GLES2:
4798 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use GL_DepthFunc instead
4799 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
4800 GL_DepthFunc(GL_ALWAYS);
4801 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4802 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL);
4803 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4804 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4805 GL_DepthFunc(GL_LEQUAL);
4806 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
4807 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4808 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL);
4809 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4810 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4813 case RENDERPATH_D3D9:
4814 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4816 case RENDERPATH_D3D10:
4817 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4819 case RENDERPATH_D3D11:
4820 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4822 case RENDERPATH_SOFT:
4823 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4827 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4830 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
4832 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4835 GLint allpixels = 0, visiblepixels = 0;
4836 // now we have to check the query result
4837 if (rtlight->corona_queryindex_visiblepixels)
4839 switch(vid.renderpath)
4841 case RENDERPATH_GL20:
4842 case RENDERPATH_GL13:
4843 case RENDERPATH_GL11:
4844 case RENDERPATH_GLES2:
4846 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
4847 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
4850 case RENDERPATH_D3D9:
4851 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4853 case RENDERPATH_D3D10:
4854 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4856 case RENDERPATH_D3D11:
4857 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4859 case RENDERPATH_SOFT:
4860 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4863 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
4864 if (visiblepixels < 1 || allpixels < 1)
4866 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
4867 cscale *= rtlight->corona_visibility;
4871 // FIXME: these traces should scan all render entities instead of cl.world
4872 if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
4875 VectorScale(rtlight->currentcolor, cscale, color);
4876 if (VectorLength(color) > (1.0f / 256.0f))
4879 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
4882 VectorNegate(color, color);
4883 switch(vid.renderpath)
4885 case RENDERPATH_GL11:
4886 case RENDERPATH_GL13:
4887 case RENDERPATH_GL20:
4888 case RENDERPATH_GLES2:
4889 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
4891 case RENDERPATH_D3D9:
4893 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_SUBTRACT);
4896 case RENDERPATH_D3D10:
4897 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4899 case RENDERPATH_D3D11:
4900 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4902 case RENDERPATH_SOFT:
4903 DPSOFTRAST_BlendSubtract(true);
4907 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4908 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);
4909 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4912 switch(vid.renderpath)
4914 case RENDERPATH_GL11:
4915 case RENDERPATH_GL13:
4916 case RENDERPATH_GL20:
4917 case RENDERPATH_GLES2:
4918 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
4920 case RENDERPATH_D3D9:
4922 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_ADD);
4925 case RENDERPATH_D3D10:
4926 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4928 case RENDERPATH_D3D11:
4929 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4931 case RENDERPATH_SOFT:
4932 DPSOFTRAST_BlendSubtract(false);
4939 void R_Shadow_DrawCoronas(void)
4942 qboolean usequery = false;
4947 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4949 if (r_waterstate.renderingscene)
4951 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4952 R_EntityMatrix(&identitymatrix);
4954 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4956 // check occlusion of coronas
4957 // use GL_ARB_occlusion_query if available
4958 // otherwise use raytraces
4960 switch (vid.renderpath)
4962 case RENDERPATH_GL11:
4963 case RENDERPATH_GL13:
4964 case RENDERPATH_GL20:
4965 case RENDERPATH_GLES2:
4966 usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
4969 GL_ColorMask(0,0,0,0);
4970 if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
4971 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
4974 r_maxqueries = (range + r_refdef.scene.numlights) * 4;
4975 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
4977 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
4980 RSurf_ActiveWorldEntity();
4981 GL_BlendFunc(GL_ONE, GL_ZERO);
4982 GL_CullFace(GL_NONE);
4983 GL_DepthMask(false);
4984 GL_DepthRange(0, 1);
4985 GL_PolygonOffset(0, 0);
4987 R_Mesh_ResetTextureState();
4988 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
4991 case RENDERPATH_D3D9:
4993 //Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4995 case RENDERPATH_D3D10:
4996 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4998 case RENDERPATH_D3D11:
4999 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5001 case RENDERPATH_SOFT:
5003 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
5006 for (lightindex = 0;lightindex < range;lightindex++)
5008 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5011 rtlight = &light->rtlight;
5012 rtlight->corona_visibility = 0;
5013 rtlight->corona_queryindex_visiblepixels = 0;
5014 rtlight->corona_queryindex_allpixels = 0;
5015 if (!(rtlight->flags & flag))
5017 if (rtlight->corona <= 0)
5019 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
5021 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
5023 for (i = 0;i < r_refdef.scene.numlights;i++)
5025 rtlight = r_refdef.scene.lights[i];
5026 rtlight->corona_visibility = 0;
5027 rtlight->corona_queryindex_visiblepixels = 0;
5028 rtlight->corona_queryindex_allpixels = 0;
5029 if (!(rtlight->flags & flag))
5031 if (rtlight->corona <= 0)
5033 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
5036 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
5038 // now draw the coronas using the query data for intensity info
5039 for (lightindex = 0;lightindex < range;lightindex++)
5041 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5044 rtlight = &light->rtlight;
5045 if (rtlight->corona_visibility <= 0)
5047 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
5049 for (i = 0;i < r_refdef.scene.numlights;i++)
5051 rtlight = r_refdef.scene.lights[i];
5052 if (rtlight->corona_visibility <= 0)
5054 if (gl_flashblend.integer)
5055 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
5057 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
5063 dlight_t *R_Shadow_NewWorldLight(void)
5065 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
5068 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)
5071 // validate parameters
5072 if (style < 0 || style >= MAX_LIGHTSTYLES)
5074 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
5080 // copy to light properties
5081 VectorCopy(origin, light->origin);
5082 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
5083 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
5084 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
5086 light->color[0] = max(color[0], 0);
5087 light->color[1] = max(color[1], 0);
5088 light->color[2] = max(color[2], 0);
5090 light->color[0] = color[0];
5091 light->color[1] = color[1];
5092 light->color[2] = color[2];
5093 light->radius = max(radius, 0);
5094 light->style = style;
5095 light->shadow = shadowenable;
5096 light->corona = corona;
5097 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
5098 light->coronasizescale = coronasizescale;
5099 light->ambientscale = ambientscale;
5100 light->diffusescale = diffusescale;
5101 light->specularscale = specularscale;
5102 light->flags = flags;
5104 // update renderable light data
5105 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
5106 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);
5109 void R_Shadow_FreeWorldLight(dlight_t *light)
5111 if (r_shadow_selectedlight == light)
5112 r_shadow_selectedlight = NULL;
5113 R_RTLight_Uncompile(&light->rtlight);
5114 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
5117 void R_Shadow_ClearWorldLights(void)
5121 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5122 for (lightindex = 0;lightindex < range;lightindex++)
5124 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5126 R_Shadow_FreeWorldLight(light);
5128 r_shadow_selectedlight = NULL;
5131 void R_Shadow_SelectLight(dlight_t *light)
5133 if (r_shadow_selectedlight)
5134 r_shadow_selectedlight->selected = false;
5135 r_shadow_selectedlight = light;
5136 if (r_shadow_selectedlight)
5137 r_shadow_selectedlight->selected = true;
5140 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
5142 // this is never batched (there can be only one)
5144 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
5145 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
5146 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5149 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
5154 skinframe_t *skinframe;
5157 // this is never batched (due to the ent parameter changing every time)
5158 // so numsurfaces == 1 and surfacelist[0] == lightnumber
5159 const dlight_t *light = (dlight_t *)ent;
5162 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
5165 VectorScale(light->color, intensity, spritecolor);
5166 if (VectorLength(spritecolor) < 0.1732f)
5167 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
5168 if (VectorLength(spritecolor) > 1.0f)
5169 VectorNormalize(spritecolor);
5171 // draw light sprite
5172 if (light->cubemapname[0] && !light->shadow)
5173 skinframe = r_editlights_sprcubemapnoshadowlight;
5174 else if (light->cubemapname[0])
5175 skinframe = r_editlights_sprcubemaplight;
5176 else if (!light->shadow)
5177 skinframe = r_editlights_sprnoshadowlight;
5179 skinframe = r_editlights_sprlight;
5181 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);
5182 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5184 // draw selection sprite if light is selected
5185 if (light->selected)
5187 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
5188 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5189 // VorteX todo: add normalmode/realtime mode light overlay sprites?
5193 void R_Shadow_DrawLightSprites(void)
5197 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5198 for (lightindex = 0;lightindex < range;lightindex++)
5200 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5202 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
5204 if (!r_editlights_lockcursor)
5205 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
5208 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
5213 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
5214 if (lightindex >= range)
5216 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5219 rtlight = &light->rtlight;
5220 //if (!(rtlight->flags & flag))
5222 VectorCopy(rtlight->shadoworigin, origin);
5223 *radius = rtlight->radius;
5224 VectorCopy(rtlight->color, color);
5228 void R_Shadow_SelectLightInView(void)
5230 float bestrating, rating, temp[3];
5234 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5238 if (r_editlights_lockcursor)
5240 for (lightindex = 0;lightindex < range;lightindex++)
5242 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5245 VectorSubtract(light->origin, r_refdef.view.origin, temp);
5246 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
5249 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
5250 if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1.0f)
5252 bestrating = rating;
5257 R_Shadow_SelectLight(best);
5260 void R_Shadow_LoadWorldLights(void)
5262 int n, a, style, shadow, flags;
5263 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
5264 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
5265 if (cl.worldmodel == NULL)
5267 Con_Print("No map loaded.\n");
5270 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
5271 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5281 for (;COM_Parse(t, true) && strcmp(
5282 if (COM_Parse(t, true))
5284 if (com_token[0] == '!')
5287 origin[0] = atof(com_token+1);
5290 origin[0] = atof(com_token);
5295 while (*s && *s != '\n' && *s != '\r')
5301 // check for modifier flags
5308 #if _MSC_VER >= 1400
5309 #define sscanf sscanf_s
5311 cubemapname[sizeof(cubemapname)-1] = 0;
5312 #if MAX_QPATH != 128
5313 #error update this code if MAX_QPATH changes
5315 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
5316 #if _MSC_VER >= 1400
5317 , sizeof(cubemapname)
5319 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
5322 flags = LIGHTFLAG_REALTIMEMODE;
5330 coronasizescale = 0.25f;
5332 VectorClear(angles);
5335 if (a < 9 || !strcmp(cubemapname, "\"\""))
5337 // remove quotes on cubemapname
5338 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
5341 namelen = strlen(cubemapname) - 2;
5342 memmove(cubemapname, cubemapname + 1, namelen);
5343 cubemapname[namelen] = '\0';
5347 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);
5350 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5358 Con_Printf("invalid rtlights file \"%s\"\n", name);
5359 Mem_Free(lightsstring);
5363 void R_Shadow_SaveWorldLights(void)
5367 size_t bufchars, bufmaxchars;
5369 char name[MAX_QPATH];
5370 char line[MAX_INPUTLINE];
5371 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
5372 // I hate lines which are 3 times my screen size :( --blub
5375 if (cl.worldmodel == NULL)
5377 Con_Print("No map loaded.\n");
5380 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
5381 bufchars = bufmaxchars = 0;
5383 for (lightindex = 0;lightindex < range;lightindex++)
5385 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5388 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
5389 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);
5390 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
5391 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]);
5393 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);
5394 if (bufchars + strlen(line) > bufmaxchars)
5396 bufmaxchars = bufchars + strlen(line) + 2048;
5398 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
5402 memcpy(buf, oldbuf, bufchars);
5408 memcpy(buf + bufchars, line, strlen(line));
5409 bufchars += strlen(line);
5413 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
5418 void R_Shadow_LoadLightsFile(void)
5421 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
5422 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
5423 if (cl.worldmodel == NULL)
5425 Con_Print("No map loaded.\n");
5428 dpsnprintf(name, sizeof(name), "%s.lights", cl.worldnamenoextension);
5429 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5437 while (*s && *s != '\n' && *s != '\r')
5443 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);
5447 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);
5450 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
5451 radius = bound(15, radius, 4096);
5452 VectorScale(color, (2.0f / (8388608.0f)), color);
5453 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5461 Con_Printf("invalid lights file \"%s\"\n", name);
5462 Mem_Free(lightsstring);
5466 // tyrlite/hmap2 light types in the delay field
5467 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
5469 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
5481 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
5482 char key[256], value[MAX_INPUTLINE];
5484 if (cl.worldmodel == NULL)
5486 Con_Print("No map loaded.\n");
5489 // try to load a .ent file first
5490 dpsnprintf(key, sizeof(key), "%s.ent", cl.worldnamenoextension);
5491 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
5492 // and if that is not found, fall back to the bsp file entity string
5494 data = cl.worldmodel->brush.entities;
5497 for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
5499 type = LIGHTTYPE_MINUSX;
5500 origin[0] = origin[1] = origin[2] = 0;
5501 originhack[0] = originhack[1] = originhack[2] = 0;
5502 angles[0] = angles[1] = angles[2] = 0;
5503 color[0] = color[1] = color[2] = 1;
5504 light[0] = light[1] = light[2] = 1;light[3] = 300;
5505 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
5515 if (!COM_ParseToken_Simple(&data, false, false))
5517 if (com_token[0] == '}')
5518 break; // end of entity
5519 if (com_token[0] == '_')
5520 strlcpy(key, com_token + 1, sizeof(key));
5522 strlcpy(key, com_token, sizeof(key));
5523 while (key[strlen(key)-1] == ' ') // remove trailing spaces
5524 key[strlen(key)-1] = 0;
5525 if (!COM_ParseToken_Simple(&data, false, false))
5527 strlcpy(value, com_token, sizeof(value));
5529 // now that we have the key pair worked out...
5530 if (!strcmp("light", key))
5532 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5536 light[0] = vec[0] * (1.0f / 256.0f);
5537 light[1] = vec[0] * (1.0f / 256.0f);
5538 light[2] = vec[0] * (1.0f / 256.0f);
5544 light[0] = vec[0] * (1.0f / 255.0f);
5545 light[1] = vec[1] * (1.0f / 255.0f);
5546 light[2] = vec[2] * (1.0f / 255.0f);
5550 else if (!strcmp("delay", key))
5552 else if (!strcmp("origin", key))
5553 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5554 else if (!strcmp("angle", key))
5555 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5556 else if (!strcmp("angles", key))
5557 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5558 else if (!strcmp("color", key))
5559 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5560 else if (!strcmp("wait", key))
5561 fadescale = atof(value);
5562 else if (!strcmp("classname", key))
5564 if (!strncmp(value, "light", 5))
5567 if (!strcmp(value, "light_fluoro"))
5572 overridecolor[0] = 1;
5573 overridecolor[1] = 1;
5574 overridecolor[2] = 1;
5576 if (!strcmp(value, "light_fluorospark"))
5581 overridecolor[0] = 1;
5582 overridecolor[1] = 1;
5583 overridecolor[2] = 1;
5585 if (!strcmp(value, "light_globe"))
5590 overridecolor[0] = 1;
5591 overridecolor[1] = 0.8;
5592 overridecolor[2] = 0.4;
5594 if (!strcmp(value, "light_flame_large_yellow"))
5599 overridecolor[0] = 1;
5600 overridecolor[1] = 0.5;
5601 overridecolor[2] = 0.1;
5603 if (!strcmp(value, "light_flame_small_yellow"))
5608 overridecolor[0] = 1;
5609 overridecolor[1] = 0.5;
5610 overridecolor[2] = 0.1;
5612 if (!strcmp(value, "light_torch_small_white"))
5617 overridecolor[0] = 1;
5618 overridecolor[1] = 0.5;
5619 overridecolor[2] = 0.1;
5621 if (!strcmp(value, "light_torch_small_walltorch"))
5626 overridecolor[0] = 1;
5627 overridecolor[1] = 0.5;
5628 overridecolor[2] = 0.1;
5632 else if (!strcmp("style", key))
5633 style = atoi(value);
5634 else if (!strcmp("skin", key))
5635 skin = (int)atof(value);
5636 else if (!strcmp("pflags", key))
5637 pflags = (int)atof(value);
5638 //else if (!strcmp("effects", key))
5639 // effects = (int)atof(value);
5640 else if (cl.worldmodel->type == mod_brushq3)
5642 if (!strcmp("scale", key))
5643 lightscale = atof(value);
5644 if (!strcmp("fade", key))
5645 fadescale = atof(value);
5650 if (lightscale <= 0)
5654 if (color[0] == color[1] && color[0] == color[2])
5656 color[0] *= overridecolor[0];
5657 color[1] *= overridecolor[1];
5658 color[2] *= overridecolor[2];
5660 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5661 color[0] = color[0] * light[0];
5662 color[1] = color[1] * light[1];
5663 color[2] = color[2] * light[2];
5666 case LIGHTTYPE_MINUSX:
5668 case LIGHTTYPE_RECIPX:
5670 VectorScale(color, (1.0f / 16.0f), color);
5672 case LIGHTTYPE_RECIPXX:
5674 VectorScale(color, (1.0f / 16.0f), color);
5677 case LIGHTTYPE_NONE:
5681 case LIGHTTYPE_MINUSXX:
5684 VectorAdd(origin, originhack, origin);
5686 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, (pflags & PFLAGS_CORONA) != 0, style, (pflags & PFLAGS_NOSHADOW) == 0, skin >= 16 ? va("cubemaps/%i", skin) : NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5689 Mem_Free(entfiledata);
5693 void R_Shadow_SetCursorLocationForView(void)
5696 vec3_t dest, endpos;
5698 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5699 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
5700 if (trace.fraction < 1)
5702 dist = trace.fraction * r_editlights_cursordistance.value;
5703 push = r_editlights_cursorpushback.value;
5707 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5708 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5712 VectorClear( endpos );
5714 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5715 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5716 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5719 void R_Shadow_UpdateWorldLightSelection(void)
5721 if (r_editlights.integer)
5723 R_Shadow_SetCursorLocationForView();
5724 R_Shadow_SelectLightInView();
5727 R_Shadow_SelectLight(NULL);
5730 void R_Shadow_EditLights_Clear_f(void)
5732 R_Shadow_ClearWorldLights();
5735 void R_Shadow_EditLights_Reload_f(void)
5739 strlcpy(r_shadow_mapname, cl.worldname, sizeof(r_shadow_mapname));
5740 R_Shadow_ClearWorldLights();
5741 R_Shadow_LoadWorldLights();
5742 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5744 R_Shadow_LoadLightsFile();
5745 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5746 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5750 void R_Shadow_EditLights_Save_f(void)
5754 R_Shadow_SaveWorldLights();
5757 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
5759 R_Shadow_ClearWorldLights();
5760 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5763 void R_Shadow_EditLights_ImportLightsFile_f(void)
5765 R_Shadow_ClearWorldLights();
5766 R_Shadow_LoadLightsFile();
5769 void R_Shadow_EditLights_Spawn_f(void)
5772 if (!r_editlights.integer)
5774 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5777 if (Cmd_Argc() != 1)
5779 Con_Print("r_editlights_spawn does not take parameters\n");
5782 color[0] = color[1] = color[2] = 1;
5783 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5786 void R_Shadow_EditLights_Edit_f(void)
5788 vec3_t origin, angles, color;
5789 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5790 int style, shadows, flags, normalmode, realtimemode;
5791 char cubemapname[MAX_INPUTLINE];
5792 if (!r_editlights.integer)
5794 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5797 if (!r_shadow_selectedlight)
5799 Con_Print("No selected light.\n");
5802 VectorCopy(r_shadow_selectedlight->origin, origin);
5803 VectorCopy(r_shadow_selectedlight->angles, angles);
5804 VectorCopy(r_shadow_selectedlight->color, color);
5805 radius = r_shadow_selectedlight->radius;
5806 style = r_shadow_selectedlight->style;
5807 if (r_shadow_selectedlight->cubemapname)
5808 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5811 shadows = r_shadow_selectedlight->shadow;
5812 corona = r_shadow_selectedlight->corona;
5813 coronasizescale = r_shadow_selectedlight->coronasizescale;
5814 ambientscale = r_shadow_selectedlight->ambientscale;
5815 diffusescale = r_shadow_selectedlight->diffusescale;
5816 specularscale = r_shadow_selectedlight->specularscale;
5817 flags = r_shadow_selectedlight->flags;
5818 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5819 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5820 if (!strcmp(Cmd_Argv(1), "origin"))
5822 if (Cmd_Argc() != 5)
5824 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5827 origin[0] = atof(Cmd_Argv(2));
5828 origin[1] = atof(Cmd_Argv(3));
5829 origin[2] = atof(Cmd_Argv(4));
5831 else if (!strcmp(Cmd_Argv(1), "originx"))
5833 if (Cmd_Argc() != 3)
5835 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5838 origin[0] = atof(Cmd_Argv(2));
5840 else if (!strcmp(Cmd_Argv(1), "originy"))
5842 if (Cmd_Argc() != 3)
5844 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5847 origin[1] = atof(Cmd_Argv(2));
5849 else if (!strcmp(Cmd_Argv(1), "originz"))
5851 if (Cmd_Argc() != 3)
5853 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5856 origin[2] = atof(Cmd_Argv(2));
5858 else if (!strcmp(Cmd_Argv(1), "move"))
5860 if (Cmd_Argc() != 5)
5862 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5865 origin[0] += atof(Cmd_Argv(2));
5866 origin[1] += atof(Cmd_Argv(3));
5867 origin[2] += atof(Cmd_Argv(4));
5869 else if (!strcmp(Cmd_Argv(1), "movex"))
5871 if (Cmd_Argc() != 3)
5873 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5876 origin[0] += atof(Cmd_Argv(2));
5878 else if (!strcmp(Cmd_Argv(1), "movey"))
5880 if (Cmd_Argc() != 3)
5882 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5885 origin[1] += atof(Cmd_Argv(2));
5887 else if (!strcmp(Cmd_Argv(1), "movez"))
5889 if (Cmd_Argc() != 3)
5891 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5894 origin[2] += atof(Cmd_Argv(2));
5896 else if (!strcmp(Cmd_Argv(1), "angles"))
5898 if (Cmd_Argc() != 5)
5900 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5903 angles[0] = atof(Cmd_Argv(2));
5904 angles[1] = atof(Cmd_Argv(3));
5905 angles[2] = atof(Cmd_Argv(4));
5907 else if (!strcmp(Cmd_Argv(1), "anglesx"))
5909 if (Cmd_Argc() != 3)
5911 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5914 angles[0] = atof(Cmd_Argv(2));
5916 else if (!strcmp(Cmd_Argv(1), "anglesy"))
5918 if (Cmd_Argc() != 3)
5920 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5923 angles[1] = atof(Cmd_Argv(2));
5925 else if (!strcmp(Cmd_Argv(1), "anglesz"))
5927 if (Cmd_Argc() != 3)
5929 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5932 angles[2] = atof(Cmd_Argv(2));
5934 else if (!strcmp(Cmd_Argv(1), "color"))
5936 if (Cmd_Argc() != 5)
5938 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
5941 color[0] = atof(Cmd_Argv(2));
5942 color[1] = atof(Cmd_Argv(3));
5943 color[2] = atof(Cmd_Argv(4));
5945 else if (!strcmp(Cmd_Argv(1), "radius"))
5947 if (Cmd_Argc() != 3)
5949 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5952 radius = atof(Cmd_Argv(2));
5954 else if (!strcmp(Cmd_Argv(1), "colorscale"))
5956 if (Cmd_Argc() == 3)
5958 double scale = atof(Cmd_Argv(2));
5965 if (Cmd_Argc() != 5)
5967 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
5970 color[0] *= atof(Cmd_Argv(2));
5971 color[1] *= atof(Cmd_Argv(3));
5972 color[2] *= atof(Cmd_Argv(4));
5975 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
5977 if (Cmd_Argc() != 3)
5979 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5982 radius *= atof(Cmd_Argv(2));
5984 else if (!strcmp(Cmd_Argv(1), "style"))
5986 if (Cmd_Argc() != 3)
5988 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5991 style = atoi(Cmd_Argv(2));
5993 else if (!strcmp(Cmd_Argv(1), "cubemap"))
5997 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6000 if (Cmd_Argc() == 3)
6001 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
6005 else if (!strcmp(Cmd_Argv(1), "shadows"))
6007 if (Cmd_Argc() != 3)
6009 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6012 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
6014 else if (!strcmp(Cmd_Argv(1), "corona"))
6016 if (Cmd_Argc() != 3)
6018 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6021 corona = atof(Cmd_Argv(2));
6023 else if (!strcmp(Cmd_Argv(1), "coronasize"))
6025 if (Cmd_Argc() != 3)
6027 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6030 coronasizescale = atof(Cmd_Argv(2));
6032 else if (!strcmp(Cmd_Argv(1), "ambient"))
6034 if (Cmd_Argc() != 3)
6036 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6039 ambientscale = atof(Cmd_Argv(2));
6041 else if (!strcmp(Cmd_Argv(1), "diffuse"))
6043 if (Cmd_Argc() != 3)
6045 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6048 diffusescale = atof(Cmd_Argv(2));
6050 else if (!strcmp(Cmd_Argv(1), "specular"))
6052 if (Cmd_Argc() != 3)
6054 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6057 specularscale = atof(Cmd_Argv(2));
6059 else if (!strcmp(Cmd_Argv(1), "normalmode"))
6061 if (Cmd_Argc() != 3)
6063 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6066 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
6068 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
6070 if (Cmd_Argc() != 3)
6072 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6075 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
6079 Con_Print("usage: r_editlights_edit [property] [value]\n");
6080 Con_Print("Selected light's properties:\n");
6081 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
6082 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
6083 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
6084 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
6085 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
6086 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
6087 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
6088 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
6089 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
6090 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
6091 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
6092 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
6093 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
6094 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
6097 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
6098 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
6101 void R_Shadow_EditLights_EditAll_f(void)
6104 dlight_t *light, *oldselected;
6107 if (!r_editlights.integer)
6109 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
6113 oldselected = r_shadow_selectedlight;
6114 // EditLights doesn't seem to have a "remove" command or something so:
6115 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6116 for (lightindex = 0;lightindex < range;lightindex++)
6118 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6121 R_Shadow_SelectLight(light);
6122 R_Shadow_EditLights_Edit_f();
6124 // return to old selected (to not mess editing once selection is locked)
6125 R_Shadow_SelectLight(oldselected);
6128 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
6130 int lightnumber, lightcount;
6131 size_t lightindex, range;
6135 if (!r_editlights.integer)
6137 x = vid_conwidth.value - 240;
6139 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
6142 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6143 for (lightindex = 0;lightindex < range;lightindex++)
6145 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6148 if (light == r_shadow_selectedlight)
6149 lightnumber = lightindex;
6152 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;
6153 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;
6155 if (r_shadow_selectedlight == NULL)
6157 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;
6158 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;
6159 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;
6160 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;
6161 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;
6162 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;
6163 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;
6164 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;
6165 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;
6166 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;
6167 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;
6168 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;
6169 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;
6170 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;
6171 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;
6174 void R_Shadow_EditLights_ToggleShadow_f(void)
6176 if (!r_editlights.integer)
6178 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6181 if (!r_shadow_selectedlight)
6183 Con_Print("No selected light.\n");
6186 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);
6189 void R_Shadow_EditLights_ToggleCorona_f(void)
6191 if (!r_editlights.integer)
6193 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6196 if (!r_shadow_selectedlight)
6198 Con_Print("No selected light.\n");
6201 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);
6204 void R_Shadow_EditLights_Remove_f(void)
6206 if (!r_editlights.integer)
6208 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
6211 if (!r_shadow_selectedlight)
6213 Con_Print("No selected light.\n");
6216 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
6217 r_shadow_selectedlight = NULL;
6220 void R_Shadow_EditLights_Help_f(void)
6223 "Documentation on r_editlights system:\n"
6225 "r_editlights : enable/disable editing mode\n"
6226 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
6227 "r_editlights_cursorpushback : push back cursor this far from surface\n"
6228 "r_editlights_cursorpushoff : push cursor off surface this far\n"
6229 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
6230 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
6232 "r_editlights_help : this help\n"
6233 "r_editlights_clear : remove all lights\n"
6234 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
6235 "r_editlights_lock : lock selection to current light, if already locked - unlock\n"
6236 "r_editlights_save : save to .rtlights file\n"
6237 "r_editlights_spawn : create a light with default settings\n"
6238 "r_editlights_edit command : edit selected light - more documentation below\n"
6239 "r_editlights_remove : remove selected light\n"
6240 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
6241 "r_editlights_importlightentitiesfrommap : reload light entities\n"
6242 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
6244 "origin x y z : set light location\n"
6245 "originx x: set x component of light location\n"
6246 "originy y: set y component of light location\n"
6247 "originz z: set z component of light location\n"
6248 "move x y z : adjust light location\n"
6249 "movex x: adjust x component of light location\n"
6250 "movey y: adjust y component of light location\n"
6251 "movez z: adjust z component of light location\n"
6252 "angles x y z : set light angles\n"
6253 "anglesx x: set x component of light angles\n"
6254 "anglesy y: set y component of light angles\n"
6255 "anglesz z: set z component of light angles\n"
6256 "color r g b : set color of light (can be brighter than 1 1 1)\n"
6257 "radius radius : set radius (size) of light\n"
6258 "colorscale grey : multiply color of light (1 does nothing)\n"
6259 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
6260 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
6261 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
6262 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
6263 "cubemap basename : set filter cubemap of light (not yet supported)\n"
6264 "shadows 1/0 : turn on/off shadows\n"
6265 "corona n : set corona intensity\n"
6266 "coronasize n : set corona size (0-1)\n"
6267 "ambient n : set ambient intensity (0-1)\n"
6268 "diffuse n : set diffuse intensity (0-1)\n"
6269 "specular n : set specular intensity (0-1)\n"
6270 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
6271 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
6272 "<nothing> : print light properties to console\n"
6276 void R_Shadow_EditLights_CopyInfo_f(void)
6278 if (!r_editlights.integer)
6280 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
6283 if (!r_shadow_selectedlight)
6285 Con_Print("No selected light.\n");
6288 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
6289 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
6290 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
6291 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
6292 if (r_shadow_selectedlight->cubemapname)
6293 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
6295 r_shadow_bufferlight.cubemapname[0] = 0;
6296 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
6297 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
6298 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
6299 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
6300 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
6301 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
6302 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
6305 void R_Shadow_EditLights_PasteInfo_f(void)
6307 if (!r_editlights.integer)
6309 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
6312 if (!r_shadow_selectedlight)
6314 Con_Print("No selected light.\n");
6317 R_Shadow_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);
6320 void R_Shadow_EditLights_Lock_f(void)
6322 if (!r_editlights.integer)
6324 Con_Print("Cannot lock on light when not in editing mode. Set r_editlights to 1.\n");
6327 if (r_editlights_lockcursor)
6329 r_editlights_lockcursor = false;
6332 if (!r_shadow_selectedlight)
6334 Con_Print("No selected light to lock on.\n");
6337 r_editlights_lockcursor = true;
6340 void R_Shadow_EditLights_Init(void)
6342 Cvar_RegisterVariable(&r_editlights);
6343 Cvar_RegisterVariable(&r_editlights_cursordistance);
6344 Cvar_RegisterVariable(&r_editlights_cursorpushback);
6345 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
6346 Cvar_RegisterVariable(&r_editlights_cursorgrid);
6347 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
6348 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
6349 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
6350 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)");
6351 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
6352 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
6353 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
6354 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)");
6355 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
6356 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
6357 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
6358 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
6359 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
6360 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
6361 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)");
6362 Cmd_AddCommand("r_editlights_lock", R_Shadow_EditLights_Lock_f, "lock selection to current light, if already locked - unlock");
6368 =============================================================================
6372 =============================================================================
6375 void R_CompleteLightPoint(vec3_t ambient, vec3_t diffuse, vec3_t lightdir, const vec3_t p, const int flags)
6377 int i, numlights, flag;
6380 float relativepoint[3];
6389 if (r_fullbright.integer)
6391 VectorSet(ambient, 1, 1, 1);
6392 VectorClear(diffuse);
6393 VectorClear(lightdir);
6397 if (flags & LP_LIGHTMAP)
6399 VectorSet(ambient, r_refdef.scene.ambient, r_refdef.scene.ambient, r_refdef.scene.ambient);
6400 VectorClear(diffuse);
6401 VectorClear(lightdir);
6402 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
6403 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambient, diffuse, lightdir);
6407 memset(sample, 0, sizeof(sample));
6408 VectorSet(sample, r_refdef.scene.ambient, r_refdef.scene.ambient, r_refdef.scene.ambient);
6410 if ((flags & LP_LIGHTMAP) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
6413 VectorClear(tempambient);
6415 VectorClear(relativepoint);
6416 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, tempambient, color, relativepoint);
6417 VectorScale(tempambient, r_refdef.lightmapintensity, tempambient);
6418 VectorScale(color, r_refdef.lightmapintensity, color);
6419 VectorAdd(sample, tempambient, sample);
6420 VectorMA(sample , 0.5f , color, sample );
6421 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
6422 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
6423 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
6424 // calculate a weighted average light direction as well
6425 intensity = VectorLength(color);
6426 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
6429 if (flags & LP_RTWORLD)
6431 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
6432 numlights = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
6433 for (i = 0; i < numlights; i++)
6435 dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
6438 light = &dlight->rtlight;
6439 if (!(light->flags & flag))
6442 lightradius2 = light->radius * light->radius;
6443 VectorSubtract(light->shadoworigin, p, relativepoint);
6444 dist2 = VectorLength2(relativepoint);
6445 if (dist2 >= lightradius2)
6447 dist = sqrt(dist2) / light->radius;
6448 intensity = min(1.0f, (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) * r_shadow_lightintensityscale.value;
6449 if (intensity <= 0.0f)
6451 if (light->shadow && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
6453 // scale down intensity to add to both ambient and diffuse
6454 //intensity *= 0.5f;
6455 VectorNormalize(relativepoint);
6456 VectorScale(light->currentcolor, intensity, color);
6457 VectorMA(sample , 0.5f , color, sample );
6458 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
6459 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
6460 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
6461 // calculate a weighted average light direction as well
6462 intensity *= VectorLength(color);
6463 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
6467 if (flags & LP_DYNLIGHT)
6470 for (i = 0;i < r_refdef.scene.numlights;i++)
6472 light = r_refdef.scene.lights[i];
6474 lightradius2 = light->radius * light->radius;
6475 VectorSubtract(light->shadoworigin, p, relativepoint);
6476 dist2 = VectorLength2(relativepoint);
6477 if (dist2 >= lightradius2)
6479 dist = sqrt(dist2) / light->radius;
6480 intensity = (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist) * r_shadow_lightintensityscale.value;
6481 if (intensity <= 0.0f)
6483 if (light->shadow && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
6485 // scale down intensity to add to both ambient and diffuse
6486 //intensity *= 0.5f;
6487 VectorNormalize(relativepoint);
6488 VectorScale(light->currentcolor, intensity, color);
6489 VectorMA(sample , 0.5f , color, sample );
6490 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
6491 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
6492 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
6493 // calculate a weighted average light direction as well
6494 intensity *= VectorLength(color);
6495 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
6499 // calculate the direction we'll use to reduce the sample to a directional light source
6500 VectorCopy(sample + 12, dir);
6501 //VectorSet(dir, sample[3] + sample[4] + sample[5], sample[6] + sample[7] + sample[8], sample[9] + sample[10] + sample[11]);
6502 VectorNormalize(dir);
6503 // extract the diffuse color along the chosen direction and scale it
6504 diffuse[0] = (dir[0]*sample[3] + dir[1]*sample[6] + dir[2]*sample[ 9] + sample[ 0]);
6505 diffuse[1] = (dir[0]*sample[4] + dir[1]*sample[7] + dir[2]*sample[10] + sample[ 1]);
6506 diffuse[2] = (dir[0]*sample[5] + dir[1]*sample[8] + dir[2]*sample[11] + sample[ 2]);
6507 // subtract some of diffuse from ambient
6508 VectorMA(sample, -0.333f, diffuse, ambient);
6509 // store the normalized lightdir
6510 VectorCopy(dir, lightdir);