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_particletrace = {CVAR_SAVE, "r_shadow_particletrace", "0", "perform particle tracing for indirect lighting (Global Illumination / radiosity), requires r_shadow_deferred 1, requires r_shadow_realtime_world 1, EXTREMELY SLOW"};
323 cvar_t r_shadow_particletrace_intensity = {CVAR_SAVE, "r_shadow_particletrace_intensity", "128", "overall brightness of particle traced radiosity"};
324 cvar_t r_shadow_particletrace_size = {CVAR_SAVE, "r_shadow_particletrace_size", "32", "particles produce bounce lights of this radius"};
325 cvar_t r_shadow_particletrace_radiusscale = {CVAR_SAVE, "r_shadow_particletrace_radiusscale", "1", "particles stop at this fraction of light radius"};
326 cvar_t r_shadow_particletrace_maxbounce = {CVAR_SAVE, "r_shadow_particletrace_maxbounce", "1", "maximum number of bounces for a particle (minimum is 1)"};
327 cvar_t r_shadow_particletrace_bounceintensity = {CVAR_SAVE, "r_shadow_particletrace_bounceintensity", "1", "amount of energy carried over after each bounce"};
328 cvar_t r_shadow_particletrace_particlespacing = {CVAR_SAVE, "r_shadow_particletrace_particlespacing", "0.25", "overlap setting in terms of particle size, this affects how many particles are used"};
329 cvar_t r_shadow_particletrace_updatepercentage = {CVAR_SAVE, "r_shadow_particletrace_updatepercentage", "0.01", "update this fraction of the particles of a light each frame (0 = best performance)"};
330 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "1", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
331 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"};
332 cvar_t r_coronas_occlusionquery = {CVAR_SAVE, "r_coronas_occlusionquery", "1", "use GL_ARB_occlusion_query extension if supported (fades coronas according to visibility)"};
333 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
334 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
335 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
336 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
337 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
338 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
339 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
340 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
341 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
343 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
344 #define ATTENTABLESIZE 256
345 // 1D gradient, 2D circle and 3D sphere attenuation textures
346 #define ATTEN1DSIZE 32
347 #define ATTEN2DSIZE 64
348 #define ATTEN3DSIZE 32
350 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
351 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
352 static float r_shadow_attentable[ATTENTABLESIZE+1];
354 rtlight_t *r_shadow_compilingrtlight;
355 static memexpandablearray_t r_shadow_worldlightsarray;
356 dlight_t *r_shadow_selectedlight;
357 dlight_t r_shadow_bufferlight;
358 vec3_t r_editlights_cursorlocation;
359 qboolean r_editlights_lockcursor;
361 extern int con_vislines;
363 void R_Shadow_UncompileWorldLights(void);
364 void R_Shadow_ClearWorldLights(void);
365 void R_Shadow_SaveWorldLights(void);
366 void R_Shadow_LoadWorldLights(void);
367 void R_Shadow_LoadLightsFile(void);
368 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
369 void R_Shadow_EditLights_Reload_f(void);
370 void R_Shadow_ValidateCvars(void);
371 static void R_Shadow_MakeTextures(void);
373 #define EDLIGHTSPRSIZE 8
374 skinframe_t *r_editlights_sprcursor;
375 skinframe_t *r_editlights_sprlight;
376 skinframe_t *r_editlights_sprnoshadowlight;
377 skinframe_t *r_editlights_sprcubemaplight;
378 skinframe_t *r_editlights_sprcubemapnoshadowlight;
379 skinframe_t *r_editlights_sprselection;
381 void R_Shadow_SetShadowMode(void)
383 r_shadow_shadowmapmaxsize = bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4);
384 r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20;
385 r_shadow_shadowmapfilterquality = r_shadow_shadowmapping_filterquality.integer;
386 r_shadow_shadowmapdepthbits = r_shadow_shadowmapping_depthbits.integer;
387 r_shadow_shadowmapborder = bound(0, r_shadow_shadowmapping_bordersize.integer, 16);
388 r_shadow_shadowmaplod = -1;
389 r_shadow_shadowmapsize = 0;
390 r_shadow_shadowmapsampler = false;
391 r_shadow_shadowmappcf = 0;
392 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
393 if ((r_shadow_shadowmapping.integer || r_shadow_deferred.integer) && vid.support.ext_framebuffer_object)
395 switch(vid.renderpath)
397 case RENDERPATH_GL20:
398 if(r_shadow_shadowmapfilterquality < 0)
400 if(vid.support.amd_texture_texture4 || vid.support.arb_texture_gather)
401 r_shadow_shadowmappcf = 1;
402 else if(strstr(gl_vendor, "NVIDIA") || strstr(gl_renderer, "Radeon HD"))
404 r_shadow_shadowmapsampler = vid.support.arb_shadow;
405 r_shadow_shadowmappcf = 1;
407 else if(strstr(gl_vendor, "ATI"))
408 r_shadow_shadowmappcf = 1;
410 r_shadow_shadowmapsampler = vid.support.arb_shadow;
414 switch (r_shadow_shadowmapfilterquality)
417 r_shadow_shadowmapsampler = vid.support.arb_shadow;
420 r_shadow_shadowmapsampler = vid.support.arb_shadow;
421 r_shadow_shadowmappcf = 1;
424 r_shadow_shadowmappcf = 1;
427 r_shadow_shadowmappcf = 2;
431 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
433 case RENDERPATH_D3D9:
434 case RENDERPATH_D3D10:
435 case RENDERPATH_D3D11:
436 case RENDERPATH_SOFT:
437 r_shadow_shadowmapsampler = false;
438 r_shadow_shadowmappcf = 1;
439 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
441 case RENDERPATH_GL13:
443 case RENDERPATH_GL11:
445 case RENDERPATH_GLES2:
451 qboolean R_Shadow_ShadowMappingEnabled(void)
453 switch (r_shadow_shadowmode)
455 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
462 void R_Shadow_FreeShadowMaps(void)
464 R_Shadow_SetShadowMode();
466 R_Mesh_DestroyFramebufferObject(r_shadow_fbo2d);
470 if (r_shadow_shadowmap2dtexture)
471 R_FreeTexture(r_shadow_shadowmap2dtexture);
472 r_shadow_shadowmap2dtexture = NULL;
474 if (r_shadow_shadowmap2dcolortexture)
475 R_FreeTexture(r_shadow_shadowmap2dcolortexture);
476 r_shadow_shadowmap2dcolortexture = NULL;
478 if (r_shadow_shadowmapvsdcttexture)
479 R_FreeTexture(r_shadow_shadowmapvsdcttexture);
480 r_shadow_shadowmapvsdcttexture = NULL;
483 void r_shadow_start(void)
485 // allocate vertex processing arrays
486 r_shadow_attenuationgradienttexture = NULL;
487 r_shadow_attenuation2dtexture = NULL;
488 r_shadow_attenuation3dtexture = NULL;
489 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
490 r_shadow_shadowmap2dtexture = NULL;
491 r_shadow_shadowmap2dcolortexture = NULL;
492 r_shadow_shadowmapvsdcttexture = NULL;
493 r_shadow_shadowmapmaxsize = 0;
494 r_shadow_shadowmapsize = 0;
495 r_shadow_shadowmaplod = 0;
496 r_shadow_shadowmapfilterquality = -1;
497 r_shadow_shadowmapdepthbits = 0;
498 r_shadow_shadowmapvsdct = false;
499 r_shadow_shadowmapsampler = false;
500 r_shadow_shadowmappcf = 0;
503 R_Shadow_FreeShadowMaps();
505 r_shadow_texturepool = NULL;
506 r_shadow_filters_texturepool = NULL;
507 R_Shadow_ValidateCvars();
508 R_Shadow_MakeTextures();
509 maxshadowtriangles = 0;
510 shadowelements = NULL;
511 maxshadowvertices = 0;
512 shadowvertex3f = NULL;
520 shadowmarklist = NULL;
525 shadowsideslist = NULL;
526 r_shadow_buffer_numleafpvsbytes = 0;
527 r_shadow_buffer_visitingleafpvs = NULL;
528 r_shadow_buffer_leafpvs = NULL;
529 r_shadow_buffer_leaflist = NULL;
530 r_shadow_buffer_numsurfacepvsbytes = 0;
531 r_shadow_buffer_surfacepvs = NULL;
532 r_shadow_buffer_surfacelist = NULL;
533 r_shadow_buffer_surfacesides = NULL;
534 r_shadow_buffer_numshadowtrispvsbytes = 0;
535 r_shadow_buffer_shadowtrispvs = NULL;
536 r_shadow_buffer_numlighttrispvsbytes = 0;
537 r_shadow_buffer_lighttrispvs = NULL;
539 r_shadow_usingdeferredprepass = false;
540 r_shadow_prepass_width = r_shadow_prepass_height = 0;
543 static void R_Shadow_FreeDeferred(void);
544 void r_shadow_shutdown(void)
547 R_Shadow_UncompileWorldLights();
549 R_Shadow_FreeShadowMaps();
551 r_shadow_usingdeferredprepass = false;
552 if (r_shadow_prepass_width)
553 R_Shadow_FreeDeferred();
554 r_shadow_prepass_width = r_shadow_prepass_height = 0;
557 r_shadow_attenuationgradienttexture = NULL;
558 r_shadow_attenuation2dtexture = NULL;
559 r_shadow_attenuation3dtexture = NULL;
560 R_FreeTexturePool(&r_shadow_texturepool);
561 R_FreeTexturePool(&r_shadow_filters_texturepool);
562 maxshadowtriangles = 0;
564 Mem_Free(shadowelements);
565 shadowelements = NULL;
567 Mem_Free(shadowvertex3f);
568 shadowvertex3f = NULL;
571 Mem_Free(vertexupdate);
574 Mem_Free(vertexremap);
580 Mem_Free(shadowmark);
583 Mem_Free(shadowmarklist);
584 shadowmarklist = NULL;
589 Mem_Free(shadowsides);
592 Mem_Free(shadowsideslist);
593 shadowsideslist = NULL;
594 r_shadow_buffer_numleafpvsbytes = 0;
595 if (r_shadow_buffer_visitingleafpvs)
596 Mem_Free(r_shadow_buffer_visitingleafpvs);
597 r_shadow_buffer_visitingleafpvs = NULL;
598 if (r_shadow_buffer_leafpvs)
599 Mem_Free(r_shadow_buffer_leafpvs);
600 r_shadow_buffer_leafpvs = NULL;
601 if (r_shadow_buffer_leaflist)
602 Mem_Free(r_shadow_buffer_leaflist);
603 r_shadow_buffer_leaflist = NULL;
604 r_shadow_buffer_numsurfacepvsbytes = 0;
605 if (r_shadow_buffer_surfacepvs)
606 Mem_Free(r_shadow_buffer_surfacepvs);
607 r_shadow_buffer_surfacepvs = NULL;
608 if (r_shadow_buffer_surfacelist)
609 Mem_Free(r_shadow_buffer_surfacelist);
610 r_shadow_buffer_surfacelist = NULL;
611 if (r_shadow_buffer_surfacesides)
612 Mem_Free(r_shadow_buffer_surfacesides);
613 r_shadow_buffer_surfacesides = NULL;
614 r_shadow_buffer_numshadowtrispvsbytes = 0;
615 if (r_shadow_buffer_shadowtrispvs)
616 Mem_Free(r_shadow_buffer_shadowtrispvs);
617 r_shadow_buffer_numlighttrispvsbytes = 0;
618 if (r_shadow_buffer_lighttrispvs)
619 Mem_Free(r_shadow_buffer_lighttrispvs);
622 void r_shadow_newmap(void)
624 if (r_shadow_lightcorona) R_SkinFrame_MarkUsed(r_shadow_lightcorona);
625 if (r_editlights_sprcursor) R_SkinFrame_MarkUsed(r_editlights_sprcursor);
626 if (r_editlights_sprlight) R_SkinFrame_MarkUsed(r_editlights_sprlight);
627 if (r_editlights_sprnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprnoshadowlight);
628 if (r_editlights_sprcubemaplight) R_SkinFrame_MarkUsed(r_editlights_sprcubemaplight);
629 if (r_editlights_sprcubemapnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprcubemapnoshadowlight);
630 if (r_editlights_sprselection) R_SkinFrame_MarkUsed(r_editlights_sprselection);
631 if (strncmp(cl.worldname, r_shadow_mapname, sizeof(r_shadow_mapname)))
632 R_Shadow_EditLights_Reload_f();
635 void R_Shadow_Init(void)
637 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
638 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
639 Cvar_RegisterVariable(&r_shadow_usebihculling);
640 Cvar_RegisterVariable(&r_shadow_usenormalmap);
641 Cvar_RegisterVariable(&r_shadow_debuglight);
642 Cvar_RegisterVariable(&r_shadow_deferred);
643 Cvar_RegisterVariable(&r_shadow_deferred_8bitrange);
644 // Cvar_RegisterVariable(&r_shadow_deferred_fp);
645 Cvar_RegisterVariable(&r_shadow_gloss);
646 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
647 Cvar_RegisterVariable(&r_shadow_glossintensity);
648 Cvar_RegisterVariable(&r_shadow_glossexponent);
649 Cvar_RegisterVariable(&r_shadow_gloss2exponent);
650 Cvar_RegisterVariable(&r_shadow_glossexact);
651 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
652 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
653 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
654 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
655 Cvar_RegisterVariable(&r_shadow_projectdistance);
656 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
657 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
658 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
659 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
660 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
661 Cvar_RegisterVariable(&r_shadow_realtime_world);
662 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
663 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
664 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
665 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
666 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
667 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
668 Cvar_RegisterVariable(&r_shadow_scissor);
669 Cvar_RegisterVariable(&r_shadow_shadowmapping);
670 Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
671 Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
672 Cvar_RegisterVariable(&r_shadow_shadowmapping_depthbits);
673 Cvar_RegisterVariable(&r_shadow_shadowmapping_precision);
674 Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
675 Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
676 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
677 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
678 Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
679 Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
680 Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
681 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonfactor);
682 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonoffset);
683 Cvar_RegisterVariable(&r_shadow_sortsurfaces);
684 Cvar_RegisterVariable(&r_shadow_polygonfactor);
685 Cvar_RegisterVariable(&r_shadow_polygonoffset);
686 Cvar_RegisterVariable(&r_shadow_texture3d);
687 Cvar_RegisterVariable(&r_shadow_particletrace);
688 Cvar_RegisterVariable(&r_shadow_particletrace_intensity);
689 Cvar_RegisterVariable(&r_shadow_particletrace_size);
690 Cvar_RegisterVariable(&r_shadow_particletrace_radiusscale);
691 Cvar_RegisterVariable(&r_shadow_particletrace_maxbounce);
692 Cvar_RegisterVariable(&r_shadow_particletrace_bounceintensity);
693 Cvar_RegisterVariable(&r_shadow_particletrace_particlespacing);
694 Cvar_RegisterVariable(&r_shadow_particletrace_updatepercentage);
695 Cvar_RegisterVariable(&r_coronas);
696 Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
697 Cvar_RegisterVariable(&r_coronas_occlusionquery);
698 Cvar_RegisterVariable(&gl_flashblend);
699 Cvar_RegisterVariable(&gl_ext_separatestencil);
700 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
701 if (gamemode == GAME_TENEBRAE)
703 Cvar_SetValue("r_shadow_gloss", 2);
704 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
706 R_Shadow_EditLights_Init();
707 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
708 maxshadowtriangles = 0;
709 shadowelements = NULL;
710 maxshadowvertices = 0;
711 shadowvertex3f = NULL;
719 shadowmarklist = NULL;
724 shadowsideslist = NULL;
725 r_shadow_buffer_numleafpvsbytes = 0;
726 r_shadow_buffer_visitingleafpvs = NULL;
727 r_shadow_buffer_leafpvs = NULL;
728 r_shadow_buffer_leaflist = NULL;
729 r_shadow_buffer_numsurfacepvsbytes = 0;
730 r_shadow_buffer_surfacepvs = NULL;
731 r_shadow_buffer_surfacelist = NULL;
732 r_shadow_buffer_surfacesides = NULL;
733 r_shadow_buffer_shadowtrispvs = NULL;
734 r_shadow_buffer_lighttrispvs = NULL;
735 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap, NULL, NULL);
738 matrix4x4_t matrix_attenuationxyz =
741 {0.5, 0.0, 0.0, 0.5},
742 {0.0, 0.5, 0.0, 0.5},
743 {0.0, 0.0, 0.5, 0.5},
748 matrix4x4_t matrix_attenuationz =
751 {0.0, 0.0, 0.5, 0.5},
752 {0.0, 0.0, 0.0, 0.5},
753 {0.0, 0.0, 0.0, 0.5},
758 void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles, int vertscale, int triscale)
760 numvertices = ((numvertices + 255) & ~255) * vertscale;
761 numtriangles = ((numtriangles + 255) & ~255) * triscale;
762 // make sure shadowelements is big enough for this volume
763 if (maxshadowtriangles < numtriangles)
765 maxshadowtriangles = numtriangles;
767 Mem_Free(shadowelements);
768 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[3]));
770 // make sure shadowvertex3f is big enough for this volume
771 if (maxshadowvertices < numvertices)
773 maxshadowvertices = numvertices;
775 Mem_Free(shadowvertex3f);
776 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[3]));
780 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
782 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
783 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
784 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
785 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
786 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
788 if (r_shadow_buffer_visitingleafpvs)
789 Mem_Free(r_shadow_buffer_visitingleafpvs);
790 if (r_shadow_buffer_leafpvs)
791 Mem_Free(r_shadow_buffer_leafpvs);
792 if (r_shadow_buffer_leaflist)
793 Mem_Free(r_shadow_buffer_leaflist);
794 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
795 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
796 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
797 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
799 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
801 if (r_shadow_buffer_surfacepvs)
802 Mem_Free(r_shadow_buffer_surfacepvs);
803 if (r_shadow_buffer_surfacelist)
804 Mem_Free(r_shadow_buffer_surfacelist);
805 if (r_shadow_buffer_surfacesides)
806 Mem_Free(r_shadow_buffer_surfacesides);
807 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
808 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
809 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
810 r_shadow_buffer_surfacesides = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
812 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
814 if (r_shadow_buffer_shadowtrispvs)
815 Mem_Free(r_shadow_buffer_shadowtrispvs);
816 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
817 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
819 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
821 if (r_shadow_buffer_lighttrispvs)
822 Mem_Free(r_shadow_buffer_lighttrispvs);
823 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
824 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
828 void R_Shadow_PrepareShadowMark(int numtris)
830 // make sure shadowmark is big enough for this volume
831 if (maxshadowmark < numtris)
833 maxshadowmark = numtris;
835 Mem_Free(shadowmark);
837 Mem_Free(shadowmarklist);
838 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
839 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
843 // if shadowmarkcount wrapped we clear the array and adjust accordingly
844 if (shadowmarkcount == 0)
847 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
852 void R_Shadow_PrepareShadowSides(int numtris)
854 if (maxshadowsides < numtris)
856 maxshadowsides = numtris;
858 Mem_Free(shadowsides);
860 Mem_Free(shadowsideslist);
861 shadowsides = (unsigned char *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsides));
862 shadowsideslist = (int *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsideslist));
867 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)
870 int outtriangles = 0, outvertices = 0;
873 float ratio, direction[3], projectvector[3];
875 if (projectdirection)
876 VectorScale(projectdirection, projectdistance, projectvector);
878 VectorClear(projectvector);
880 // create the vertices
881 if (projectdirection)
883 for (i = 0;i < numshadowmarktris;i++)
885 element = inelement3i + shadowmarktris[i] * 3;
886 for (j = 0;j < 3;j++)
888 if (vertexupdate[element[j]] != vertexupdatenum)
890 vertexupdate[element[j]] = vertexupdatenum;
891 vertexremap[element[j]] = outvertices;
892 vertex = invertex3f + element[j] * 3;
893 // project one copy of the vertex according to projectvector
894 VectorCopy(vertex, outvertex3f);
895 VectorAdd(vertex, projectvector, (outvertex3f + 3));
904 for (i = 0;i < numshadowmarktris;i++)
906 element = inelement3i + shadowmarktris[i] * 3;
907 for (j = 0;j < 3;j++)
909 if (vertexupdate[element[j]] != vertexupdatenum)
911 vertexupdate[element[j]] = vertexupdatenum;
912 vertexremap[element[j]] = outvertices;
913 vertex = invertex3f + element[j] * 3;
914 // project one copy of the vertex to the sphere radius of the light
915 // (FIXME: would projecting it to the light box be better?)
916 VectorSubtract(vertex, projectorigin, direction);
917 ratio = projectdistance / VectorLength(direction);
918 VectorCopy(vertex, outvertex3f);
919 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
927 if (r_shadow_frontsidecasting.integer)
929 for (i = 0;i < numshadowmarktris;i++)
931 int remappedelement[3];
933 const int *neighbortriangle;
935 markindex = shadowmarktris[i] * 3;
936 element = inelement3i + markindex;
937 neighbortriangle = inneighbor3i + markindex;
938 // output the front and back triangles
939 outelement3i[0] = vertexremap[element[0]];
940 outelement3i[1] = vertexremap[element[1]];
941 outelement3i[2] = vertexremap[element[2]];
942 outelement3i[3] = vertexremap[element[2]] + 1;
943 outelement3i[4] = vertexremap[element[1]] + 1;
944 outelement3i[5] = vertexremap[element[0]] + 1;
948 // output the sides (facing outward from this triangle)
949 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
951 remappedelement[0] = vertexremap[element[0]];
952 remappedelement[1] = vertexremap[element[1]];
953 outelement3i[0] = remappedelement[1];
954 outelement3i[1] = remappedelement[0];
955 outelement3i[2] = remappedelement[0] + 1;
956 outelement3i[3] = remappedelement[1];
957 outelement3i[4] = remappedelement[0] + 1;
958 outelement3i[5] = remappedelement[1] + 1;
963 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
965 remappedelement[1] = vertexremap[element[1]];
966 remappedelement[2] = vertexremap[element[2]];
967 outelement3i[0] = remappedelement[2];
968 outelement3i[1] = remappedelement[1];
969 outelement3i[2] = remappedelement[1] + 1;
970 outelement3i[3] = remappedelement[2];
971 outelement3i[4] = remappedelement[1] + 1;
972 outelement3i[5] = remappedelement[2] + 1;
977 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
979 remappedelement[0] = vertexremap[element[0]];
980 remappedelement[2] = vertexremap[element[2]];
981 outelement3i[0] = remappedelement[0];
982 outelement3i[1] = remappedelement[2];
983 outelement3i[2] = remappedelement[2] + 1;
984 outelement3i[3] = remappedelement[0];
985 outelement3i[4] = remappedelement[2] + 1;
986 outelement3i[5] = remappedelement[0] + 1;
995 for (i = 0;i < numshadowmarktris;i++)
997 int remappedelement[3];
999 const int *neighbortriangle;
1001 markindex = shadowmarktris[i] * 3;
1002 element = inelement3i + markindex;
1003 neighbortriangle = inneighbor3i + markindex;
1004 // output the front and back triangles
1005 outelement3i[0] = vertexremap[element[2]];
1006 outelement3i[1] = vertexremap[element[1]];
1007 outelement3i[2] = vertexremap[element[0]];
1008 outelement3i[3] = vertexremap[element[0]] + 1;
1009 outelement3i[4] = vertexremap[element[1]] + 1;
1010 outelement3i[5] = vertexremap[element[2]] + 1;
1014 // output the sides (facing outward from this triangle)
1015 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
1017 remappedelement[0] = vertexremap[element[0]];
1018 remappedelement[1] = vertexremap[element[1]];
1019 outelement3i[0] = remappedelement[0];
1020 outelement3i[1] = remappedelement[1];
1021 outelement3i[2] = remappedelement[1] + 1;
1022 outelement3i[3] = remappedelement[0];
1023 outelement3i[4] = remappedelement[1] + 1;
1024 outelement3i[5] = remappedelement[0] + 1;
1029 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1031 remappedelement[1] = vertexremap[element[1]];
1032 remappedelement[2] = vertexremap[element[2]];
1033 outelement3i[0] = remappedelement[1];
1034 outelement3i[1] = remappedelement[2];
1035 outelement3i[2] = remappedelement[2] + 1;
1036 outelement3i[3] = remappedelement[1];
1037 outelement3i[4] = remappedelement[2] + 1;
1038 outelement3i[5] = remappedelement[1] + 1;
1043 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1045 remappedelement[0] = vertexremap[element[0]];
1046 remappedelement[2] = vertexremap[element[2]];
1047 outelement3i[0] = remappedelement[2];
1048 outelement3i[1] = remappedelement[0];
1049 outelement3i[2] = remappedelement[0] + 1;
1050 outelement3i[3] = remappedelement[2];
1051 outelement3i[4] = remappedelement[0] + 1;
1052 outelement3i[5] = remappedelement[2] + 1;
1060 *outnumvertices = outvertices;
1061 return outtriangles;
1064 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)
1067 int outtriangles = 0, outvertices = 0;
1069 const float *vertex;
1070 float ratio, direction[3], projectvector[3];
1073 if (projectdirection)
1074 VectorScale(projectdirection, projectdistance, projectvector);
1076 VectorClear(projectvector);
1078 for (i = 0;i < numshadowmarktris;i++)
1080 int remappedelement[3];
1082 const int *neighbortriangle;
1084 markindex = shadowmarktris[i] * 3;
1085 neighbortriangle = inneighbor3i + markindex;
1086 side[0] = shadowmark[neighbortriangle[0]] == shadowmarkcount;
1087 side[1] = shadowmark[neighbortriangle[1]] == shadowmarkcount;
1088 side[2] = shadowmark[neighbortriangle[2]] == shadowmarkcount;
1089 if (side[0] + side[1] + side[2] == 0)
1093 element = inelement3i + markindex;
1095 // create the vertices
1096 for (j = 0;j < 3;j++)
1098 if (side[j] + side[j+1] == 0)
1101 if (vertexupdate[k] != vertexupdatenum)
1103 vertexupdate[k] = vertexupdatenum;
1104 vertexremap[k] = outvertices;
1105 vertex = invertex3f + k * 3;
1106 VectorCopy(vertex, outvertex3f);
1107 if (projectdirection)
1109 // project one copy of the vertex according to projectvector
1110 VectorAdd(vertex, projectvector, (outvertex3f + 3));
1114 // project one copy of the vertex to the sphere radius of the light
1115 // (FIXME: would projecting it to the light box be better?)
1116 VectorSubtract(vertex, projectorigin, direction);
1117 ratio = projectdistance / VectorLength(direction);
1118 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1125 // output the sides (facing outward from this triangle)
1128 remappedelement[0] = vertexremap[element[0]];
1129 remappedelement[1] = vertexremap[element[1]];
1130 outelement3i[0] = remappedelement[1];
1131 outelement3i[1] = remappedelement[0];
1132 outelement3i[2] = remappedelement[0] + 1;
1133 outelement3i[3] = remappedelement[1];
1134 outelement3i[4] = remappedelement[0] + 1;
1135 outelement3i[5] = remappedelement[1] + 1;
1142 remappedelement[1] = vertexremap[element[1]];
1143 remappedelement[2] = vertexremap[element[2]];
1144 outelement3i[0] = remappedelement[2];
1145 outelement3i[1] = remappedelement[1];
1146 outelement3i[2] = remappedelement[1] + 1;
1147 outelement3i[3] = remappedelement[2];
1148 outelement3i[4] = remappedelement[1] + 1;
1149 outelement3i[5] = remappedelement[2] + 1;
1156 remappedelement[0] = vertexremap[element[0]];
1157 remappedelement[2] = vertexremap[element[2]];
1158 outelement3i[0] = remappedelement[0];
1159 outelement3i[1] = remappedelement[2];
1160 outelement3i[2] = remappedelement[2] + 1;
1161 outelement3i[3] = remappedelement[0];
1162 outelement3i[4] = remappedelement[2] + 1;
1163 outelement3i[5] = remappedelement[0] + 1;
1170 *outnumvertices = outvertices;
1171 return outtriangles;
1174 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)
1180 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1182 tend = firsttriangle + numtris;
1183 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1185 // surface box entirely inside light box, no box cull
1186 if (projectdirection)
1188 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1190 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
1191 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1192 shadowmarklist[numshadowmark++] = t;
1197 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1198 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
1199 shadowmarklist[numshadowmark++] = t;
1204 // surface box not entirely inside light box, cull each triangle
1205 if (projectdirection)
1207 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1209 v[0] = invertex3f + e[0] * 3;
1210 v[1] = invertex3f + e[1] * 3;
1211 v[2] = invertex3f + e[2] * 3;
1212 TriangleNormal(v[0], v[1], v[2], normal);
1213 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1214 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1215 shadowmarklist[numshadowmark++] = t;
1220 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1222 v[0] = invertex3f + e[0] * 3;
1223 v[1] = invertex3f + e[1] * 3;
1224 v[2] = invertex3f + e[2] * 3;
1225 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1226 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1227 shadowmarklist[numshadowmark++] = t;
1233 qboolean R_Shadow_UseZPass(vec3_t mins, vec3_t maxs)
1238 if (r_shadow_compilingrtlight || !r_shadow_frontsidecasting.integer || !r_shadow_usezpassifpossible.integer)
1240 // check if the shadow volume intersects the near plane
1242 // a ray between the eye and light origin may intersect the caster,
1243 // indicating that the shadow may touch the eye location, however we must
1244 // test the near plane (a polygon), not merely the eye location, so it is
1245 // easiest to enlarge the caster bounding shape slightly for this.
1251 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)
1253 int i, tris, outverts;
1254 if (projectdistance < 0.1)
1256 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
1259 if (!numverts || !nummarktris)
1261 // make sure shadowelements is big enough for this volume
1262 if (maxshadowtriangles < nummarktris*8 || maxshadowvertices < numverts*2)
1263 R_Shadow_ResizeShadowArrays(numverts, nummarktris, 2, 8);
1265 if (maxvertexupdate < numverts)
1267 maxvertexupdate = numverts;
1269 Mem_Free(vertexupdate);
1271 Mem_Free(vertexremap);
1272 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1273 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1274 vertexupdatenum = 0;
1277 if (vertexupdatenum == 0)
1279 vertexupdatenum = 1;
1280 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
1281 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
1284 for (i = 0;i < nummarktris;i++)
1285 shadowmark[marktris[i]] = shadowmarkcount;
1287 if (r_shadow_compilingrtlight)
1289 // if we're compiling an rtlight, capture the mesh
1290 //tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1291 //Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zpass, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1292 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1293 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zfail, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1295 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
1297 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1298 R_Mesh_PrepareVertices_Vertex3f(outverts, shadowvertex3f, NULL);
1299 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1303 // decide which type of shadow to generate and set stencil mode
1304 R_Shadow_RenderMode_StencilShadowVolumes(R_Shadow_UseZPass(trismins, trismaxs));
1305 // generate the sides or a solid volume, depending on type
1306 if (r_shadow_rendermode >= R_SHADOW_RENDERMODE_ZPASS_STENCIL && r_shadow_rendermode <= R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE)
1307 tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1309 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1310 r_refdef.stats.lights_dynamicshadowtriangles += tris;
1311 r_refdef.stats.lights_shadowtriangles += tris;
1312 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
1314 // increment stencil if frontface is infront of depthbuffer
1315 GL_CullFace(r_refdef.view.cullface_front);
1316 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
1317 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1318 // decrement stencil if backface is infront of depthbuffer
1319 GL_CullFace(r_refdef.view.cullface_back);
1320 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
1322 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
1324 // decrement stencil if backface is behind depthbuffer
1325 GL_CullFace(r_refdef.view.cullface_front);
1326 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
1327 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1328 // increment stencil if frontface is behind depthbuffer
1329 GL_CullFace(r_refdef.view.cullface_back);
1330 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
1332 R_Mesh_PrepareVertices_Vertex3f(outverts, shadowvertex3f, NULL);
1333 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1337 int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias)
1339 // p1, p2, p3 are in the cubemap's local coordinate system
1340 // bias = border/(size - border)
1343 float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1344 dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2),
1345 dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3);
1346 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1348 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1349 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1350 | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1351 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1353 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1354 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1355 | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1357 dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1358 dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2),
1359 dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3);
1360 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1362 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1363 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1364 | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1365 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1367 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1368 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1369 | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1371 dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1372 dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2),
1373 dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3);
1374 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1376 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1377 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1378 | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1379 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1381 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1382 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1383 | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1388 int R_Shadow_CalcBBoxSideMask(const vec3_t mins, const vec3_t maxs, const matrix4x4_t *worldtolight, const matrix4x4_t *radiustolight, float bias)
1390 vec3_t center, radius, lightcenter, lightradius, pmin, pmax;
1391 float dp1, dn1, ap1, an1, dp2, dn2, ap2, an2;
1394 VectorSubtract(maxs, mins, radius);
1395 VectorScale(radius, 0.5f, radius);
1396 VectorAdd(mins, radius, center);
1397 Matrix4x4_Transform(worldtolight, center, lightcenter);
1398 Matrix4x4_Transform3x3(radiustolight, radius, lightradius);
1399 VectorSubtract(lightcenter, lightradius, pmin);
1400 VectorAdd(lightcenter, lightradius, pmax);
1402 dp1 = pmax[0] + pmax[1], dn1 = pmax[0] - pmin[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1403 dp2 = pmin[0] + pmin[1], dn2 = pmin[0] - pmax[1], ap2 = fabs(dp2), an2 = fabs(dn2);
1404 if(ap1 > bias*an1 && ap2 > bias*an2)
1406 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1407 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1408 if(an1 > bias*ap1 && an2 > bias*ap2)
1410 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1411 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1413 dp1 = pmax[1] + pmax[2], dn1 = pmax[1] - pmin[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1414 dp2 = pmin[1] + pmin[2], dn2 = pmin[1] - pmax[2], ap2 = fabs(dp2), an2 = fabs(dn2);
1415 if(ap1 > bias*an1 && ap2 > bias*an2)
1417 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1418 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1419 if(an1 > bias*ap1 && an2 > bias*ap2)
1421 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1422 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1424 dp1 = pmax[2] + pmax[0], dn1 = pmax[2] - pmin[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1425 dp2 = pmin[2] + pmin[0], dn2 = pmin[2] - pmax[0], ap2 = fabs(dp2), an2 = fabs(dn2);
1426 if(ap1 > bias*an1 && ap2 > bias*an2)
1428 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1429 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1430 if(an1 > bias*ap1 && an2 > bias*ap2)
1432 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1433 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1438 #define R_Shadow_CalcEntitySideMask(ent, worldtolight, radiustolight, bias) R_Shadow_CalcBBoxSideMask((ent)->mins, (ent)->maxs, worldtolight, radiustolight, bias)
1440 int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
1442 // p is in the cubemap's local coordinate system
1443 // bias = border/(size - border)
1444 float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn);
1445 float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn);
1446 float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn);
1448 if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
1449 if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
1450 if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
1451 if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
1452 if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
1453 if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
1457 int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
1461 int sides = 0x3F, masks[6] = { 3<<4, 3<<4, 3<<0, 3<<0, 3<<2, 3<<2 };
1462 float scale = (size - 2*border)/size, len;
1463 float bias = border / (float)(size - border), dp, dn, ap, an;
1464 // check if cone enclosing side would cross frustum plane
1465 scale = 2 / (scale*scale + 2);
1466 for (i = 0;i < 5;i++)
1468 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) > -0.03125)
1470 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[i].normal, n);
1471 len = scale*VectorLength2(n);
1472 if(n[0]*n[0] > len) sides &= n[0] < 0 ? ~(1<<0) : ~(2 << 0);
1473 if(n[1]*n[1] > len) sides &= n[1] < 0 ? ~(1<<2) : ~(2 << 2);
1474 if(n[2]*n[2] > len) sides &= n[2] < 0 ? ~(1<<4) : ~(2 << 4);
1476 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[4]) >= r_refdef.farclip - r_refdef.nearclip + 0.03125)
1478 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[4].normal, n);
1479 len = scale*VectorLength(n);
1480 if(n[0]*n[0] > len) sides &= n[0] >= 0 ? ~(1<<0) : ~(2 << 0);
1481 if(n[1]*n[1] > len) sides &= n[1] >= 0 ? ~(1<<2) : ~(2 << 2);
1482 if(n[2]*n[2] > len) sides &= n[2] >= 0 ? ~(1<<4) : ~(2 << 4);
1484 // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results
1485 // check if frustum corners/origin cross plane sides
1487 // infinite version, assumes frustum corners merely give direction and extend to infinite distance
1488 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.origin, p);
1489 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1490 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1491 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1492 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1493 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1494 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1495 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1496 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1497 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1498 for (i = 0;i < 4;i++)
1500 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.frustumcorner[i], n);
1501 VectorSubtract(n, p, n);
1502 dp = n[0] + n[1], dn = n[0] - n[1], ap = fabs(dp), an = fabs(dn);
1503 if(ap > 0) masks[0] |= dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2);
1504 if(an > 0) masks[1] |= dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2);
1505 dp = n[1] + n[2], dn = n[1] - n[2], ap = fabs(dp), an = fabs(dn);
1506 if(ap > 0) masks[2] |= dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4);
1507 if(an > 0) masks[3] |= dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4);
1508 dp = n[2] + n[0], dn = n[2] - n[0], ap = fabs(dp), an = fabs(dn);
1509 if(ap > 0) masks[4] |= dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0);
1510 if(an > 0) masks[5] |= dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0);
1513 // finite version, assumes corners are a finite distance from origin dependent on far plane
1514 for (i = 0;i < 5;i++)
1516 Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p);
1517 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1518 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1519 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1520 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1521 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1522 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1523 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1524 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1525 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1528 return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5];
1531 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)
1539 int mask, surfacemask = 0;
1540 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1542 bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
1543 tend = firsttriangle + numtris;
1544 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1546 // surface box entirely inside light box, no box cull
1547 if (projectdirection)
1549 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1551 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1552 TriangleNormal(v[0], v[1], v[2], normal);
1553 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1555 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1556 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1557 surfacemask |= mask;
1560 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;
1561 shadowsides[numshadowsides] = mask;
1562 shadowsideslist[numshadowsides++] = t;
1569 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1571 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1572 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]))
1574 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1575 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1576 surfacemask |= mask;
1579 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;
1580 shadowsides[numshadowsides] = mask;
1581 shadowsideslist[numshadowsides++] = t;
1589 // surface box not entirely inside light box, cull each triangle
1590 if (projectdirection)
1592 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1594 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1595 TriangleNormal(v[0], v[1], v[2], normal);
1596 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1597 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1599 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1600 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1601 surfacemask |= mask;
1604 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;
1605 shadowsides[numshadowsides] = mask;
1606 shadowsideslist[numshadowsides++] = t;
1613 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1615 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1616 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1617 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1619 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1620 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1621 surfacemask |= mask;
1624 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;
1625 shadowsides[numshadowsides] = mask;
1626 shadowsideslist[numshadowsides++] = t;
1635 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)
1637 int i, j, outtriangles = 0;
1638 int *outelement3i[6];
1639 if (!numverts || !numsidetris || !r_shadow_compilingrtlight)
1641 outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5];
1642 // make sure shadowelements is big enough for this mesh
1643 if (maxshadowtriangles < outtriangles)
1644 R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1);
1646 // compute the offset and size of the separate index lists for each cubemap side
1648 for (i = 0;i < 6;i++)
1650 outelement3i[i] = shadowelements + outtriangles * 3;
1651 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles;
1652 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i];
1653 outtriangles += sidetotals[i];
1656 // gather up the (sparse) triangles into separate index lists for each cubemap side
1657 for (i = 0;i < numsidetris;i++)
1659 const int *element = elements + sidetris[i] * 3;
1660 for (j = 0;j < 6;j++)
1662 if (sides[i] & (1 << j))
1664 outelement3i[j][0] = element[0];
1665 outelement3i[j][1] = element[1];
1666 outelement3i[j][2] = element[2];
1667 outelement3i[j] += 3;
1672 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, outtriangles, shadowelements);
1675 static void R_Shadow_MakeTextures_MakeCorona(void)
1679 unsigned char pixels[32][32][4];
1680 for (y = 0;y < 32;y++)
1682 dy = (y - 15.5f) * (1.0f / 16.0f);
1683 for (x = 0;x < 32;x++)
1685 dx = (x - 15.5f) * (1.0f / 16.0f);
1686 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1687 a = bound(0, a, 255);
1688 pixels[y][x][0] = a;
1689 pixels[y][x][1] = a;
1690 pixels[y][x][2] = a;
1691 pixels[y][x][3] = 255;
1694 r_shadow_lightcorona = R_SkinFrame_LoadInternalBGRA("lightcorona", TEXF_FORCELINEAR, &pixels[0][0][0], 32, 32);
1697 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1699 float dist = sqrt(x*x+y*y+z*z);
1700 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1701 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1702 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1705 static void R_Shadow_MakeTextures(void)
1708 float intensity, dist;
1710 R_Shadow_FreeShadowMaps();
1711 R_FreeTexturePool(&r_shadow_texturepool);
1712 r_shadow_texturepool = R_AllocTexturePool();
1713 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1714 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1715 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1716 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1717 for (x = 0;x <= ATTENTABLESIZE;x++)
1719 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1720 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1721 r_shadow_attentable[x] = bound(0, intensity, 1);
1723 // 1D gradient texture
1724 for (x = 0;x < ATTEN1DSIZE;x++)
1725 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1726 r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1727 // 2D circle texture
1728 for (y = 0;y < ATTEN2DSIZE;y++)
1729 for (x = 0;x < ATTEN2DSIZE;x++)
1730 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);
1731 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1732 // 3D sphere texture
1733 if (r_shadow_texture3d.integer && vid.support.ext_texture_3d)
1735 for (z = 0;z < ATTEN3DSIZE;z++)
1736 for (y = 0;y < ATTEN3DSIZE;y++)
1737 for (x = 0;x < ATTEN3DSIZE;x++)
1738 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));
1739 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);
1742 r_shadow_attenuation3dtexture = NULL;
1745 R_Shadow_MakeTextures_MakeCorona();
1747 // Editor light sprites
1748 r_editlights_sprcursor = R_SkinFrame_LoadInternal8bit("gfx/editlights/cursor", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1765 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1766 r_editlights_sprlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/light", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1783 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1784 r_editlights_sprnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/noshadow", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1801 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1802 r_editlights_sprcubemaplight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemaplight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1819 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1820 r_editlights_sprcubemapnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemapnoshadowlight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1837 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1838 r_editlights_sprselection = R_SkinFrame_LoadInternal8bit("gfx/editlights/selection", TEXF_ALPHA | TEXF_CLAMP, (unsigned char *)
1855 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1858 void R_Shadow_ValidateCvars(void)
1860 if (r_shadow_texture3d.integer && !vid.support.ext_texture_3d)
1861 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1862 if (gl_ext_separatestencil.integer && !vid.support.ati_separate_stencil)
1863 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
1864 if (gl_ext_stenciltwoside.integer && !vid.support.ext_stencil_two_side)
1865 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1868 void R_Shadow_RenderMode_Begin(void)
1874 R_Shadow_ValidateCvars();
1876 if (!r_shadow_attenuation2dtexture
1877 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1878 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1879 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1880 R_Shadow_MakeTextures();
1883 R_Mesh_ResetTextureState();
1884 GL_BlendFunc(GL_ONE, GL_ZERO);
1885 GL_DepthRange(0, 1);
1886 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1888 GL_DepthMask(false);
1889 GL_Color(0, 0, 0, 1);
1890 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1892 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1894 if (gl_ext_separatestencil.integer && vid.support.ati_separate_stencil)
1896 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
1897 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
1899 else if (gl_ext_stenciltwoside.integer && vid.support.ext_stencil_two_side)
1901 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
1902 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
1906 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
1907 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
1910 switch(vid.renderpath)
1912 case RENDERPATH_GL20:
1913 case RENDERPATH_D3D9:
1914 case RENDERPATH_D3D10:
1915 case RENDERPATH_D3D11:
1916 case RENDERPATH_SOFT:
1917 case RENDERPATH_GLES2:
1918 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1920 case RENDERPATH_GL13:
1921 case RENDERPATH_GL11:
1922 if (r_textureunits.integer >= 2 && vid.texunits >= 2 && r_shadow_texture3d.integer && r_shadow_attenuation3dtexture)
1923 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN;
1924 else if (r_textureunits.integer >= 3 && vid.texunits >= 3)
1925 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN;
1926 else if (r_textureunits.integer >= 2 && vid.texunits >= 2)
1927 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN;
1929 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1935 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
1936 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
1937 r_shadow_drawbuffer = drawbuffer;
1938 r_shadow_readbuffer = readbuffer;
1940 r_shadow_cullface_front = r_refdef.view.cullface_front;
1941 r_shadow_cullface_back = r_refdef.view.cullface_back;
1944 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
1946 rsurface.rtlight = rtlight;
1949 void R_Shadow_RenderMode_Reset(void)
1951 R_Mesh_ResetRenderTargets();
1952 R_SetViewport(&r_refdef.view.viewport);
1953 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
1954 R_Mesh_ResetTextureState();
1955 GL_DepthRange(0, 1);
1957 GL_DepthMask(false);
1958 GL_DepthFunc(GL_LEQUAL);
1959 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1960 r_refdef.view.cullface_front = r_shadow_cullface_front;
1961 r_refdef.view.cullface_back = r_shadow_cullface_back;
1962 GL_CullFace(r_refdef.view.cullface_back);
1963 GL_Color(1, 1, 1, 1);
1964 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
1965 GL_BlendFunc(GL_ONE, GL_ZERO);
1966 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
1967 r_shadow_usingshadowmap2d = false;
1968 r_shadow_usingshadowmaportho = false;
1969 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
1972 void R_Shadow_ClearStencil(void)
1974 GL_Clear(GL_STENCIL_BUFFER_BIT, NULL, 1.0f, 128);
1975 r_refdef.stats.lights_clears++;
1978 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
1980 r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
1981 if (r_shadow_rendermode == mode)
1983 R_Shadow_RenderMode_Reset();
1984 GL_DepthFunc(GL_LESS);
1985 GL_ColorMask(0, 0, 0, 0);
1986 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1987 GL_CullFace(GL_NONE);
1988 R_SetupShader_DepthOrShadow();
1989 r_shadow_rendermode = mode;
1994 case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
1995 case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
1996 R_SetStencilSeparate(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, GL_ALWAYS, 128, 255);
1998 case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
1999 case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
2000 R_SetStencilSeparate(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, GL_ALWAYS, 128, 255);
2005 static void R_Shadow_MakeVSDCT(void)
2007 // maps to a 2x3 texture rectangle with normalized coordinates
2012 // stores abs(dir.xy), offset.xy/2.5
2013 unsigned char data[4*6] =
2015 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
2016 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
2017 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
2018 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
2019 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
2020 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
2022 r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
2025 static void R_Shadow_MakeShadowMap(int side, int size)
2027 switch (r_shadow_shadowmode)
2029 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2030 if (r_shadow_shadowmap2dtexture) return;
2031 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);
2032 r_shadow_shadowmap2dcolortexture = NULL;
2033 switch(vid.renderpath)
2036 case RENDERPATH_D3D9:
2037 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);
2038 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
2042 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2dtexture, NULL, NULL, NULL, NULL);
2050 // render depth into the fbo, do not render color at all
2051 // validate the fbo now
2055 qglDrawBuffer(GL_NONE);CHECKGLERROR
2056 qglReadBuffer(GL_NONE);CHECKGLERROR
2057 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2058 if (status != GL_FRAMEBUFFER_COMPLETE_EXT && (r_shadow_shadowmapping.integer || r_shadow_deferred.integer))
2060 Con_Printf("R_Shadow_MakeShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2061 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2062 Cvar_SetValueQuick(&r_shadow_deferred, 0);
2067 void R_Shadow_RenderMode_ShadowMap(int side, int clear, int size)
2069 float nearclip, farclip, bias;
2070 r_viewport_t viewport;
2073 float clearcolor[4];
2074 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
2076 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
2077 r_shadow_shadowmap_parameters[1] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
2078 r_shadow_shadowmap_parameters[3] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
2079 r_shadow_shadowmapside = side;
2080 r_shadow_shadowmapsize = size;
2082 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2083 r_shadow_shadowmap_parameters[2] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2084 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
2085 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D) goto init_done;
2087 // complex unrolled cube approach (more flexible)
2088 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2089 R_Shadow_MakeVSDCT();
2090 if (!r_shadow_shadowmap2dtexture)
2091 R_Shadow_MakeShadowMap(side, r_shadow_shadowmapmaxsize);
2092 if (r_shadow_shadowmap2dtexture) fbo = r_shadow_fbo2d;
2093 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
2094 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
2095 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
2097 R_Mesh_ResetTextureState();
2098 R_Mesh_ResetRenderTargets();
2099 R_Shadow_RenderMode_Reset();
2102 R_Mesh_SetRenderTargets(fbo, r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
2103 R_SetupShader_DepthOrShadow();
2106 R_SetupShader_ShowDepth();
2107 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
2112 R_SetViewport(&viewport);
2113 flipped = (side & 1) ^ (side >> 2);
2114 r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
2115 r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
2116 switch(vid.renderpath)
2118 case RENDERPATH_GL11:
2119 case RENDERPATH_GL13:
2120 case RENDERPATH_GL20:
2121 case RENDERPATH_SOFT:
2122 case RENDERPATH_GLES2:
2123 GL_CullFace(r_refdef.view.cullface_back);
2124 // OpenGL lets us scissor larger than the viewport, so go ahead and clear all views at once
2125 if ((clear & ((2 << side) - 1)) == (1 << side)) // only clear if the side is the first in the mask
2127 // get tightest scissor rectangle that encloses all viewports in the clear mask
2128 int x1 = clear & 0x15 ? 0 : size;
2129 int x2 = clear & 0x2A ? 2 * size : size;
2130 int y1 = clear & 0x03 ? 0 : (clear & 0xC ? size : 2 * size);
2131 int y2 = clear & 0x30 ? 3 * size : (clear & 0xC ? 2 * size : size);
2132 GL_Scissor(x1, y1, x2 - x1, y2 - y1);
2133 GL_Clear(GL_DEPTH_BUFFER_BIT, NULL, 1.0f, 0);
2135 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2137 case RENDERPATH_D3D9:
2138 case RENDERPATH_D3D10:
2139 case RENDERPATH_D3D11:
2140 Vector4Set(clearcolor, 1,1,1,1);
2141 // completely different meaning than in OpenGL path
2142 r_shadow_shadowmap_parameters[1] = 0;
2143 r_shadow_shadowmap_parameters[3] = -bias;
2144 // we invert the cull mode because we flip the projection matrix
2145 // NOTE: this actually does nothing because the DrawShadowMap code sets it to doublesided...
2146 GL_CullFace(r_refdef.view.cullface_front);
2147 // D3D considers it an error to use a scissor larger than the viewport... clear just this view
2148 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2149 if (r_shadow_shadowmapsampler)
2151 GL_ColorMask(0,0,0,0);
2153 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
2157 GL_ColorMask(1,1,1,1);
2159 GL_Clear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
2165 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
2167 R_Mesh_ResetTextureState();
2168 R_Mesh_ResetRenderTargets();
2171 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2172 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2173 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2174 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2176 R_Shadow_RenderMode_Reset();
2177 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2179 GL_DepthFunc(GL_EQUAL);
2180 // do global setup needed for the chosen lighting mode
2181 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2182 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2183 r_shadow_usingshadowmap2d = shadowmapping;
2184 r_shadow_rendermode = r_shadow_lightingrendermode;
2185 // only draw light where this geometry was already rendered AND the
2186 // stencil is 128 (values other than this mean shadow)
2188 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2190 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
2193 static const unsigned short bboxelements[36] =
2203 static const float bboxpoints[8][3] =
2215 void R_Shadow_RenderMode_DrawDeferredLight(qboolean stenciltest, qboolean shadowmapping)
2218 float vertex3f[8*3];
2219 const matrix4x4_t *matrix = &rsurface.rtlight->matrix_lighttoworld;
2220 // do global setup needed for the chosen lighting mode
2221 R_Shadow_RenderMode_Reset();
2222 r_shadow_rendermode = r_shadow_lightingrendermode;
2223 R_EntityMatrix(&identitymatrix);
2224 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2225 // only draw light where this geometry was already rendered AND the
2226 // stencil is 128 (values other than this mean shadow)
2227 R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2228 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
2230 r_shadow_usingshadowmap2d = shadowmapping;
2232 // render the lighting
2233 R_SetupShader_DeferredLight(rsurface.rtlight);
2234 for (i = 0;i < 8;i++)
2235 Matrix4x4_Transform(matrix, bboxpoints[i], vertex3f + i*3);
2236 GL_ColorMask(1,1,1,1);
2237 GL_DepthMask(false);
2238 GL_DepthRange(0, 1);
2239 GL_PolygonOffset(0, 0);
2241 GL_DepthFunc(GL_GREATER);
2242 GL_CullFace(r_refdef.view.cullface_back);
2243 R_Mesh_PrepareVertices_Vertex3f(8, vertex3f, NULL);
2244 R_Mesh_Draw(0, 8, 0, 12, NULL, NULL, 0, bboxelements, NULL, 0);
2247 #define MAXPARTICLESPERLIGHT 262144
2248 #define MAXLIGHTSPERDRAW 1024
2250 static void R_Shadow_RenderParticlesForLight(rtlight_t *rtlight)
2256 int hitsupercontentsmask;
2259 int shootparticles = 0;
2262 unsigned int seed = 0;
2263 static unsigned short bouncelight_elements[MAXLIGHTSPERDRAW*36];
2264 static float vertex3f[MAXLIGHTSPERDRAW*24];
2265 static float lightorigin4f[MAXLIGHTSPERDRAW*32];
2266 static float color4f[MAXLIGHTSPERDRAW*32];
2267 float scaledpoints[8][3];
2271 rtlight_particle_t *p;
2272 vec_t wantparticles = 0;
2276 vec_t iparticlesize;
2282 vec3_t currentcolor;
2287 if (!rtlight->draw || !rtlight->isstatic || !r_shadow_usingdeferredprepass)
2289 if (r_shadow_particletrace.integer)
2291 radius = rtlight->radius * bound(0.0001f, r_shadow_particletrace_radiusscale.value, 1.0f) - r_shadow_particletrace_size.value;
2292 s = rtlight->radius / bound(1.0f, r_shadow_particletrace_particlespacing.value * r_shadow_particletrace_size.value, 1048576.0f);
2293 wantparticles = s*s;
2294 n = (int)bound(0, wantparticles, MAXPARTICLESPERLIGHT);
2298 shootparticles = (int)(n * r_shadow_particletrace_updatepercentage.value);
2299 if ((n && !rtlight->particlecache_particles) || rtlight->particlecache_maxparticles != n)
2301 if (rtlight->particlecache_particles)
2302 Mem_Free(rtlight->particlecache_particles);
2303 rtlight->particlecache_particles = NULL;
2304 rtlight->particlecache_numparticles = 0;
2305 rtlight->particlecache_maxparticles = n;
2306 rtlight->particlecache_updateparticle = 0;
2307 if (rtlight->particlecache_maxparticles)
2308 rtlight->particlecache_particles = Mem_Alloc(r_main_mempool, rtlight->particlecache_maxparticles * sizeof(*rtlight->particlecache_particles));
2309 shootparticles = n * 16;
2312 if (!rtlight->particlecache_maxparticles)
2315 // if (rtlight->particlecache_numparticles < rtlight->particlecache_maxparticles)
2316 // shootparticles = rtlight->particlecache_maxparticles;
2318 // if (rtlight->particlecache_numparticles >= rtlight->particlecache_maxparticles)
2319 // shootparticles = 0;
2321 maxbounce = bound(1, r_shadow_particletrace_maxbounce.integer, 16);
2322 r_refdef.stats.lights_bouncelightsupdated += shootparticles;
2323 for (shotparticles = 0;shotparticles < shootparticles;shotparticles++)
2325 seed = rtlight->particlecache_updateparticle;
2326 VectorSet(shotcolor, 1.0f, 1.0f, 1.0f);
2327 VectorCopy(rtlight->shadoworigin, clipstart);
2328 VectorRandom(clipend);
2329 VectorMA(clipstart, radius, clipend, clipend);
2330 hitsupercontentsmask = SUPERCONTENTS_SOLID | SUPERCONTENTS_LIQUIDSMASK;
2331 bouncelimit = 1 + (rtlight->particlecache_updateparticle % maxbounce);
2332 for (bouncecount = 0;;bouncecount++)
2334 cliptrace = CL_TraceLine(clipstart, clipend, MOVE_NOMONSTERS, NULL, hitsupercontentsmask, true, false, NULL, true);
2335 //Collision_ClipLineToWorld(&cliptrace, cl.worldmodel, clipstart, clipend, hitsupercontentsmask);
2336 if (cliptrace.fraction >= 1.0f)
2338 if (VectorLength2(shotcolor) < (1.0f / 262144.0f))
2340 if (bouncecount >= bouncelimit)
2342 VectorCopy(cliptrace.endpos, rtlight->particlecache_particles[rtlight->particlecache_updateparticle].origin);
2343 VectorCopy(shotcolor, rtlight->particlecache_particles[rtlight->particlecache_updateparticle].color);
2344 rtlight->particlecache_updateparticle++;
2345 if (rtlight->particlecache_numparticles < rtlight->particlecache_updateparticle)
2346 rtlight->particlecache_numparticles = rtlight->particlecache_updateparticle;
2347 if (rtlight->particlecache_updateparticle >= rtlight->particlecache_maxparticles)
2349 rtlight->particlecache_updateparticle = 0;
2350 shotparticles = shootparticles;
2354 // scale down shot color by bounce intensity and texture color
2355 VectorScale(shotcolor, r_shadow_particletrace_bounceintensity.value, shotcolor);
2356 if (cliptrace.hittexture && cliptrace.hittexture->currentskinframe)
2357 VectorMultiply(shotcolor, rsurface.texture->currentskinframe->avgcolor, shotcolor);
2358 // reflect the remaining portion of the line across plane normal
2359 //VectorSubtract(clipend, cliptrace.endpos, clipdiff);
2360 //VectorReflect(clipdiff, 1.0, cliptrace.plane.normal, clipend);
2361 // random direction, primarily along plane normal
2362 s = VectorDistance(cliptrace.endpos, clipend);
2363 VectorRandom(clipend);
2364 VectorMA(cliptrace.plane.normal, 0.95f, clipend, clipend);
2365 VectorNormalize(clipend);
2366 VectorScale(clipend, s, clipend);
2367 // calculate the new line start and end
2368 VectorCopy(cliptrace.endpos, clipstart);
2369 VectorAdd(clipstart, clipend, clipend);
2373 if (!rtlight->particlecache_numparticles)
2376 // render the particles as deferred lights
2377 // do global setup needed for the chosen lighting mode
2378 R_Shadow_RenderMode_Reset();
2379 r_shadow_rendermode = r_shadow_lightingrendermode;
2380 r_shadow_usingshadowmap2d = false;
2381 R_EntityMatrix(&identitymatrix);
2382 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2383 // only draw light where this geometry was already rendered AND the
2384 // stencil is 128 (values other than this mean shadow)
2385 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2386 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
2387 R_SetupShader_DeferredBounceLight();
2388 GL_ColorMask(1,1,1,1);
2389 GL_DepthMask(false);
2390 GL_DepthRange(0, 1);
2391 GL_PolygonOffset(0, 0);
2393 GL_DepthFunc(GL_GREATER);
2394 GL_CullFace(r_refdef.view.cullface_back);
2395 s = r_shadow_particletrace_intensity.value / (float)rtlight->particlecache_numparticles;
2396 VectorScale(rtlight->currentcolor, s, currentcolor);
2397 particlesize = bound(0.0001f, r_shadow_particletrace_size.value, 1024.0f);
2398 iparticlesize = 1.0f / particlesize;
2399 // VectorScale(r_refdef.view.forward, particlesize, offset);
2400 // VectorScale(r_refdef.view.left, -particlesize, right);
2401 // VectorScale(r_refdef.view.up, particlesize, up);
2402 org[3] = iparticlesize;
2405 lo4f = lightorigin4f;
2408 if (!bouncelight_elements[1])
2409 for (i = 0;i < MAXLIGHTSPERDRAW;i++)
2410 for (j = 0;j < 36;j++)
2411 bouncelight_elements[i*36+j] = i*8+bboxelements[j];
2412 for (j = 0;j < 8;j++)
2413 VectorScale(bboxpoints[j], particlesize, scaledpoints[j]);
2414 r_refdef.stats.lights_bouncelightscounted += rtlight->particlecache_numparticles;
2415 for (j = 0, p = rtlight->particlecache_particles, n = rtlight->particlecache_numparticles;j < n;j++, p++)
2417 VectorCopy(p->origin, org);
2418 // org[3] is set above
2419 VectorMultiply(p->color, currentcolor, color);
2420 // color[3] is set above
2421 VectorAdd(scaledpoints[0], org, v3f + 0);
2422 VectorAdd(scaledpoints[1], org, v3f + 3);
2423 VectorAdd(scaledpoints[2], org, v3f + 6);
2424 VectorAdd(scaledpoints[3], org, v3f + 9);
2425 VectorAdd(scaledpoints[4], org, v3f + 12);
2426 VectorAdd(scaledpoints[5], org, v3f + 15);
2427 VectorAdd(scaledpoints[6], org, v3f + 18);
2428 VectorAdd(scaledpoints[7], org, v3f + 21);
2429 Vector4Copy(org, lo4f + 0);
2430 Vector4Copy(org, lo4f + 4);
2431 Vector4Copy(org, lo4f + 8);
2432 Vector4Copy(org, lo4f + 12);
2433 Vector4Copy(org, lo4f + 16);
2434 Vector4Copy(org, lo4f + 20);
2435 Vector4Copy(org, lo4f + 24);
2436 Vector4Copy(org, lo4f + 28);
2437 Vector4Copy(color, c4f + 0);
2438 Vector4Copy(color, c4f + 4);
2439 Vector4Copy(color, c4f + 8);
2440 Vector4Copy(color, c4f + 12);
2441 Vector4Copy(color, c4f + 16);
2442 Vector4Copy(color, c4f + 20);
2443 Vector4Copy(color, c4f + 24);
2444 Vector4Copy(color, c4f + 28);
2449 if (batchcount >= MAXLIGHTSPERDRAW)
2451 r_refdef.stats.lights_bouncelightsdrawn += batchcount;
2452 R_Mesh_PrepareVertices_BounceLight_Arrays(batchcount*8, vertex3f, color4f, lightorigin4f);
2453 R_Mesh_Draw(0, batchcount*8, 0, batchcount*12, NULL, NULL, 0, bouncelight_elements, NULL, 0);
2455 lo4f = lightorigin4f;
2462 r_refdef.stats.lights_bouncelightsdrawn += batchcount;
2463 R_Mesh_PrepareVertices_BounceLight_Arrays(batchcount*8, vertex3f, color4f, lightorigin4f);
2464 R_Mesh_Draw(0, batchcount*8, 0, batchcount*12, NULL, NULL, 0, bouncelight_elements, NULL, 0);
2466 lo4f = lightorigin4f;
2472 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
2474 R_Shadow_RenderMode_Reset();
2475 GL_BlendFunc(GL_ONE, GL_ONE);
2476 GL_DepthRange(0, 1);
2477 GL_DepthTest(r_showshadowvolumes.integer < 2);
2478 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
2479 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2480 GL_CullFace(GL_NONE);
2481 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
2484 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
2486 R_Shadow_RenderMode_Reset();
2487 GL_BlendFunc(GL_ONE, GL_ONE);
2488 GL_DepthRange(0, 1);
2489 GL_DepthTest(r_showlighting.integer < 2);
2490 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2492 GL_DepthFunc(GL_EQUAL);
2493 R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2494 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2497 void R_Shadow_RenderMode_End(void)
2499 R_Shadow_RenderMode_Reset();
2500 R_Shadow_RenderMode_ActiveLight(NULL);
2502 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2503 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2506 int bboxedges[12][2] =
2525 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2527 if (!r_shadow_scissor.integer)
2529 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2530 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2531 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2532 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2535 if(R_ScissorForBBox(mins, maxs, r_shadow_lightscissor))
2536 return true; // invisible
2537 if(r_shadow_lightscissor[0] != r_refdef.view.viewport.x
2538 || r_shadow_lightscissor[1] != r_refdef.view.viewport.y
2539 || r_shadow_lightscissor[2] != r_refdef.view.viewport.width
2540 || r_shadow_lightscissor[3] != r_refdef.view.viewport.height)
2541 r_refdef.stats.lights_scissored++;
2545 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, const float *diffusecolor, const float *ambientcolor)
2548 const float *vertex3f;
2549 const float *normal3f;
2551 float dist, dot, distintensity, shadeintensity, v[3], n[3];
2552 switch (r_shadow_rendermode)
2554 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2555 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2556 if (VectorLength2(diffusecolor) > 0)
2558 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)
2560 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2561 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2562 if ((dot = DotProduct(n, v)) < 0)
2564 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2565 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
2568 VectorCopy(ambientcolor, color4f);
2569 if (r_refdef.fogenabled)
2572 f = RSurf_FogVertex(vertex3f);
2573 VectorScale(color4f, f, color4f);
2580 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
2582 VectorCopy(ambientcolor, color4f);
2583 if (r_refdef.fogenabled)
2586 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2587 f = RSurf_FogVertex(vertex3f);
2588 VectorScale(color4f + 4*i, f, color4f);
2594 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2595 if (VectorLength2(diffusecolor) > 0)
2597 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)
2599 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2600 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2602 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2603 if ((dot = DotProduct(n, v)) < 0)
2605 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2606 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2607 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2608 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2612 color4f[0] = ambientcolor[0] * distintensity;
2613 color4f[1] = ambientcolor[1] * distintensity;
2614 color4f[2] = ambientcolor[2] * distintensity;
2616 if (r_refdef.fogenabled)
2619 f = RSurf_FogVertex(vertex3f);
2620 VectorScale(color4f, f, color4f);
2624 VectorClear(color4f);
2630 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
2632 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2633 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2635 color4f[0] = ambientcolor[0] * distintensity;
2636 color4f[1] = ambientcolor[1] * distintensity;
2637 color4f[2] = ambientcolor[2] * distintensity;
2638 if (r_refdef.fogenabled)
2641 f = RSurf_FogVertex(vertex3f);
2642 VectorScale(color4f, f, color4f);
2646 VectorClear(color4f);
2651 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2652 if (VectorLength2(diffusecolor) > 0)
2654 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)
2656 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2657 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2659 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2660 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2661 if ((dot = DotProduct(n, v)) < 0)
2663 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2664 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2665 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2666 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2670 color4f[0] = ambientcolor[0] * distintensity;
2671 color4f[1] = ambientcolor[1] * distintensity;
2672 color4f[2] = ambientcolor[2] * distintensity;
2674 if (r_refdef.fogenabled)
2677 f = RSurf_FogVertex(vertex3f);
2678 VectorScale(color4f, f, color4f);
2682 VectorClear(color4f);
2688 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
2690 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2691 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2693 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2694 color4f[0] = ambientcolor[0] * distintensity;
2695 color4f[1] = ambientcolor[1] * distintensity;
2696 color4f[2] = ambientcolor[2] * distintensity;
2697 if (r_refdef.fogenabled)
2700 f = RSurf_FogVertex(vertex3f);
2701 VectorScale(color4f, f, color4f);
2705 VectorClear(color4f);
2715 static void R_Shadow_RenderLighting_VisibleLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
2717 // used to display how many times a surface is lit for level design purposes
2718 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
2719 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
2723 static void R_Shadow_RenderLighting_Light_GLSL(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale, float specularscale)
2725 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2726 R_SetupShader_Surface(lightcolor, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT, texturenumsurfaces, texturesurfacelist, NULL);
2727 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2728 GL_DepthFunc(GL_EQUAL);
2730 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2731 GL_DepthFunc(GL_LEQUAL);
2734 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
2741 int newnumtriangles;
2745 int maxtriangles = 4096;
2746 static int newelements[4096*3];
2747 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, diffusecolor2, ambientcolor2);
2748 for (renders = 0;renders < 4;renders++)
2753 newnumtriangles = 0;
2755 // due to low fillrate on the cards this vertex lighting path is
2756 // designed for, we manually cull all triangles that do not
2757 // contain a lit vertex
2758 // this builds batches of triangles from multiple surfaces and
2759 // renders them at once
2760 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
2762 if (VectorLength2(rsurface.passcolor4f + e[0] * 4) + VectorLength2(rsurface.passcolor4f + e[1] * 4) + VectorLength2(rsurface.passcolor4f + e[2] * 4) >= 0.01)
2764 if (newnumtriangles)
2766 newfirstvertex = min(newfirstvertex, e[0]);
2767 newlastvertex = max(newlastvertex, e[0]);
2771 newfirstvertex = e[0];
2772 newlastvertex = e[0];
2774 newfirstvertex = min(newfirstvertex, e[1]);
2775 newlastvertex = max(newlastvertex, e[1]);
2776 newfirstvertex = min(newfirstvertex, e[2]);
2777 newlastvertex = max(newlastvertex, e[2]);
2783 if (newnumtriangles >= maxtriangles)
2785 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
2786 newnumtriangles = 0;
2792 if (newnumtriangles >= 1)
2794 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
2797 // if we couldn't find any lit triangles, exit early
2800 // now reduce the intensity for the next overbright pass
2801 // we have to clamp to 0 here incase the drivers have improper
2802 // handling of negative colors
2803 // (some old drivers even have improper handling of >1 color)
2805 for (i = 0, c = rsurface.passcolor4f + 4 * firstvertex;i < numvertices;i++, c += 4)
2807 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
2809 c[0] = max(0, c[0] - 1);
2810 c[1] = max(0, c[1] - 1);
2811 c[2] = max(0, c[2] - 1);
2823 static void R_Shadow_RenderLighting_Light_Vertex(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale)
2825 // OpenGL 1.1 path (anything)
2826 float ambientcolorbase[3], diffusecolorbase[3];
2827 float ambientcolorpants[3], diffusecolorpants[3];
2828 float ambientcolorshirt[3], diffusecolorshirt[3];
2829 const float *surfacecolor = rsurface.texture->dlightcolor;
2830 const float *surfacepants = rsurface.colormap_pantscolor;
2831 const float *surfaceshirt = rsurface.colormap_shirtcolor;
2832 rtexture_t *basetexture = rsurface.texture->basetexture;
2833 rtexture_t *pantstexture = rsurface.texture->pantstexture;
2834 rtexture_t *shirttexture = rsurface.texture->shirttexture;
2835 qboolean dopants = pantstexture && VectorLength2(surfacepants) >= (1.0f / 1048576.0f);
2836 qboolean doshirt = shirttexture && VectorLength2(surfaceshirt) >= (1.0f / 1048576.0f);
2837 ambientscale *= 2 * r_refdef.view.colorscale;
2838 diffusescale *= 2 * r_refdef.view.colorscale;
2839 ambientcolorbase[0] = lightcolor[0] * ambientscale * surfacecolor[0];ambientcolorbase[1] = lightcolor[1] * ambientscale * surfacecolor[1];ambientcolorbase[2] = lightcolor[2] * ambientscale * surfacecolor[2];
2840 diffusecolorbase[0] = lightcolor[0] * diffusescale * surfacecolor[0];diffusecolorbase[1] = lightcolor[1] * diffusescale * surfacecolor[1];diffusecolorbase[2] = lightcolor[2] * diffusescale * surfacecolor[2];
2841 ambientcolorpants[0] = ambientcolorbase[0] * surfacepants[0];ambientcolorpants[1] = ambientcolorbase[1] * surfacepants[1];ambientcolorpants[2] = ambientcolorbase[2] * surfacepants[2];
2842 diffusecolorpants[0] = diffusecolorbase[0] * surfacepants[0];diffusecolorpants[1] = diffusecolorbase[1] * surfacepants[1];diffusecolorpants[2] = diffusecolorbase[2] * surfacepants[2];
2843 ambientcolorshirt[0] = ambientcolorbase[0] * surfaceshirt[0];ambientcolorshirt[1] = ambientcolorbase[1] * surfaceshirt[1];ambientcolorshirt[2] = ambientcolorbase[2] * surfaceshirt[2];
2844 diffusecolorshirt[0] = diffusecolorbase[0] * surfaceshirt[0];diffusecolorshirt[1] = diffusecolorbase[1] * surfaceshirt[1];diffusecolorshirt[2] = diffusecolorbase[2] * surfaceshirt[2];
2845 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | (diffusescale > 0 ? BATCHNEED_ARRAY_NORMAL : 0) | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
2846 rsurface.passcolor4f = (float *)R_FrameData_Alloc((rsurface.batchfirstvertex + rsurface.batchnumvertices) * sizeof(float[4]));
2847 R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
2848 R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.passcolor4f, 0, 0);
2849 R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
2850 R_Mesh_TexBind(0, basetexture);
2851 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
2852 R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
2853 switch(r_shadow_rendermode)
2855 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2856 R_Mesh_TexBind(1, r_shadow_attenuation3dtexture);
2857 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
2858 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
2859 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
2861 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2862 R_Mesh_TexBind(2, r_shadow_attenuation2dtexture);
2863 R_Mesh_TexMatrix(2, &rsurface.entitytoattenuationz);
2864 R_Mesh_TexCombine(2, GL_MODULATE, GL_MODULATE, 1, 1);
2865 R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
2867 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2868 R_Mesh_TexBind(1, r_shadow_attenuation2dtexture);
2869 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
2870 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
2871 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
2873 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2878 //R_Mesh_TexBind(0, basetexture);
2879 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorbase, ambientcolorbase);
2882 R_Mesh_TexBind(0, pantstexture);
2883 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorpants, ambientcolorpants);
2887 R_Mesh_TexBind(0, shirttexture);
2888 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorshirt, ambientcolorshirt);
2892 extern cvar_t gl_lightmaps;
2893 void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
2895 float ambientscale, diffusescale, specularscale;
2897 float lightcolor[3];
2898 VectorCopy(rsurface.rtlight->currentcolor, lightcolor);
2899 ambientscale = rsurface.rtlight->ambientscale;
2900 diffusescale = rsurface.rtlight->diffusescale;
2901 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
2902 if (!r_shadow_usenormalmap.integer)
2904 ambientscale += 1.0f * diffusescale;
2908 if ((ambientscale + diffusescale) * VectorLength2(lightcolor) + specularscale * VectorLength2(lightcolor) < (1.0f / 1048576.0f))
2910 negated = (lightcolor[0] + lightcolor[1] + lightcolor[2] < 0) && vid.support.ext_blend_subtract;
2913 VectorNegate(lightcolor, lightcolor);
2914 switch(vid.renderpath)
2916 case RENDERPATH_GL11:
2917 case RENDERPATH_GL13:
2918 case RENDERPATH_GL20:
2919 case RENDERPATH_GLES2:
2920 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
2922 case RENDERPATH_D3D9:
2924 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_SUBTRACT);
2927 case RENDERPATH_D3D10:
2928 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2930 case RENDERPATH_D3D11:
2931 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2933 case RENDERPATH_SOFT:
2934 DPSOFTRAST_BlendSubtract(true);
2938 RSurf_SetupDepthAndCulling();
2939 switch (r_shadow_rendermode)
2941 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2942 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2943 R_Shadow_RenderLighting_VisibleLighting(texturenumsurfaces, texturesurfacelist);
2945 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2946 R_Shadow_RenderLighting_Light_GLSL(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale, specularscale);
2948 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2949 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2950 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2951 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2952 R_Shadow_RenderLighting_Light_Vertex(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale);
2955 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2960 switch(vid.renderpath)
2962 case RENDERPATH_GL11:
2963 case RENDERPATH_GL13:
2964 case RENDERPATH_GL20:
2965 case RENDERPATH_GLES2:
2966 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
2968 case RENDERPATH_D3D9:
2970 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_ADD);
2973 case RENDERPATH_D3D10:
2974 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2976 case RENDERPATH_D3D11:
2977 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2979 case RENDERPATH_SOFT:
2980 DPSOFTRAST_BlendSubtract(false);
2986 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)
2988 matrix4x4_t tempmatrix = *matrix;
2989 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
2991 // if this light has been compiled before, free the associated data
2992 R_RTLight_Uncompile(rtlight);
2994 // clear it completely to avoid any lingering data
2995 memset(rtlight, 0, sizeof(*rtlight));
2997 // copy the properties
2998 rtlight->matrix_lighttoworld = tempmatrix;
2999 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
3000 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
3001 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
3002 VectorCopy(color, rtlight->color);
3003 rtlight->cubemapname[0] = 0;
3004 if (cubemapname && cubemapname[0])
3005 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
3006 rtlight->shadow = shadow;
3007 rtlight->corona = corona;
3008 rtlight->style = style;
3009 rtlight->isstatic = isstatic;
3010 rtlight->coronasizescale = coronasizescale;
3011 rtlight->ambientscale = ambientscale;
3012 rtlight->diffusescale = diffusescale;
3013 rtlight->specularscale = specularscale;
3014 rtlight->flags = flags;
3016 // compute derived data
3017 //rtlight->cullradius = rtlight->radius;
3018 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
3019 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3020 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3021 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3022 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3023 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3024 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3027 // compiles rtlight geometry
3028 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
3029 void R_RTLight_Compile(rtlight_t *rtlight)
3032 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
3033 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
3034 entity_render_t *ent = r_refdef.scene.worldentity;
3035 dp_model_t *model = r_refdef.scene.worldmodel;
3036 unsigned char *data;
3039 // compile the light
3040 rtlight->compiled = true;
3041 rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
3042 rtlight->static_numleafs = 0;
3043 rtlight->static_numleafpvsbytes = 0;
3044 rtlight->static_leaflist = NULL;
3045 rtlight->static_leafpvs = NULL;
3046 rtlight->static_numsurfaces = 0;
3047 rtlight->static_surfacelist = NULL;
3048 rtlight->static_shadowmap_receivers = 0x3F;
3049 rtlight->static_shadowmap_casters = 0x3F;
3050 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3051 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3052 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3053 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3054 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3055 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3057 if (model && model->GetLightInfo)
3059 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
3060 r_shadow_compilingrtlight = rtlight;
3061 R_FrameData_SetMark();
3062 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);
3063 R_FrameData_ReturnToMark();
3064 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
3065 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
3066 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3067 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
3068 rtlight->static_numsurfaces = numsurfaces;
3069 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
3070 rtlight->static_numleafs = numleafs;
3071 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
3072 rtlight->static_numleafpvsbytes = numleafpvsbytes;
3073 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
3074 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
3075 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
3076 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
3077 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3078 if (rtlight->static_numsurfaces)
3079 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3080 if (rtlight->static_numleafs)
3081 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3082 if (rtlight->static_numleafpvsbytes)
3083 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3084 if (rtlight->static_numshadowtrispvsbytes)
3085 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3086 if (rtlight->static_numlighttrispvsbytes)
3087 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3088 R_FrameData_SetMark();
3089 switch (rtlight->shadowmode)
3091 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
3092 if (model->CompileShadowMap && rtlight->shadow)
3093 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3096 if (model->CompileShadowVolume && rtlight->shadow)
3097 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3100 R_FrameData_ReturnToMark();
3101 // now we're done compiling the rtlight
3102 r_shadow_compilingrtlight = NULL;
3106 // use smallest available cullradius - box radius or light radius
3107 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3108 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3110 shadowzpasstris = 0;
3111 if (rtlight->static_meshchain_shadow_zpass)
3112 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
3113 shadowzpasstris += mesh->numtriangles;
3115 shadowzfailtris = 0;
3116 if (rtlight->static_meshchain_shadow_zfail)
3117 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
3118 shadowzfailtris += mesh->numtriangles;
3121 if (rtlight->static_numlighttrispvsbytes)
3122 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3123 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3127 if (rtlight->static_numlighttrispvsbytes)
3128 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3129 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3132 if (developer_extra.integer)
3133 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);
3136 void R_RTLight_Uncompile(rtlight_t *rtlight)
3138 if (rtlight->compiled)
3140 if (rtlight->static_meshchain_shadow_zpass)
3141 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
3142 rtlight->static_meshchain_shadow_zpass = NULL;
3143 if (rtlight->static_meshchain_shadow_zfail)
3144 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
3145 rtlight->static_meshchain_shadow_zfail = NULL;
3146 if (rtlight->static_meshchain_shadow_shadowmap)
3147 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
3148 rtlight->static_meshchain_shadow_shadowmap = NULL;
3149 // these allocations are grouped
3150 if (rtlight->static_surfacelist)
3151 Mem_Free(rtlight->static_surfacelist);
3152 rtlight->static_numleafs = 0;
3153 rtlight->static_numleafpvsbytes = 0;
3154 rtlight->static_leaflist = NULL;
3155 rtlight->static_leafpvs = NULL;
3156 rtlight->static_numsurfaces = 0;
3157 rtlight->static_surfacelist = NULL;
3158 rtlight->static_numshadowtrispvsbytes = 0;
3159 rtlight->static_shadowtrispvs = NULL;
3160 rtlight->static_numlighttrispvsbytes = 0;
3161 rtlight->static_lighttrispvs = NULL;
3162 rtlight->compiled = false;
3166 void R_Shadow_UncompileWorldLights(void)
3170 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3171 for (lightindex = 0;lightindex < range;lightindex++)
3173 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3176 R_RTLight_Uncompile(&light->rtlight);
3180 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3184 // reset the count of frustum planes
3185 // see rtlight->cached_frustumplanes definition for how much this array
3187 rtlight->cached_numfrustumplanes = 0;
3189 // haven't implemented a culling path for ortho rendering
3190 if (!r_refdef.view.useperspective)
3192 // check if the light is on screen and copy the 4 planes if it is
3193 for (i = 0;i < 4;i++)
3194 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3197 for (i = 0;i < 4;i++)
3198 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3203 // generate a deformed frustum that includes the light origin, this is
3204 // used to cull shadow casting surfaces that can not possibly cast a
3205 // shadow onto the visible light-receiving surfaces, which can be a
3208 // if the light origin is onscreen the result will be 4 planes exactly
3209 // if the light origin is offscreen on only one axis the result will
3210 // be exactly 5 planes (split-side case)
3211 // if the light origin is offscreen on two axes the result will be
3212 // exactly 4 planes (stretched corner case)
3213 for (i = 0;i < 4;i++)
3215 // quickly reject standard frustum planes that put the light
3216 // origin outside the frustum
3217 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3220 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3222 // if all the standard frustum planes were accepted, the light is onscreen
3223 // otherwise we need to generate some more planes below...
3224 if (rtlight->cached_numfrustumplanes < 4)
3226 // at least one of the stock frustum planes failed, so we need to
3227 // create one or two custom planes to enclose the light origin
3228 for (i = 0;i < 4;i++)
3230 // create a plane using the view origin and light origin, and a
3231 // single point from the frustum corner set
3232 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3233 VectorNormalize(plane.normal);
3234 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3235 // see if this plane is backwards and flip it if so
3236 for (j = 0;j < 4;j++)
3237 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3241 VectorNegate(plane.normal, plane.normal);
3243 // flipped plane, test again to see if it is now valid
3244 for (j = 0;j < 4;j++)
3245 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3247 // if the plane is still not valid, then it is dividing the
3248 // frustum and has to be rejected
3252 // we have created a valid plane, compute extra info
3253 PlaneClassify(&plane);
3255 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3257 // if we've found 5 frustum planes then we have constructed a
3258 // proper split-side case and do not need to keep searching for
3259 // planes to enclose the light origin
3260 if (rtlight->cached_numfrustumplanes == 5)
3268 for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
3270 plane = rtlight->cached_frustumplanes[i];
3271 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));
3276 // now add the light-space box planes if the light box is rotated, as any
3277 // caster outside the oriented light box is irrelevant (even if it passed
3278 // the worldspace light box, which is axial)
3279 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3281 for (i = 0;i < 6;i++)
3285 v[i >> 1] = (i & 1) ? -1 : 1;
3286 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3287 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3288 plane.dist = VectorNormalizeLength(plane.normal);
3289 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3290 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3296 // add the world-space reduced box planes
3297 for (i = 0;i < 6;i++)
3299 VectorClear(plane.normal);
3300 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3301 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
3302 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3311 // reduce all plane distances to tightly fit the rtlight cull box, which
3313 VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3314 VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3315 VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3316 VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3317 VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3318 VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3319 VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3320 VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3321 oldnum = rtlight->cached_numfrustumplanes;
3322 rtlight->cached_numfrustumplanes = 0;
3323 for (j = 0;j < oldnum;j++)
3325 // find the nearest point on the box to this plane
3326 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
3327 for (i = 1;i < 8;i++)
3329 dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
3330 if (bestdist > dist)
3333 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);
3334 // if the nearest point is near or behind the plane, we want this
3335 // plane, otherwise the plane is useless as it won't cull anything
3336 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
3338 PlaneClassify(&rtlight->cached_frustumplanes[j]);
3339 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
3346 void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
3350 RSurf_ActiveWorldEntity();
3352 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3355 GL_CullFace(GL_NONE);
3356 mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3357 for (;mesh;mesh = mesh->next)
3359 if (!mesh->sidetotals[r_shadow_shadowmapside])
3361 r_refdef.stats.lights_shadowtriangles += mesh->sidetotals[r_shadow_shadowmapside];
3362 if (mesh->vertex3fbuffer)
3363 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vertex3fbuffer);
3365 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer);
3366 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);
3370 else if (r_refdef.scene.worldentity->model)
3371 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);
3373 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3376 void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3378 qboolean zpass = false;
3381 int surfacelistindex;
3382 msurface_t *surface;
3384 // if triangle neighbors are disabled, shadowvolumes are disabled
3385 if (r_refdef.scene.worldmodel->brush.shadowmesh ? !r_refdef.scene.worldmodel->brush.shadowmesh->neighbor3i : !r_refdef.scene.worldmodel->surfmesh.data_neighbor3i)
3388 RSurf_ActiveWorldEntity();
3390 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3393 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
3395 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
3396 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
3398 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
3399 for (;mesh;mesh = mesh->next)
3401 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
3402 if (mesh->vertex3fbuffer)
3403 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vertex3fbuffer);
3405 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer);
3406 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
3408 // increment stencil if frontface is infront of depthbuffer
3409 GL_CullFace(r_refdef.view.cullface_back);
3410 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
3411 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);
3412 // decrement stencil if backface is infront of depthbuffer
3413 GL_CullFace(r_refdef.view.cullface_front);
3414 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
3416 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
3418 // decrement stencil if backface is behind depthbuffer
3419 GL_CullFace(r_refdef.view.cullface_front);
3420 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
3421 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);
3422 // increment stencil if frontface is behind depthbuffer
3423 GL_CullFace(r_refdef.view.cullface_back);
3424 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
3426 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);
3430 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh)
3432 // use the shadow trispvs calculated earlier by GetLightInfo to cull world triangles on this dynamic light
3433 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
3434 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
3436 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
3437 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
3438 if (CHECKPVSBIT(trispvs, t))
3439 shadowmarklist[numshadowmark++] = t;
3441 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);
3443 else if (numsurfaces)
3445 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);
3448 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3451 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3453 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3454 vec_t relativeshadowradius;
3455 RSurf_ActiveModelEntity(ent, false, false, false);
3456 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3457 // we need to re-init the shader for each entity because the matrix changed
3458 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3459 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3460 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3461 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3462 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3463 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3464 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3465 switch (r_shadow_rendermode)
3467 case R_SHADOW_RENDERMODE_SHADOWMAP2D:
3468 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
3471 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3474 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3477 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3479 // set up properties for rendering light onto this entity
3480 RSurf_ActiveModelEntity(ent, true, true, false);
3481 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3482 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3483 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3484 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3487 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
3489 if (!r_refdef.scene.worldmodel->DrawLight)
3492 // set up properties for rendering light onto this entity
3493 RSurf_ActiveWorldEntity();
3494 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3495 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3496 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3497 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3499 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
3501 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3504 void R_Shadow_DrawEntityLight(entity_render_t *ent)
3506 dp_model_t *model = ent->model;
3507 if (!model->DrawLight)
3510 R_Shadow_SetupEntityLight(ent);
3512 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3514 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3517 void R_Shadow_PrepareLight(rtlight_t *rtlight)
3521 int numleafs, numsurfaces;
3522 int *leaflist, *surfacelist;
3523 unsigned char *leafpvs;
3524 unsigned char *shadowtrispvs;
3525 unsigned char *lighttrispvs;
3526 //unsigned char *surfacesides;
3527 int numlightentities;
3528 int numlightentities_noselfshadow;
3529 int numshadowentities;
3530 int numshadowentities_noselfshadow;
3531 static entity_render_t *lightentities[MAX_EDICTS];
3532 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3533 static entity_render_t *shadowentities[MAX_EDICTS];
3534 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3537 rtlight->draw = false;
3539 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3540 // skip lights that are basically invisible (color 0 0 0)
3541 nolight = VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f);
3543 // loading is done before visibility checks because loading should happen
3544 // all at once at the start of a level, not when it stalls gameplay.
3545 // (especially important to benchmarks)
3547 if (rtlight->isstatic && !nolight && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
3549 if (rtlight->compiled)
3550 R_RTLight_Uncompile(rtlight);
3551 R_RTLight_Compile(rtlight);
3555 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
3557 // look up the light style value at this time
3558 f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3559 VectorScale(rtlight->color, f, rtlight->currentcolor);
3561 if (rtlight->selected)
3563 f = 2 + sin(realtime * M_PI * 4.0);
3564 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3568 // if lightstyle is currently off, don't draw the light
3569 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3572 // skip processing on corona-only lights
3576 // if the light box is offscreen, skip it
3577 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3580 VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
3581 VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
3583 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3585 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3587 // compiled light, world available and can receive realtime lighting
3588 // retrieve leaf information
3589 numleafs = rtlight->static_numleafs;
3590 leaflist = rtlight->static_leaflist;
3591 leafpvs = rtlight->static_leafpvs;
3592 numsurfaces = rtlight->static_numsurfaces;
3593 surfacelist = rtlight->static_surfacelist;
3594 //surfacesides = NULL;
3595 shadowtrispvs = rtlight->static_shadowtrispvs;
3596 lighttrispvs = rtlight->static_lighttrispvs;
3598 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3600 // dynamic light, world available and can receive realtime lighting
3601 // calculate lit surfaces and leafs
3602 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);
3603 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3604 leaflist = r_shadow_buffer_leaflist;
3605 leafpvs = r_shadow_buffer_leafpvs;
3606 surfacelist = r_shadow_buffer_surfacelist;
3607 //surfacesides = r_shadow_buffer_surfacesides;
3608 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3609 lighttrispvs = r_shadow_buffer_lighttrispvs;
3610 // if the reduced leaf bounds are offscreen, skip it
3611 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3622 //surfacesides = NULL;
3623 shadowtrispvs = NULL;
3624 lighttrispvs = NULL;
3626 // check if light is illuminating any visible leafs
3629 for (i = 0;i < numleafs;i++)
3630 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3636 // make a list of lit entities and shadow casting entities
3637 numlightentities = 0;
3638 numlightentities_noselfshadow = 0;
3639 numshadowentities = 0;
3640 numshadowentities_noselfshadow = 0;
3642 // add dynamic entities that are lit by the light
3643 for (i = 0;i < r_refdef.scene.numentities;i++)
3646 entity_render_t *ent = r_refdef.scene.entities[i];
3648 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3650 // skip the object entirely if it is not within the valid
3651 // shadow-casting region (which includes the lit region)
3652 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
3654 if (!(model = ent->model))
3656 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
3658 // this entity wants to receive light, is visible, and is
3659 // inside the light box
3660 // TODO: check if the surfaces in the model can receive light
3661 // so now check if it's in a leaf seen by the light
3662 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))
3664 if (ent->flags & RENDER_NOSELFSHADOW)
3665 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
3667 lightentities[numlightentities++] = ent;
3668 // since it is lit, it probably also casts a shadow...
3669 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3670 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3671 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3673 // note: exterior models without the RENDER_NOSELFSHADOW
3674 // flag still create a RENDER_NOSELFSHADOW shadow but
3675 // are lit normally, this means that they are
3676 // self-shadowing but do not shadow other
3677 // RENDER_NOSELFSHADOW entities such as the gun
3678 // (very weird, but keeps the player shadow off the gun)
3679 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3680 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3682 shadowentities[numshadowentities++] = ent;
3685 else if (ent->flags & RENDER_SHADOW)
3687 // this entity is not receiving light, but may still need to
3689 // TODO: check if the surfaces in the model can cast shadow
3690 // now check if it is in a leaf seen by the light
3691 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))
3693 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3694 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3695 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3697 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3698 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3700 shadowentities[numshadowentities++] = ent;
3705 // return if there's nothing at all to light
3706 if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
3709 // count this light in the r_speeds
3710 r_refdef.stats.lights++;
3712 // flag it as worth drawing later
3713 rtlight->draw = true;
3715 // cache all the animated entities that cast a shadow but are not visible
3716 for (i = 0;i < numshadowentities;i++)
3717 if (!shadowentities[i]->animcache_vertex3f)
3718 R_AnimCache_GetEntity(shadowentities[i], false, false);
3719 for (i = 0;i < numshadowentities_noselfshadow;i++)
3720 if (!shadowentities_noselfshadow[i]->animcache_vertex3f)
3721 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
3723 // allocate some temporary memory for rendering this light later in the frame
3724 // reusable buffers need to be copied, static data can be used as-is
3725 rtlight->cached_numlightentities = numlightentities;
3726 rtlight->cached_numlightentities_noselfshadow = numlightentities_noselfshadow;
3727 rtlight->cached_numshadowentities = numshadowentities;
3728 rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
3729 rtlight->cached_numsurfaces = numsurfaces;
3730 rtlight->cached_lightentities = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
3731 rtlight->cached_lightentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
3732 rtlight->cached_shadowentities = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
3733 rtlight->cached_shadowentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
3734 if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
3736 int numshadowtrispvsbytes = (((r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles) + 7) >> 3);
3737 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
3738 rtlight->cached_shadowtrispvs = (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
3739 rtlight->cached_lighttrispvs = (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
3740 rtlight->cached_surfacelist = (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
3744 // compiled light data
3745 rtlight->cached_shadowtrispvs = shadowtrispvs;
3746 rtlight->cached_lighttrispvs = lighttrispvs;
3747 rtlight->cached_surfacelist = surfacelist;
3751 void R_Shadow_DrawLight(rtlight_t *rtlight)
3755 unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
3756 int numlightentities;
3757 int numlightentities_noselfshadow;
3758 int numshadowentities;
3759 int numshadowentities_noselfshadow;
3760 entity_render_t **lightentities;
3761 entity_render_t **lightentities_noselfshadow;
3762 entity_render_t **shadowentities;
3763 entity_render_t **shadowentities_noselfshadow;
3765 static unsigned char entitysides[MAX_EDICTS];
3766 static unsigned char entitysides_noselfshadow[MAX_EDICTS];
3767 vec3_t nearestpoint;
3769 qboolean castshadows;
3772 // check if we cached this light this frame (meaning it is worth drawing)
3776 numlightentities = rtlight->cached_numlightentities;
3777 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
3778 numshadowentities = rtlight->cached_numshadowentities;
3779 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
3780 numsurfaces = rtlight->cached_numsurfaces;
3781 lightentities = rtlight->cached_lightentities;
3782 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
3783 shadowentities = rtlight->cached_shadowentities;
3784 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
3785 shadowtrispvs = rtlight->cached_shadowtrispvs;
3786 lighttrispvs = rtlight->cached_lighttrispvs;
3787 surfacelist = rtlight->cached_surfacelist;
3789 // set up a scissor rectangle for this light
3790 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3793 // don't let sound skip if going slow
3794 if (r_refdef.scene.extraupdate)
3797 // make this the active rtlight for rendering purposes
3798 R_Shadow_RenderMode_ActiveLight(rtlight);
3800 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
3802 // optionally draw visible shape of the shadow volumes
3803 // for performance analysis by level designers
3804 R_Shadow_RenderMode_VisibleShadowVolumes();
3806 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
3807 for (i = 0;i < numshadowentities;i++)
3808 R_Shadow_DrawEntityShadow(shadowentities[i]);
3809 for (i = 0;i < numshadowentities_noselfshadow;i++)
3810 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3811 R_Shadow_RenderMode_VisibleLighting(false, false);
3814 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
3816 // optionally draw the illuminated areas
3817 // for performance analysis by level designers
3818 R_Shadow_RenderMode_VisibleLighting(false, false);
3820 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3821 for (i = 0;i < numlightentities;i++)
3822 R_Shadow_DrawEntityLight(lightentities[i]);
3823 for (i = 0;i < numlightentities_noselfshadow;i++)
3824 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3827 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
3829 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
3830 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
3831 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
3832 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
3834 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance/rtlight->radius));
3835 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
3836 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
3838 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
3844 int receivermask = 0;
3845 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
3846 Matrix4x4_Abs(&radiustolight);
3848 r_shadow_shadowmaplod = 0;
3849 for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
3850 if ((r_shadow_shadowmapmaxsize >> i) > lodlinear)
3851 r_shadow_shadowmaplod = i;
3853 size = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
3855 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
3857 surfacesides = NULL;
3860 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3862 castermask = rtlight->static_shadowmap_casters;
3863 receivermask = rtlight->static_shadowmap_receivers;
3867 surfacesides = r_shadow_buffer_surfacesides;
3868 for(i = 0;i < numsurfaces;i++)
3870 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
3871 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3872 castermask |= surfacesides[i];
3873 receivermask |= surfacesides[i];
3877 if (receivermask < 0x3F)
3879 for (i = 0;i < numlightentities;i++)
3880 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3881 if (receivermask < 0x3F)
3882 for(i = 0; i < numlightentities_noselfshadow;i++)
3883 receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3886 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
3890 for (i = 0;i < numshadowentities;i++)
3891 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3892 for (i = 0;i < numshadowentities_noselfshadow;i++)
3893 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3896 //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
3898 // render shadow casters into 6 sided depth texture
3899 for (side = 0;side < 6;side++) if (receivermask & (1 << side))
3901 R_Shadow_RenderMode_ShadowMap(side, receivermask, size);
3902 if (! (castermask & (1 << side))) continue;
3904 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
3905 for (i = 0;i < numshadowentities;i++) if (entitysides[i] & (1 << side))
3906 R_Shadow_DrawEntityShadow(shadowentities[i]);
3909 if (numlightentities_noselfshadow)
3911 // render lighting using the depth texture as shadowmap
3912 // draw lighting in the unmasked areas
3913 R_Shadow_RenderMode_Lighting(false, false, true);
3914 for (i = 0;i < numlightentities_noselfshadow;i++)
3915 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3918 // render shadow casters into 6 sided depth texture
3919 if (numshadowentities_noselfshadow)
3921 for (side = 0;side < 6;side++) if ((receivermask & castermask) & (1 << side))
3923 R_Shadow_RenderMode_ShadowMap(side, 0, size);
3924 for (i = 0;i < numshadowentities_noselfshadow;i++) if (entitysides_noselfshadow[i] & (1 << side))
3925 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3929 // render lighting using the depth texture as shadowmap
3930 // draw lighting in the unmasked areas
3931 R_Shadow_RenderMode_Lighting(false, false, true);
3932 // draw lighting in the unmasked areas
3934 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3935 for (i = 0;i < numlightentities;i++)
3936 R_Shadow_DrawEntityLight(lightentities[i]);
3938 else if (castshadows && vid.stencil)
3940 // draw stencil shadow volumes to mask off pixels that are in shadow
3941 // so that they won't receive lighting
3942 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
3943 R_Shadow_ClearStencil();
3946 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
3947 for (i = 0;i < numshadowentities;i++)
3948 R_Shadow_DrawEntityShadow(shadowentities[i]);
3950 // draw lighting in the unmasked areas
3951 R_Shadow_RenderMode_Lighting(true, false, false);
3952 for (i = 0;i < numlightentities_noselfshadow;i++)
3953 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3955 for (i = 0;i < numshadowentities_noselfshadow;i++)
3956 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3958 // draw lighting in the unmasked areas
3959 R_Shadow_RenderMode_Lighting(true, false, false);
3961 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3962 for (i = 0;i < numlightentities;i++)
3963 R_Shadow_DrawEntityLight(lightentities[i]);
3967 // draw lighting in the unmasked areas
3968 R_Shadow_RenderMode_Lighting(false, false, false);
3970 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3971 for (i = 0;i < numlightentities;i++)
3972 R_Shadow_DrawEntityLight(lightentities[i]);
3973 for (i = 0;i < numlightentities_noselfshadow;i++)
3974 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3977 if (r_shadow_usingdeferredprepass)
3979 // when rendering deferred lighting, we simply rasterize the box
3980 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
3981 R_Shadow_RenderMode_DrawDeferredLight(false, true);
3982 else if (castshadows && vid.stencil)
3983 R_Shadow_RenderMode_DrawDeferredLight(true, false);
3985 R_Shadow_RenderMode_DrawDeferredLight(false, false);
3988 if (r_shadow_particletrace.integer)
3989 R_Shadow_RenderParticlesForLight(rtlight);
3992 static void R_Shadow_FreeDeferred(void)
3994 R_Mesh_DestroyFramebufferObject(r_shadow_prepassgeometryfbo);
3995 r_shadow_prepassgeometryfbo = 0;
3997 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusespecularfbo);
3998 r_shadow_prepasslightingdiffusespecularfbo = 0;
4000 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingdiffusefbo);
4001 r_shadow_prepasslightingdiffusefbo = 0;
4003 if (r_shadow_prepassgeometrydepthtexture)
4004 R_FreeTexture(r_shadow_prepassgeometrydepthtexture);
4005 r_shadow_prepassgeometrydepthtexture = NULL;
4007 if (r_shadow_prepassgeometrydepthcolortexture)
4008 R_FreeTexture(r_shadow_prepassgeometrydepthcolortexture);
4009 r_shadow_prepassgeometrydepthcolortexture = NULL;
4011 if (r_shadow_prepassgeometrynormalmaptexture)
4012 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
4013 r_shadow_prepassgeometrynormalmaptexture = NULL;
4015 if (r_shadow_prepasslightingdiffusetexture)
4016 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
4017 r_shadow_prepasslightingdiffusetexture = NULL;
4019 if (r_shadow_prepasslightingspeculartexture)
4020 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
4021 r_shadow_prepasslightingspeculartexture = NULL;
4024 void R_Shadow_DrawPrepass(void)
4032 entity_render_t *ent;
4033 float clearcolor[4];
4035 R_Mesh_ResetTextureState();
4037 GL_ColorMask(1,1,1,1);
4038 GL_BlendFunc(GL_ONE, GL_ZERO);
4041 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, r_shadow_prepassgeometrydepthcolortexture, NULL, NULL);
4042 Vector4Set(clearcolor, 0.5f,0.5f,0.5f,1.0f);
4043 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4044 if (r_timereport_active)
4045 R_TimeReport("prepasscleargeom");
4047 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
4048 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
4049 if (r_timereport_active)
4050 R_TimeReport("prepassworld");
4052 for (i = 0;i < r_refdef.scene.numentities;i++)
4054 if (!r_refdef.viewcache.entityvisible[i])
4056 ent = r_refdef.scene.entities[i];
4057 if (ent->model && ent->model->DrawPrepass != NULL)
4058 ent->model->DrawPrepass(ent);
4061 if (r_timereport_active)
4062 R_TimeReport("prepassmodels");
4064 GL_DepthMask(false);
4065 GL_ColorMask(1,1,1,1);
4068 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4069 Vector4Set(clearcolor, 0, 0, 0, 0);
4070 GL_Clear(GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
4071 if (r_timereport_active)
4072 R_TimeReport("prepassclearlit");
4074 R_Shadow_RenderMode_Begin();
4076 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4077 if (r_shadow_debuglight.integer >= 0)
4079 lightindex = r_shadow_debuglight.integer;
4080 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4081 if (light && (light->flags & flag) && light->rtlight.draw)
4082 R_Shadow_DrawLight(&light->rtlight);
4086 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4087 for (lightindex = 0;lightindex < range;lightindex++)
4089 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4090 if (light && (light->flags & flag) && light->rtlight.draw)
4091 R_Shadow_DrawLight(&light->rtlight);
4094 if (r_refdef.scene.rtdlight)
4095 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4096 if (r_refdef.scene.lights[lnum]->draw)
4097 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4099 R_Mesh_ResetRenderTargets();
4101 R_Shadow_RenderMode_End();
4103 if (r_timereport_active)
4104 R_TimeReport("prepasslights");
4107 void R_Shadow_DrawLightSprites(void);
4108 void R_Shadow_PrepareLights(void)
4118 if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4) ||
4119 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
4120 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20) ||
4121 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
4122 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
4123 r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
4124 R_Shadow_FreeShadowMaps();
4126 r_shadow_usingshadowmaportho = false;
4128 switch (vid.renderpath)
4130 case RENDERPATH_GL20:
4131 case RENDERPATH_D3D9:
4132 case RENDERPATH_D3D10:
4133 case RENDERPATH_D3D11:
4134 case RENDERPATH_SOFT:
4135 case RENDERPATH_GLES2:
4136 if (!r_shadow_deferred.integer || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_STENCIL || !vid.support.ext_framebuffer_object || vid.maxdrawbuffers < 2)
4138 r_shadow_usingdeferredprepass = false;
4139 if (r_shadow_prepass_width)
4140 R_Shadow_FreeDeferred();
4141 r_shadow_prepass_width = r_shadow_prepass_height = 0;
4145 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
4147 R_Shadow_FreeDeferred();
4149 r_shadow_usingdeferredprepass = true;
4150 r_shadow_prepass_width = vid.width;
4151 r_shadow_prepass_height = vid.height;
4152 r_shadow_prepassgeometrydepthtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "prepassgeometrydepthmap", vid.width, vid.height, 24, false);
4153 switch (vid.renderpath)
4155 case RENDERPATH_D3D9:
4156 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);
4161 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);
4162 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);
4163 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);
4165 // set up the geometry pass fbo (depth + normalmap)
4166 r_shadow_prepassgeometryfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4167 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, r_shadow_prepassgeometrydepthcolortexture, NULL, NULL);
4168 // render depth into one texture and normalmap into the other
4169 if (qglDrawBuffersARB)
4171 qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);CHECKGLERROR
4172 qglReadBuffer(GL_NONE);CHECKGLERROR
4173 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4174 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4176 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4177 Cvar_SetValueQuick(&r_shadow_deferred, 0);
4178 r_shadow_usingdeferredprepass = false;
4182 // set up the lighting pass fbo (diffuse + specular)
4183 r_shadow_prepasslightingdiffusespecularfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4184 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusespecularfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4185 // render diffuse into one texture and specular into another,
4186 // with depth and normalmap bound as textures,
4187 // with depth bound as attachment as well
4188 if (qglDrawBuffersARB)
4190 qglDrawBuffersARB(2, r_shadow_prepasslightingdrawbuffers);CHECKGLERROR
4191 qglReadBuffer(GL_NONE);CHECKGLERROR
4192 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4193 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4195 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4196 Cvar_SetValueQuick(&r_shadow_deferred, 0);
4197 r_shadow_usingdeferredprepass = false;
4201 // set up the lighting pass fbo (diffuse)
4202 r_shadow_prepasslightingdiffusefbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
4203 R_Mesh_SetRenderTargets(r_shadow_prepasslightingdiffusefbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, NULL, NULL, NULL);
4204 // render diffuse into one texture,
4205 // with depth and normalmap bound as textures,
4206 // with depth bound as attachment as well
4207 if (qglDrawBuffersARB)
4209 qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);CHECKGLERROR
4210 qglReadBuffer(GL_NONE);CHECKGLERROR
4211 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4212 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4214 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4215 Cvar_SetValueQuick(&r_shadow_deferred, 0);
4216 r_shadow_usingdeferredprepass = false;
4221 case RENDERPATH_GL13:
4222 case RENDERPATH_GL11:
4223 r_shadow_usingdeferredprepass = false;
4227 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);
4229 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4230 if (r_shadow_debuglight.integer >= 0)
4232 lightindex = r_shadow_debuglight.integer;
4233 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4234 if (light && (light->flags & flag))
4235 R_Shadow_PrepareLight(&light->rtlight);
4239 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4240 for (lightindex = 0;lightindex < range;lightindex++)
4242 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4243 if (light && (light->flags & flag))
4244 R_Shadow_PrepareLight(&light->rtlight);
4247 if (r_refdef.scene.rtdlight)
4249 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4250 R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
4252 else if(gl_flashblend.integer)
4254 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4256 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
4257 f = (rtlight->style >= 0 ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4258 VectorScale(rtlight->color, f, rtlight->currentcolor);
4262 if (r_editlights.integer)
4263 R_Shadow_DrawLightSprites();
4266 void R_Shadow_DrawLights(void)
4274 R_Shadow_RenderMode_Begin();
4276 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4277 if (r_shadow_debuglight.integer >= 0)
4279 lightindex = r_shadow_debuglight.integer;
4280 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4281 if (light && (light->flags & flag))
4282 R_Shadow_DrawLight(&light->rtlight);
4286 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4287 for (lightindex = 0;lightindex < range;lightindex++)
4289 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4290 if (light && (light->flags & flag))
4291 R_Shadow_DrawLight(&light->rtlight);
4294 if (r_refdef.scene.rtdlight)
4295 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4296 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4298 R_Shadow_RenderMode_End();
4301 extern const float r_screenvertex3f[12];
4302 extern void R_SetupView(qboolean allowwaterclippingplane);
4303 extern void R_ResetViewRendering3D(void);
4304 extern void R_ResetViewRendering2D(void);
4305 extern cvar_t r_shadows;
4306 extern cvar_t r_shadows_darken;
4307 extern cvar_t r_shadows_drawafterrtlighting;
4308 extern cvar_t r_shadows_castfrombmodels;
4309 extern cvar_t r_shadows_throwdistance;
4310 extern cvar_t r_shadows_throwdirection;
4311 extern cvar_t r_shadows_focus;
4312 extern cvar_t r_shadows_shadowmapscale;
4314 void R_Shadow_PrepareModelShadows(void)
4317 float scale, size, radius, dot1, dot2;
4318 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
4319 entity_render_t *ent;
4321 if (!r_refdef.scene.numentities)
4324 switch (r_shadow_shadowmode)
4326 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4327 if (r_shadows.integer >= 2)
4330 case R_SHADOW_SHADOWMODE_STENCIL:
4331 for (i = 0;i < r_refdef.scene.numentities;i++)
4333 ent = r_refdef.scene.entities[i];
4334 if (!ent->animcache_vertex3f && ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4335 R_AnimCache_GetEntity(ent, false, false);
4342 size = 2*r_shadow_shadowmapmaxsize;
4343 scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
4344 radius = 0.5f * size / scale;
4346 Math_atov(r_shadows_throwdirection.string, shadowdir);
4347 VectorNormalize(shadowdir);
4348 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4349 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4350 if (fabs(dot1) <= fabs(dot2))
4351 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4353 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4354 VectorNormalize(shadowforward);
4355 CrossProduct(shadowdir, shadowforward, shadowright);
4356 Math_atov(r_shadows_focus.string, shadowfocus);
4357 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4358 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4359 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4360 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4361 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4363 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4365 shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4366 shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4367 shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4368 shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4369 shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4370 shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4372 for (i = 0;i < r_refdef.scene.numentities;i++)
4374 ent = r_refdef.scene.entities[i];
4375 if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
4377 // cast shadows from anything of the map (submodels are optional)
4378 if (!ent->animcache_vertex3f && ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4379 R_AnimCache_GetEntity(ent, false, false);
4383 void R_DrawModelShadowMaps(void)
4386 float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
4387 entity_render_t *ent;
4388 vec3_t relativelightorigin;
4389 vec3_t relativelightdirection, relativeforward, relativeright;
4390 vec3_t relativeshadowmins, relativeshadowmaxs;
4391 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
4393 matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
4394 r_viewport_t viewport;
4396 float clearcolor[4];
4398 if (!r_refdef.scene.numentities)
4401 switch (r_shadow_shadowmode)
4403 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4409 R_ResetViewRendering3D();
4410 R_Shadow_RenderMode_Begin();
4411 R_Shadow_RenderMode_ActiveLight(NULL);
4413 switch (r_shadow_shadowmode)
4415 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4416 if (!r_shadow_shadowmap2dtexture)
4417 R_Shadow_MakeShadowMap(0, r_shadow_shadowmapmaxsize);
4418 fbo = r_shadow_fbo2d;
4419 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
4420 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
4421 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
4427 size = 2*r_shadow_shadowmapmaxsize;
4428 scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
4429 radius = 0.5f / scale;
4430 nearclip = -r_shadows_throwdistance.value;
4431 farclip = r_shadows_throwdistance.value;
4432 bias = r_shadow_shadowmapping_bias.value * r_shadow_shadowmapping_nearclip.value / (2 * r_shadows_throwdistance.value) * (1024.0f / size);
4434 r_shadow_shadowmap_parameters[0] = size;
4435 r_shadow_shadowmap_parameters[1] = size;
4436 r_shadow_shadowmap_parameters[2] = 1.0;
4437 r_shadow_shadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
4439 Math_atov(r_shadows_throwdirection.string, shadowdir);
4440 VectorNormalize(shadowdir);
4441 Math_atov(r_shadows_focus.string, shadowfocus);
4442 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4443 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4444 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4445 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4446 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4447 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4448 if (fabs(dot1) <= fabs(dot2))
4449 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4451 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4452 VectorNormalize(shadowforward);
4453 VectorM(scale, shadowforward, &m[0]);
4454 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4456 m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
4457 CrossProduct(shadowdir, shadowforward, shadowright);
4458 VectorM(scale, shadowright, &m[4]);
4459 m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
4460 VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
4461 m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
4462 Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
4463 Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
4464 R_Viewport_InitOrtho(&viewport, &cameramatrix, 0, 0, size, size, 0, 0, 1, 1, 0, -1, NULL);
4466 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4468 R_Mesh_SetRenderTargets(fbo, r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
4469 R_SetupShader_DepthOrShadow();
4470 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
4473 R_SetViewport(&viewport);
4474 GL_Scissor(viewport.x, viewport.y, min(viewport.width + r_shadow_shadowmapborder, 2*r_shadow_shadowmapmaxsize), viewport.height + r_shadow_shadowmapborder);
4475 Vector4Set(clearcolor, 1,1,1,1);
4476 // in D3D9 we have to render to a color texture shadowmap
4477 // in GL we render directly to a depth texture only
4478 if (r_shadow_shadowmap2dtexture)
4479 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4481 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4482 // render into a slightly restricted region so that the borders of the
4483 // shadowmap area fade away, rather than streaking across everything
4484 // outside the usable area
4485 GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
4489 R_Mesh_ResetRenderTargets();
4490 R_SetupShader_ShowDepth();
4491 GL_ColorMask(1,1,1,1);
4492 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4495 for (i = 0;i < r_refdef.scene.numentities;i++)
4497 ent = r_refdef.scene.entities[i];
4499 // cast shadows from anything of the map (submodels are optional)
4500 if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4502 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4503 Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
4504 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4505 Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
4506 Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
4507 relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4508 relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4509 relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4510 relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4511 relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4512 relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4513 RSurf_ActiveModelEntity(ent, false, false, false);
4514 ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
4515 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4522 unsigned char *rawpixels = Z_Malloc(viewport.width*viewport.height*4);
4524 qglReadPixels(viewport.x, viewport.y, viewport.width, viewport.height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, rawpixels);
4526 Image_WriteTGABGRA("r_shadows_2.tga", viewport.width, viewport.height, rawpixels);
4527 Cvar_SetValueQuick(&r_test, 0);
4532 R_Shadow_RenderMode_End();
4534 Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
4535 Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
4536 Matrix4x4_CreateScale3(&scalematrix, size, -size, 1);
4537 Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
4538 Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
4539 Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
4541 switch (vid.renderpath)
4543 case RENDERPATH_GL11:
4544 case RENDERPATH_GL13:
4545 case RENDERPATH_GL20:
4546 case RENDERPATH_SOFT:
4547 case RENDERPATH_GLES2:
4549 case RENDERPATH_D3D9:
4550 case RENDERPATH_D3D10:
4551 case RENDERPATH_D3D11:
4552 #ifdef OPENGL_ORIENTATION
4553 r_shadow_shadowmapmatrix.m[0][0] *= -1.0f;
4554 r_shadow_shadowmapmatrix.m[0][1] *= -1.0f;
4555 r_shadow_shadowmapmatrix.m[0][2] *= -1.0f;
4556 r_shadow_shadowmapmatrix.m[0][3] *= -1.0f;
4558 r_shadow_shadowmapmatrix.m[0][0] *= -1.0f;
4559 r_shadow_shadowmapmatrix.m[1][0] *= -1.0f;
4560 r_shadow_shadowmapmatrix.m[2][0] *= -1.0f;
4561 r_shadow_shadowmapmatrix.m[3][0] *= -1.0f;
4566 r_shadow_usingshadowmaportho = true;
4567 switch (r_shadow_shadowmode)
4569 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4570 r_shadow_usingshadowmap2d = true;
4577 void R_DrawModelShadows(void)
4580 float relativethrowdistance;
4581 entity_render_t *ent;
4582 vec3_t relativelightorigin;
4583 vec3_t relativelightdirection;
4584 vec3_t relativeshadowmins, relativeshadowmaxs;
4585 vec3_t tmp, shadowdir;
4587 if (!r_refdef.scene.numentities || !vid.stencil || (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL && r_shadows.integer != 1))
4590 R_ResetViewRendering3D();
4591 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4592 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4593 R_Shadow_RenderMode_Begin();
4594 R_Shadow_RenderMode_ActiveLight(NULL);
4595 r_shadow_lightscissor[0] = r_refdef.view.x;
4596 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
4597 r_shadow_lightscissor[2] = r_refdef.view.width;
4598 r_shadow_lightscissor[3] = r_refdef.view.height;
4599 R_Shadow_RenderMode_StencilShadowVolumes(false);
4602 if (r_shadows.integer == 2)
4604 Math_atov(r_shadows_throwdirection.string, shadowdir);
4605 VectorNormalize(shadowdir);
4608 R_Shadow_ClearStencil();
4610 for (i = 0;i < r_refdef.scene.numentities;i++)
4612 ent = r_refdef.scene.entities[i];
4614 // cast shadows from anything of the map (submodels are optional)
4615 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4617 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4618 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
4619 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
4620 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
4621 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4624 if(ent->entitynumber != 0)
4626 if(ent->entitynumber >= MAX_EDICTS) // csqc entity
4628 // FIXME handle this
4629 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4633 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
4634 int entnum, entnum2, recursion;
4635 entnum = entnum2 = ent->entitynumber;
4636 for(recursion = 32; recursion > 0; --recursion)
4638 entnum2 = cl.entities[entnum].state_current.tagentity;
4639 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
4644 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
4646 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
4647 // transform into modelspace of OUR entity
4648 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
4649 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
4652 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4656 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4659 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
4660 RSurf_ActiveModelEntity(ent, false, false, false);
4661 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4662 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4666 // not really the right mode, but this will disable any silly stencil features
4667 R_Shadow_RenderMode_End();
4669 // set up ortho view for rendering this pass
4670 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4671 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4672 //GL_ScissorTest(true);
4673 //R_EntityMatrix(&identitymatrix);
4674 //R_Mesh_ResetTextureState();
4675 R_ResetViewRendering2D();
4677 // set up a darkening blend on shadowed areas
4678 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4679 //GL_DepthRange(0, 1);
4680 //GL_DepthTest(false);
4681 //GL_DepthMask(false);
4682 //GL_PolygonOffset(0, 0);CHECKGLERROR
4683 GL_Color(0, 0, 0, r_shadows_darken.value);
4684 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4685 //GL_DepthFunc(GL_ALWAYS);
4686 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_NOTEQUAL, 128, 255);
4688 // apply the blend to the shadowed areas
4689 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, NULL);
4690 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
4691 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4693 // restore the viewport
4694 R_SetViewport(&r_refdef.view.viewport);
4696 // restore other state to normal
4697 //R_Shadow_RenderMode_End();
4700 void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4703 vec3_t centerorigin;
4705 // if it's too close, skip it
4706 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
4708 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4711 if (usequery && r_numqueries + 2 <= r_maxqueries)
4713 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4714 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4715 // 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
4716 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4718 switch(vid.renderpath)
4720 case RENDERPATH_GL20:
4721 case RENDERPATH_GL13:
4722 case RENDERPATH_GL11:
4723 case RENDERPATH_GLES2:
4725 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use GL_DepthFunc instead
4726 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
4727 GL_DepthFunc(GL_ALWAYS);
4728 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4729 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL);
4730 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4731 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4732 GL_DepthFunc(GL_LEQUAL);
4733 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
4734 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4735 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL);
4736 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4737 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4740 case RENDERPATH_D3D9:
4741 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4743 case RENDERPATH_D3D10:
4744 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4746 case RENDERPATH_D3D11:
4747 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4749 case RENDERPATH_SOFT:
4750 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4754 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4757 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
4759 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4762 GLint allpixels = 0, visiblepixels = 0;
4763 // now we have to check the query result
4764 if (rtlight->corona_queryindex_visiblepixels)
4766 switch(vid.renderpath)
4768 case RENDERPATH_GL20:
4769 case RENDERPATH_GL13:
4770 case RENDERPATH_GL11:
4771 case RENDERPATH_GLES2:
4773 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
4774 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
4777 case RENDERPATH_D3D9:
4778 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4780 case RENDERPATH_D3D10:
4781 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4783 case RENDERPATH_D3D11:
4784 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4786 case RENDERPATH_SOFT:
4787 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4790 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
4791 if (visiblepixels < 1 || allpixels < 1)
4793 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
4794 cscale *= rtlight->corona_visibility;
4798 // FIXME: these traces should scan all render entities instead of cl.world
4799 if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
4802 VectorScale(rtlight->currentcolor, cscale, color);
4803 if (VectorLength(color) > (1.0f / 256.0f))
4806 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
4809 VectorNegate(color, color);
4810 switch(vid.renderpath)
4812 case RENDERPATH_GL11:
4813 case RENDERPATH_GL13:
4814 case RENDERPATH_GL20:
4815 case RENDERPATH_GLES2:
4816 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
4818 case RENDERPATH_D3D9:
4820 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_SUBTRACT);
4823 case RENDERPATH_D3D10:
4824 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4826 case RENDERPATH_D3D11:
4827 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4829 case RENDERPATH_SOFT:
4830 DPSOFTRAST_BlendSubtract(true);
4834 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4835 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);
4836 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4839 switch(vid.renderpath)
4841 case RENDERPATH_GL11:
4842 case RENDERPATH_GL13:
4843 case RENDERPATH_GL20:
4844 case RENDERPATH_GLES2:
4845 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
4847 case RENDERPATH_D3D9:
4849 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_ADD);
4852 case RENDERPATH_D3D10:
4853 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4855 case RENDERPATH_D3D11:
4856 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4858 case RENDERPATH_SOFT:
4859 DPSOFTRAST_BlendSubtract(false);
4866 void R_Shadow_DrawCoronas(void)
4869 qboolean usequery = false;
4874 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4876 if (r_waterstate.renderingscene)
4878 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4879 R_EntityMatrix(&identitymatrix);
4881 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4883 // check occlusion of coronas
4884 // use GL_ARB_occlusion_query if available
4885 // otherwise use raytraces
4887 switch (vid.renderpath)
4889 case RENDERPATH_GL11:
4890 case RENDERPATH_GL13:
4891 case RENDERPATH_GL20:
4892 case RENDERPATH_GLES2:
4893 usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
4896 GL_ColorMask(0,0,0,0);
4897 if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
4898 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
4901 r_maxqueries = (range + r_refdef.scene.numlights) * 4;
4902 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
4904 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
4907 RSurf_ActiveWorldEntity();
4908 GL_BlendFunc(GL_ONE, GL_ZERO);
4909 GL_CullFace(GL_NONE);
4910 GL_DepthMask(false);
4911 GL_DepthRange(0, 1);
4912 GL_PolygonOffset(0, 0);
4914 R_Mesh_ResetTextureState();
4915 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
4918 case RENDERPATH_D3D9:
4920 //Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4922 case RENDERPATH_D3D10:
4923 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4925 case RENDERPATH_D3D11:
4926 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4928 case RENDERPATH_SOFT:
4930 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4933 for (lightindex = 0;lightindex < range;lightindex++)
4935 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4938 rtlight = &light->rtlight;
4939 rtlight->corona_visibility = 0;
4940 rtlight->corona_queryindex_visiblepixels = 0;
4941 rtlight->corona_queryindex_allpixels = 0;
4942 if (!(rtlight->flags & flag))
4944 if (rtlight->corona <= 0)
4946 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4948 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4950 for (i = 0;i < r_refdef.scene.numlights;i++)
4952 rtlight = r_refdef.scene.lights[i];
4953 rtlight->corona_visibility = 0;
4954 rtlight->corona_queryindex_visiblepixels = 0;
4955 rtlight->corona_queryindex_allpixels = 0;
4956 if (!(rtlight->flags & flag))
4958 if (rtlight->corona <= 0)
4960 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4963 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4965 // now draw the coronas using the query data for intensity info
4966 for (lightindex = 0;lightindex < range;lightindex++)
4968 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4971 rtlight = &light->rtlight;
4972 if (rtlight->corona_visibility <= 0)
4974 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4976 for (i = 0;i < r_refdef.scene.numlights;i++)
4978 rtlight = r_refdef.scene.lights[i];
4979 if (rtlight->corona_visibility <= 0)
4981 if (gl_flashblend.integer)
4982 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4984 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4990 dlight_t *R_Shadow_NewWorldLight(void)
4992 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4995 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)
4998 // validate parameters
4999 if (style < 0 || style >= MAX_LIGHTSTYLES)
5001 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
5007 // copy to light properties
5008 VectorCopy(origin, light->origin);
5009 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
5010 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
5011 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
5013 light->color[0] = max(color[0], 0);
5014 light->color[1] = max(color[1], 0);
5015 light->color[2] = max(color[2], 0);
5017 light->color[0] = color[0];
5018 light->color[1] = color[1];
5019 light->color[2] = color[2];
5020 light->radius = max(radius, 0);
5021 light->style = style;
5022 light->shadow = shadowenable;
5023 light->corona = corona;
5024 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
5025 light->coronasizescale = coronasizescale;
5026 light->ambientscale = ambientscale;
5027 light->diffusescale = diffusescale;
5028 light->specularscale = specularscale;
5029 light->flags = flags;
5031 // update renderable light data
5032 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
5033 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);
5036 void R_Shadow_FreeWorldLight(dlight_t *light)
5038 if (r_shadow_selectedlight == light)
5039 r_shadow_selectedlight = NULL;
5040 R_RTLight_Uncompile(&light->rtlight);
5041 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
5044 void R_Shadow_ClearWorldLights(void)
5048 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5049 for (lightindex = 0;lightindex < range;lightindex++)
5051 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5053 R_Shadow_FreeWorldLight(light);
5055 r_shadow_selectedlight = NULL;
5058 void R_Shadow_SelectLight(dlight_t *light)
5060 if (r_shadow_selectedlight)
5061 r_shadow_selectedlight->selected = false;
5062 r_shadow_selectedlight = light;
5063 if (r_shadow_selectedlight)
5064 r_shadow_selectedlight->selected = true;
5067 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
5069 // this is never batched (there can be only one)
5071 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
5072 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
5073 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5076 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
5081 skinframe_t *skinframe;
5084 // this is never batched (due to the ent parameter changing every time)
5085 // so numsurfaces == 1 and surfacelist[0] == lightnumber
5086 const dlight_t *light = (dlight_t *)ent;
5089 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
5092 VectorScale(light->color, intensity, spritecolor);
5093 if (VectorLength(spritecolor) < 0.1732f)
5094 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
5095 if (VectorLength(spritecolor) > 1.0f)
5096 VectorNormalize(spritecolor);
5098 // draw light sprite
5099 if (light->cubemapname[0] && !light->shadow)
5100 skinframe = r_editlights_sprcubemapnoshadowlight;
5101 else if (light->cubemapname[0])
5102 skinframe = r_editlights_sprcubemaplight;
5103 else if (!light->shadow)
5104 skinframe = r_editlights_sprnoshadowlight;
5106 skinframe = r_editlights_sprlight;
5108 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);
5109 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5111 // draw selection sprite if light is selected
5112 if (light->selected)
5114 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
5115 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5116 // VorteX todo: add normalmode/realtime mode light overlay sprites?
5120 void R_Shadow_DrawLightSprites(void)
5124 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5125 for (lightindex = 0;lightindex < range;lightindex++)
5127 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5129 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
5131 if (!r_editlights_lockcursor)
5132 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
5135 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
5140 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
5141 if (lightindex >= range)
5143 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5146 rtlight = &light->rtlight;
5147 //if (!(rtlight->flags & flag))
5149 VectorCopy(rtlight->shadoworigin, origin);
5150 *radius = rtlight->radius;
5151 VectorCopy(rtlight->color, color);
5155 void R_Shadow_SelectLightInView(void)
5157 float bestrating, rating, temp[3];
5161 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5165 if (r_editlights_lockcursor)
5167 for (lightindex = 0;lightindex < range;lightindex++)
5169 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5172 VectorSubtract(light->origin, r_refdef.view.origin, temp);
5173 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
5176 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
5177 if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1.0f)
5179 bestrating = rating;
5184 R_Shadow_SelectLight(best);
5187 void R_Shadow_LoadWorldLights(void)
5189 int n, a, style, shadow, flags;
5190 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
5191 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
5192 if (cl.worldmodel == NULL)
5194 Con_Print("No map loaded.\n");
5197 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
5198 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5208 for (;COM_Parse(t, true) && strcmp(
5209 if (COM_Parse(t, true))
5211 if (com_token[0] == '!')
5214 origin[0] = atof(com_token+1);
5217 origin[0] = atof(com_token);
5222 while (*s && *s != '\n' && *s != '\r')
5228 // check for modifier flags
5235 #if _MSC_VER >= 1400
5236 #define sscanf sscanf_s
5238 cubemapname[sizeof(cubemapname)-1] = 0;
5239 #if MAX_QPATH != 128
5240 #error update this code if MAX_QPATH changes
5242 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
5243 #if _MSC_VER >= 1400
5244 , sizeof(cubemapname)
5246 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
5249 flags = LIGHTFLAG_REALTIMEMODE;
5257 coronasizescale = 0.25f;
5259 VectorClear(angles);
5262 if (a < 9 || !strcmp(cubemapname, "\"\""))
5264 // remove quotes on cubemapname
5265 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
5268 namelen = strlen(cubemapname) - 2;
5269 memmove(cubemapname, cubemapname + 1, namelen);
5270 cubemapname[namelen] = '\0';
5274 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);
5277 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5285 Con_Printf("invalid rtlights file \"%s\"\n", name);
5286 Mem_Free(lightsstring);
5290 void R_Shadow_SaveWorldLights(void)
5294 size_t bufchars, bufmaxchars;
5296 char name[MAX_QPATH];
5297 char line[MAX_INPUTLINE];
5298 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
5299 // I hate lines which are 3 times my screen size :( --blub
5302 if (cl.worldmodel == NULL)
5304 Con_Print("No map loaded.\n");
5307 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
5308 bufchars = bufmaxchars = 0;
5310 for (lightindex = 0;lightindex < range;lightindex++)
5312 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5315 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
5316 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);
5317 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
5318 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]);
5320 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);
5321 if (bufchars + strlen(line) > bufmaxchars)
5323 bufmaxchars = bufchars + strlen(line) + 2048;
5325 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
5329 memcpy(buf, oldbuf, bufchars);
5335 memcpy(buf + bufchars, line, strlen(line));
5336 bufchars += strlen(line);
5340 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
5345 void R_Shadow_LoadLightsFile(void)
5348 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
5349 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
5350 if (cl.worldmodel == NULL)
5352 Con_Print("No map loaded.\n");
5355 dpsnprintf(name, sizeof(name), "%s.lights", cl.worldnamenoextension);
5356 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5364 while (*s && *s != '\n' && *s != '\r')
5370 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);
5374 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);
5377 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
5378 radius = bound(15, radius, 4096);
5379 VectorScale(color, (2.0f / (8388608.0f)), color);
5380 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5388 Con_Printf("invalid lights file \"%s\"\n", name);
5389 Mem_Free(lightsstring);
5393 // tyrlite/hmap2 light types in the delay field
5394 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
5396 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
5408 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
5409 char key[256], value[MAX_INPUTLINE];
5411 if (cl.worldmodel == NULL)
5413 Con_Print("No map loaded.\n");
5416 // try to load a .ent file first
5417 dpsnprintf(key, sizeof(key), "%s.ent", cl.worldnamenoextension);
5418 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
5419 // and if that is not found, fall back to the bsp file entity string
5421 data = cl.worldmodel->brush.entities;
5424 for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
5426 type = LIGHTTYPE_MINUSX;
5427 origin[0] = origin[1] = origin[2] = 0;
5428 originhack[0] = originhack[1] = originhack[2] = 0;
5429 angles[0] = angles[1] = angles[2] = 0;
5430 color[0] = color[1] = color[2] = 1;
5431 light[0] = light[1] = light[2] = 1;light[3] = 300;
5432 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
5442 if (!COM_ParseToken_Simple(&data, false, false))
5444 if (com_token[0] == '}')
5445 break; // end of entity
5446 if (com_token[0] == '_')
5447 strlcpy(key, com_token + 1, sizeof(key));
5449 strlcpy(key, com_token, sizeof(key));
5450 while (key[strlen(key)-1] == ' ') // remove trailing spaces
5451 key[strlen(key)-1] = 0;
5452 if (!COM_ParseToken_Simple(&data, false, false))
5454 strlcpy(value, com_token, sizeof(value));
5456 // now that we have the key pair worked out...
5457 if (!strcmp("light", key))
5459 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5463 light[0] = vec[0] * (1.0f / 256.0f);
5464 light[1] = vec[0] * (1.0f / 256.0f);
5465 light[2] = vec[0] * (1.0f / 256.0f);
5471 light[0] = vec[0] * (1.0f / 255.0f);
5472 light[1] = vec[1] * (1.0f / 255.0f);
5473 light[2] = vec[2] * (1.0f / 255.0f);
5477 else if (!strcmp("delay", key))
5479 else if (!strcmp("origin", key))
5480 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5481 else if (!strcmp("angle", key))
5482 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5483 else if (!strcmp("angles", key))
5484 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5485 else if (!strcmp("color", key))
5486 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5487 else if (!strcmp("wait", key))
5488 fadescale = atof(value);
5489 else if (!strcmp("classname", key))
5491 if (!strncmp(value, "light", 5))
5494 if (!strcmp(value, "light_fluoro"))
5499 overridecolor[0] = 1;
5500 overridecolor[1] = 1;
5501 overridecolor[2] = 1;
5503 if (!strcmp(value, "light_fluorospark"))
5508 overridecolor[0] = 1;
5509 overridecolor[1] = 1;
5510 overridecolor[2] = 1;
5512 if (!strcmp(value, "light_globe"))
5517 overridecolor[0] = 1;
5518 overridecolor[1] = 0.8;
5519 overridecolor[2] = 0.4;
5521 if (!strcmp(value, "light_flame_large_yellow"))
5526 overridecolor[0] = 1;
5527 overridecolor[1] = 0.5;
5528 overridecolor[2] = 0.1;
5530 if (!strcmp(value, "light_flame_small_yellow"))
5535 overridecolor[0] = 1;
5536 overridecolor[1] = 0.5;
5537 overridecolor[2] = 0.1;
5539 if (!strcmp(value, "light_torch_small_white"))
5544 overridecolor[0] = 1;
5545 overridecolor[1] = 0.5;
5546 overridecolor[2] = 0.1;
5548 if (!strcmp(value, "light_torch_small_walltorch"))
5553 overridecolor[0] = 1;
5554 overridecolor[1] = 0.5;
5555 overridecolor[2] = 0.1;
5559 else if (!strcmp("style", key))
5560 style = atoi(value);
5561 else if (!strcmp("skin", key))
5562 skin = (int)atof(value);
5563 else if (!strcmp("pflags", key))
5564 pflags = (int)atof(value);
5565 //else if (!strcmp("effects", key))
5566 // effects = (int)atof(value);
5567 else if (cl.worldmodel->type == mod_brushq3)
5569 if (!strcmp("scale", key))
5570 lightscale = atof(value);
5571 if (!strcmp("fade", key))
5572 fadescale = atof(value);
5577 if (lightscale <= 0)
5581 if (color[0] == color[1] && color[0] == color[2])
5583 color[0] *= overridecolor[0];
5584 color[1] *= overridecolor[1];
5585 color[2] *= overridecolor[2];
5587 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5588 color[0] = color[0] * light[0];
5589 color[1] = color[1] * light[1];
5590 color[2] = color[2] * light[2];
5593 case LIGHTTYPE_MINUSX:
5595 case LIGHTTYPE_RECIPX:
5597 VectorScale(color, (1.0f / 16.0f), color);
5599 case LIGHTTYPE_RECIPXX:
5601 VectorScale(color, (1.0f / 16.0f), color);
5604 case LIGHTTYPE_NONE:
5608 case LIGHTTYPE_MINUSXX:
5611 VectorAdd(origin, originhack, origin);
5613 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);
5616 Mem_Free(entfiledata);
5620 void R_Shadow_SetCursorLocationForView(void)
5623 vec3_t dest, endpos;
5625 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5626 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
5627 if (trace.fraction < 1)
5629 dist = trace.fraction * r_editlights_cursordistance.value;
5630 push = r_editlights_cursorpushback.value;
5634 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5635 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5639 VectorClear( endpos );
5641 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5642 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5643 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5646 void R_Shadow_UpdateWorldLightSelection(void)
5648 if (r_editlights.integer)
5650 R_Shadow_SetCursorLocationForView();
5651 R_Shadow_SelectLightInView();
5654 R_Shadow_SelectLight(NULL);
5657 void R_Shadow_EditLights_Clear_f(void)
5659 R_Shadow_ClearWorldLights();
5662 void R_Shadow_EditLights_Reload_f(void)
5666 strlcpy(r_shadow_mapname, cl.worldname, sizeof(r_shadow_mapname));
5667 R_Shadow_ClearWorldLights();
5668 R_Shadow_LoadWorldLights();
5669 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5671 R_Shadow_LoadLightsFile();
5672 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5673 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5677 void R_Shadow_EditLights_Save_f(void)
5681 R_Shadow_SaveWorldLights();
5684 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
5686 R_Shadow_ClearWorldLights();
5687 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5690 void R_Shadow_EditLights_ImportLightsFile_f(void)
5692 R_Shadow_ClearWorldLights();
5693 R_Shadow_LoadLightsFile();
5696 void R_Shadow_EditLights_Spawn_f(void)
5699 if (!r_editlights.integer)
5701 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5704 if (Cmd_Argc() != 1)
5706 Con_Print("r_editlights_spawn does not take parameters\n");
5709 color[0] = color[1] = color[2] = 1;
5710 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5713 void R_Shadow_EditLights_Edit_f(void)
5715 vec3_t origin, angles, color;
5716 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5717 int style, shadows, flags, normalmode, realtimemode;
5718 char cubemapname[MAX_INPUTLINE];
5719 if (!r_editlights.integer)
5721 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5724 if (!r_shadow_selectedlight)
5726 Con_Print("No selected light.\n");
5729 VectorCopy(r_shadow_selectedlight->origin, origin);
5730 VectorCopy(r_shadow_selectedlight->angles, angles);
5731 VectorCopy(r_shadow_selectedlight->color, color);
5732 radius = r_shadow_selectedlight->radius;
5733 style = r_shadow_selectedlight->style;
5734 if (r_shadow_selectedlight->cubemapname)
5735 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5738 shadows = r_shadow_selectedlight->shadow;
5739 corona = r_shadow_selectedlight->corona;
5740 coronasizescale = r_shadow_selectedlight->coronasizescale;
5741 ambientscale = r_shadow_selectedlight->ambientscale;
5742 diffusescale = r_shadow_selectedlight->diffusescale;
5743 specularscale = r_shadow_selectedlight->specularscale;
5744 flags = r_shadow_selectedlight->flags;
5745 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5746 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5747 if (!strcmp(Cmd_Argv(1), "origin"))
5749 if (Cmd_Argc() != 5)
5751 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5754 origin[0] = atof(Cmd_Argv(2));
5755 origin[1] = atof(Cmd_Argv(3));
5756 origin[2] = atof(Cmd_Argv(4));
5758 else if (!strcmp(Cmd_Argv(1), "originx"))
5760 if (Cmd_Argc() != 3)
5762 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5765 origin[0] = atof(Cmd_Argv(2));
5767 else if (!strcmp(Cmd_Argv(1), "originy"))
5769 if (Cmd_Argc() != 3)
5771 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5774 origin[1] = atof(Cmd_Argv(2));
5776 else if (!strcmp(Cmd_Argv(1), "originz"))
5778 if (Cmd_Argc() != 3)
5780 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5783 origin[2] = atof(Cmd_Argv(2));
5785 else if (!strcmp(Cmd_Argv(1), "move"))
5787 if (Cmd_Argc() != 5)
5789 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5792 origin[0] += atof(Cmd_Argv(2));
5793 origin[1] += atof(Cmd_Argv(3));
5794 origin[2] += atof(Cmd_Argv(4));
5796 else if (!strcmp(Cmd_Argv(1), "movex"))
5798 if (Cmd_Argc() != 3)
5800 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5803 origin[0] += atof(Cmd_Argv(2));
5805 else if (!strcmp(Cmd_Argv(1), "movey"))
5807 if (Cmd_Argc() != 3)
5809 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5812 origin[1] += atof(Cmd_Argv(2));
5814 else if (!strcmp(Cmd_Argv(1), "movez"))
5816 if (Cmd_Argc() != 3)
5818 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5821 origin[2] += atof(Cmd_Argv(2));
5823 else if (!strcmp(Cmd_Argv(1), "angles"))
5825 if (Cmd_Argc() != 5)
5827 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5830 angles[0] = atof(Cmd_Argv(2));
5831 angles[1] = atof(Cmd_Argv(3));
5832 angles[2] = atof(Cmd_Argv(4));
5834 else if (!strcmp(Cmd_Argv(1), "anglesx"))
5836 if (Cmd_Argc() != 3)
5838 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5841 angles[0] = atof(Cmd_Argv(2));
5843 else if (!strcmp(Cmd_Argv(1), "anglesy"))
5845 if (Cmd_Argc() != 3)
5847 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5850 angles[1] = atof(Cmd_Argv(2));
5852 else if (!strcmp(Cmd_Argv(1), "anglesz"))
5854 if (Cmd_Argc() != 3)
5856 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5859 angles[2] = atof(Cmd_Argv(2));
5861 else if (!strcmp(Cmd_Argv(1), "color"))
5863 if (Cmd_Argc() != 5)
5865 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
5868 color[0] = atof(Cmd_Argv(2));
5869 color[1] = atof(Cmd_Argv(3));
5870 color[2] = atof(Cmd_Argv(4));
5872 else if (!strcmp(Cmd_Argv(1), "radius"))
5874 if (Cmd_Argc() != 3)
5876 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5879 radius = atof(Cmd_Argv(2));
5881 else if (!strcmp(Cmd_Argv(1), "colorscale"))
5883 if (Cmd_Argc() == 3)
5885 double scale = atof(Cmd_Argv(2));
5892 if (Cmd_Argc() != 5)
5894 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
5897 color[0] *= atof(Cmd_Argv(2));
5898 color[1] *= atof(Cmd_Argv(3));
5899 color[2] *= atof(Cmd_Argv(4));
5902 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
5904 if (Cmd_Argc() != 3)
5906 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5909 radius *= atof(Cmd_Argv(2));
5911 else if (!strcmp(Cmd_Argv(1), "style"))
5913 if (Cmd_Argc() != 3)
5915 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5918 style = atoi(Cmd_Argv(2));
5920 else if (!strcmp(Cmd_Argv(1), "cubemap"))
5924 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5927 if (Cmd_Argc() == 3)
5928 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
5932 else if (!strcmp(Cmd_Argv(1), "shadows"))
5934 if (Cmd_Argc() != 3)
5936 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5939 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5941 else if (!strcmp(Cmd_Argv(1), "corona"))
5943 if (Cmd_Argc() != 3)
5945 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5948 corona = atof(Cmd_Argv(2));
5950 else if (!strcmp(Cmd_Argv(1), "coronasize"))
5952 if (Cmd_Argc() != 3)
5954 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5957 coronasizescale = atof(Cmd_Argv(2));
5959 else if (!strcmp(Cmd_Argv(1), "ambient"))
5961 if (Cmd_Argc() != 3)
5963 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5966 ambientscale = atof(Cmd_Argv(2));
5968 else if (!strcmp(Cmd_Argv(1), "diffuse"))
5970 if (Cmd_Argc() != 3)
5972 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5975 diffusescale = atof(Cmd_Argv(2));
5977 else if (!strcmp(Cmd_Argv(1), "specular"))
5979 if (Cmd_Argc() != 3)
5981 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5984 specularscale = atof(Cmd_Argv(2));
5986 else if (!strcmp(Cmd_Argv(1), "normalmode"))
5988 if (Cmd_Argc() != 3)
5990 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5993 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5995 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
5997 if (Cmd_Argc() != 3)
5999 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
6002 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
6006 Con_Print("usage: r_editlights_edit [property] [value]\n");
6007 Con_Print("Selected light's properties:\n");
6008 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
6009 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
6010 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
6011 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
6012 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
6013 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
6014 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
6015 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
6016 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
6017 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
6018 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
6019 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
6020 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
6021 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
6024 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
6025 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
6028 void R_Shadow_EditLights_EditAll_f(void)
6031 dlight_t *light, *oldselected;
6034 if (!r_editlights.integer)
6036 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
6040 oldselected = r_shadow_selectedlight;
6041 // EditLights doesn't seem to have a "remove" command or something so:
6042 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6043 for (lightindex = 0;lightindex < range;lightindex++)
6045 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6048 R_Shadow_SelectLight(light);
6049 R_Shadow_EditLights_Edit_f();
6051 // return to old selected (to not mess editing once selection is locked)
6052 R_Shadow_SelectLight(oldselected);
6055 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
6057 int lightnumber, lightcount;
6058 size_t lightindex, range;
6062 if (!r_editlights.integer)
6064 x = vid_conwidth.value - 240;
6066 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
6069 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6070 for (lightindex = 0;lightindex < range;lightindex++)
6072 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6075 if (light == r_shadow_selectedlight)
6076 lightnumber = lightindex;
6079 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;
6080 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;
6082 if (r_shadow_selectedlight == NULL)
6084 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;
6085 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;
6086 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;
6087 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;
6088 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;
6089 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;
6090 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;
6091 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;
6092 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;
6093 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;
6094 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;
6095 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;
6096 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;
6097 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;
6098 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;
6101 void R_Shadow_EditLights_ToggleShadow_f(void)
6103 if (!r_editlights.integer)
6105 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6108 if (!r_shadow_selectedlight)
6110 Con_Print("No selected light.\n");
6113 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);
6116 void R_Shadow_EditLights_ToggleCorona_f(void)
6118 if (!r_editlights.integer)
6120 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6123 if (!r_shadow_selectedlight)
6125 Con_Print("No selected light.\n");
6128 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);
6131 void R_Shadow_EditLights_Remove_f(void)
6133 if (!r_editlights.integer)
6135 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
6138 if (!r_shadow_selectedlight)
6140 Con_Print("No selected light.\n");
6143 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
6144 r_shadow_selectedlight = NULL;
6147 void R_Shadow_EditLights_Help_f(void)
6150 "Documentation on r_editlights system:\n"
6152 "r_editlights : enable/disable editing mode\n"
6153 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
6154 "r_editlights_cursorpushback : push back cursor this far from surface\n"
6155 "r_editlights_cursorpushoff : push cursor off surface this far\n"
6156 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
6157 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
6159 "r_editlights_help : this help\n"
6160 "r_editlights_clear : remove all lights\n"
6161 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
6162 "r_editlights_lock : lock selection to current light, if already locked - unlock\n"
6163 "r_editlights_save : save to .rtlights file\n"
6164 "r_editlights_spawn : create a light with default settings\n"
6165 "r_editlights_edit command : edit selected light - more documentation below\n"
6166 "r_editlights_remove : remove selected light\n"
6167 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
6168 "r_editlights_importlightentitiesfrommap : reload light entities\n"
6169 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
6171 "origin x y z : set light location\n"
6172 "originx x: set x component of light location\n"
6173 "originy y: set y component of light location\n"
6174 "originz z: set z component of light location\n"
6175 "move x y z : adjust light location\n"
6176 "movex x: adjust x component of light location\n"
6177 "movey y: adjust y component of light location\n"
6178 "movez z: adjust z component of light location\n"
6179 "angles x y z : set light angles\n"
6180 "anglesx x: set x component of light angles\n"
6181 "anglesy y: set y component of light angles\n"
6182 "anglesz z: set z component of light angles\n"
6183 "color r g b : set color of light (can be brighter than 1 1 1)\n"
6184 "radius radius : set radius (size) of light\n"
6185 "colorscale grey : multiply color of light (1 does nothing)\n"
6186 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
6187 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
6188 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
6189 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
6190 "cubemap basename : set filter cubemap of light (not yet supported)\n"
6191 "shadows 1/0 : turn on/off shadows\n"
6192 "corona n : set corona intensity\n"
6193 "coronasize n : set corona size (0-1)\n"
6194 "ambient n : set ambient intensity (0-1)\n"
6195 "diffuse n : set diffuse intensity (0-1)\n"
6196 "specular n : set specular intensity (0-1)\n"
6197 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
6198 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
6199 "<nothing> : print light properties to console\n"
6203 void R_Shadow_EditLights_CopyInfo_f(void)
6205 if (!r_editlights.integer)
6207 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
6210 if (!r_shadow_selectedlight)
6212 Con_Print("No selected light.\n");
6215 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
6216 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
6217 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
6218 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
6219 if (r_shadow_selectedlight->cubemapname)
6220 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
6222 r_shadow_bufferlight.cubemapname[0] = 0;
6223 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
6224 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
6225 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
6226 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
6227 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
6228 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
6229 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
6232 void R_Shadow_EditLights_PasteInfo_f(void)
6234 if (!r_editlights.integer)
6236 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
6239 if (!r_shadow_selectedlight)
6241 Con_Print("No selected light.\n");
6244 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);
6247 void R_Shadow_EditLights_Lock_f(void)
6249 if (!r_editlights.integer)
6251 Con_Print("Cannot lock on light when not in editing mode. Set r_editlights to 1.\n");
6254 if (r_editlights_lockcursor)
6256 r_editlights_lockcursor = false;
6259 if (!r_shadow_selectedlight)
6261 Con_Print("No selected light to lock on.\n");
6264 r_editlights_lockcursor = true;
6267 void R_Shadow_EditLights_Init(void)
6269 Cvar_RegisterVariable(&r_editlights);
6270 Cvar_RegisterVariable(&r_editlights_cursordistance);
6271 Cvar_RegisterVariable(&r_editlights_cursorpushback);
6272 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
6273 Cvar_RegisterVariable(&r_editlights_cursorgrid);
6274 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
6275 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
6276 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
6277 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)");
6278 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
6279 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
6280 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
6281 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)");
6282 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
6283 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
6284 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
6285 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
6286 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
6287 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
6288 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)");
6289 Cmd_AddCommand("r_editlights_lock", R_Shadow_EditLights_Lock_f, "lock selection to current light, if already locked - unlock");
6295 =============================================================================
6299 =============================================================================
6302 void R_CompleteLightPoint(vec3_t ambient, vec3_t diffuse, vec3_t lightdir, const vec3_t p, const int flags)
6304 int i, numlights, flag;
6307 float relativepoint[3];
6316 if (r_fullbright.integer)
6318 VectorSet(ambient, 1, 1, 1);
6319 VectorClear(diffuse);
6320 VectorClear(lightdir);
6324 if (flags & LP_LIGHTMAP)
6326 VectorSet(ambient, r_refdef.scene.ambient, r_refdef.scene.ambient, r_refdef.scene.ambient);
6327 VectorClear(diffuse);
6328 VectorClear(lightdir);
6329 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
6330 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambient, diffuse, lightdir);
6334 memset(sample, 0, sizeof(sample));
6335 VectorSet(sample, r_refdef.scene.ambient, r_refdef.scene.ambient, r_refdef.scene.ambient);
6337 if ((flags & LP_LIGHTMAP) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
6340 VectorClear(tempambient);
6342 VectorClear(relativepoint);
6343 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, tempambient, color, relativepoint);
6344 VectorScale(tempambient, r_refdef.lightmapintensity, tempambient);
6345 VectorScale(color, r_refdef.lightmapintensity, color);
6346 VectorAdd(sample, tempambient, sample);
6347 VectorMA(sample , 0.5f , color, sample );
6348 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
6349 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
6350 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
6351 // calculate a weighted average light direction as well
6352 intensity = VectorLength(color);
6353 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
6356 if (flags & LP_RTWORLD)
6358 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
6359 numlights = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
6360 for (i = 0; i < numlights; i++)
6362 dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
6365 light = &dlight->rtlight;
6366 if (!(light->flags & flag))
6369 lightradius2 = light->radius * light->radius;
6370 VectorSubtract(light->shadoworigin, p, relativepoint);
6371 dist2 = VectorLength2(relativepoint);
6372 if (dist2 >= lightradius2)
6374 dist = sqrt(dist2) / light->radius;
6375 intensity = min(1.0f, (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) * r_shadow_lightintensityscale.value;
6376 if (intensity <= 0.0f)
6378 if (light->shadow && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
6380 // scale down intensity to add to both ambient and diffuse
6381 //intensity *= 0.5f;
6382 VectorNormalize(relativepoint);
6383 VectorScale(light->currentcolor, intensity, color);
6384 VectorMA(sample , 0.5f , color, sample );
6385 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
6386 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
6387 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
6388 // calculate a weighted average light direction as well
6389 intensity *= VectorLength(color);
6390 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
6394 if (flags & LP_DYNLIGHT)
6397 for (i = 0;i < r_refdef.scene.numlights;i++)
6399 light = r_refdef.scene.lights[i];
6401 lightradius2 = light->radius * light->radius;
6402 VectorSubtract(light->shadoworigin, p, relativepoint);
6403 dist2 = VectorLength2(relativepoint);
6404 if (dist2 >= lightradius2)
6406 dist = sqrt(dist2) / light->radius;
6407 intensity = (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist) * r_shadow_lightintensityscale.value;
6408 if (intensity <= 0.0f)
6410 if (light->shadow && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
6412 // scale down intensity to add to both ambient and diffuse
6413 //intensity *= 0.5f;
6414 VectorNormalize(relativepoint);
6415 VectorScale(light->currentcolor, intensity, color);
6416 VectorMA(sample , 0.5f , color, sample );
6417 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
6418 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
6419 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
6420 // calculate a weighted average light direction as well
6421 intensity *= VectorLength(color);
6422 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
6426 // calculate the direction we'll use to reduce the sample to a directional light source
6427 VectorCopy(sample + 12, dir);
6428 //VectorSet(dir, sample[3] + sample[4] + sample[5], sample[6] + sample[7] + sample[8], sample[9] + sample[10] + sample[11]);
6429 VectorNormalize(dir);
6430 // extract the diffuse color along the chosen direction and scale it
6431 diffuse[0] = (dir[0]*sample[3] + dir[1]*sample[6] + dir[2]*sample[ 9] + sample[ 0]);
6432 diffuse[1] = (dir[0]*sample[4] + dir[1]*sample[7] + dir[2]*sample[10] + sample[ 1]);
6433 diffuse[2] = (dir[0]*sample[5] + dir[1]*sample[8] + dir[2]*sample[11] + sample[ 2]);
6434 // subtract some of diffuse from ambient
6435 VectorMA(sample, -0.333f, diffuse, ambient);
6436 // store the normalized lightdir
6437 VectorCopy(dir, lightdir);