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"
143 extern void R_Shadow_EditLights_Init(void);
145 typedef enum r_shadow_rendermode_e
147 R_SHADOW_RENDERMODE_NONE,
148 R_SHADOW_RENDERMODE_ZPASS_STENCIL,
149 R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL,
150 R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE,
151 R_SHADOW_RENDERMODE_ZFAIL_STENCIL,
152 R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL,
153 R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE,
154 R_SHADOW_RENDERMODE_LIGHT_VERTEX,
155 R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN,
156 R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN,
157 R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN,
158 R_SHADOW_RENDERMODE_LIGHT_GLSL,
159 R_SHADOW_RENDERMODE_VISIBLEVOLUMES,
160 R_SHADOW_RENDERMODE_VISIBLELIGHTING,
161 R_SHADOW_RENDERMODE_SHADOWMAP2D,
162 R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE,
163 R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE,
165 r_shadow_rendermode_t;
167 typedef enum r_shadow_shadowmode_e
169 R_SHADOW_SHADOWMODE_STENCIL,
170 R_SHADOW_SHADOWMODE_SHADOWMAP2D,
171 R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE,
172 R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE
174 r_shadow_shadowmode_t;
176 r_shadow_rendermode_t r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
177 r_shadow_rendermode_t r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_NONE;
178 r_shadow_rendermode_t r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_NONE;
179 r_shadow_rendermode_t r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_NONE;
180 qboolean r_shadow_usingshadowmaprect;
181 qboolean r_shadow_usingshadowmap2d;
182 qboolean r_shadow_usingshadowmapcube;
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_fborectangle;
193 GLuint r_shadow_fbocubeside[R_SHADOW_SHADOWMAP_NUMCUBEMAPS];
194 GLuint r_shadow_fbo2d;
195 r_shadow_shadowmode_t r_shadow_shadowmode;
196 int r_shadow_shadowmapfilterquality;
197 int r_shadow_shadowmaptexturetype;
198 int r_shadow_shadowmapdepthbits;
199 int r_shadow_shadowmapmaxsize;
200 qboolean r_shadow_shadowmapvsdct;
201 qboolean r_shadow_shadowmapsampler;
202 int r_shadow_shadowmappcf;
203 int r_shadow_shadowmapborder;
204 matrix4x4_t r_shadow_shadowmapmatrix;
205 int r_shadow_lightscissor[4];
206 qboolean r_shadow_usingdeferredprepass;
208 int maxshadowtriangles;
211 int maxshadowvertices;
212 float *shadowvertex3f;
222 unsigned char *shadowsides;
223 int *shadowsideslist;
230 int r_shadow_buffer_numleafpvsbytes;
231 unsigned char *r_shadow_buffer_visitingleafpvs;
232 unsigned char *r_shadow_buffer_leafpvs;
233 int *r_shadow_buffer_leaflist;
235 int r_shadow_buffer_numsurfacepvsbytes;
236 unsigned char *r_shadow_buffer_surfacepvs;
237 int *r_shadow_buffer_surfacelist;
238 unsigned char *r_shadow_buffer_surfacesides;
240 int r_shadow_buffer_numshadowtrispvsbytes;
241 unsigned char *r_shadow_buffer_shadowtrispvs;
242 int r_shadow_buffer_numlighttrispvsbytes;
243 unsigned char *r_shadow_buffer_lighttrispvs;
245 rtexturepool_t *r_shadow_texturepool;
246 rtexture_t *r_shadow_attenuationgradienttexture;
247 rtexture_t *r_shadow_attenuation2dtexture;
248 rtexture_t *r_shadow_attenuation3dtexture;
249 skinframe_t *r_shadow_lightcorona;
250 rtexture_t *r_shadow_shadowmaprectangletexture;
251 rtexture_t *r_shadow_shadowmap2dtexture;
252 rtexture_t *r_shadow_shadowmapcubetexture[R_SHADOW_SHADOWMAP_NUMCUBEMAPS];
253 rtexture_t *r_shadow_shadowmapvsdcttexture;
254 int r_shadow_shadowmapsize; // changes for each light based on distance
255 int r_shadow_shadowmaplod; // changes for each light based on distance
257 GLuint r_shadow_prepassgeometryfbo;
258 GLuint r_shadow_prepasslightingfbo;
259 int r_shadow_prepass_width;
260 int r_shadow_prepass_height;
261 rtexture_t *r_shadow_prepassgeometrydepthtexture;
262 rtexture_t *r_shadow_prepassgeometrynormalmaptexture;
263 rtexture_t *r_shadow_prepasslightingdiffusetexture;
264 rtexture_t *r_shadow_prepasslightingspeculartexture;
266 // lights are reloaded when this changes
267 char r_shadow_mapname[MAX_QPATH];
269 // used only for light filters (cubemaps)
270 rtexturepool_t *r_shadow_filters_texturepool;
272 static const GLenum r_shadow_prepasslightingdrawbuffers[2] = {GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT};
274 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"};
275 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"};
276 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
277 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"};
278 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)"};
279 //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"};
280 cvar_t r_shadow_usenormalmap = {CVAR_SAVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"};
281 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)"};
282 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"};
283 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
284 cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
285 cvar_t r_shadow_gloss2exponent = {0, "r_shadow_gloss2exponent", "32", "same as r_shadow_glossexponent but for forced gloss (gloss 2) surfaces"};
286 cvar_t r_shadow_glossexact = {0, "r_shadow_glossexact", "0", "use exact reflection math for gloss (slightly slower, but should look a tad better)"};
287 cvar_t r_shadow_lightattenuationdividebias = {0, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"};
288 cvar_t r_shadow_lightattenuationlinearscale = {0, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"};
289 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
290 cvar_t r_shadow_lightradiusscale = {0, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
291 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "0", "how far to cast shadows"};
292 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)"};
293 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
294 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
295 cvar_t r_shadow_realtime_dlight_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
296 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
297 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)"};
298 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"};
299 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
300 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
301 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"};
302 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)"};
303 cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "0", "enables portal-based culling optimization during compilation (overrides compilesvbsp)"};
304 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)"};
305 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"};
306 cvar_t r_shadow_shadowmapping_texturetype = {CVAR_SAVE, "r_shadow_shadowmapping_texturetype", "-1", "shadowmap texture types: -1 = auto-select, 0 = 2D, 1 = rectangle, 2 = cubemap"};
307 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)"};
308 cvar_t r_shadow_shadowmapping_depthbits = {CVAR_SAVE, "r_shadow_shadowmapping_depthbits", "24", "requested minimum shadowmap texture depth bits"};
309 cvar_t r_shadow_shadowmapping_vsdct = {CVAR_SAVE, "r_shadow_shadowmapping_vsdct", "1", "enables use of virtual shadow depth cube texture"};
310 cvar_t r_shadow_shadowmapping_minsize = {CVAR_SAVE, "r_shadow_shadowmapping_minsize", "32", "shadowmap size limit"};
311 cvar_t r_shadow_shadowmapping_maxsize = {CVAR_SAVE, "r_shadow_shadowmapping_maxsize", "512", "shadowmap size limit"};
312 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"};
313 //cvar_t r_shadow_shadowmapping_lod_bias = {CVAR_SAVE, "r_shadow_shadowmapping_lod_bias", "16", "shadowmap size bias"};
314 //cvar_t r_shadow_shadowmapping_lod_scale = {CVAR_SAVE, "r_shadow_shadowmapping_lod_scale", "128", "shadowmap size scaling parameter"};
315 cvar_t r_shadow_shadowmapping_bordersize = {CVAR_SAVE, "r_shadow_shadowmapping_bordersize", "4", "shadowmap size bias for filtering"};
316 cvar_t r_shadow_shadowmapping_nearclip = {CVAR_SAVE, "r_shadow_shadowmapping_nearclip", "1", "shadowmap nearclip in world units"};
317 cvar_t r_shadow_shadowmapping_bias = {CVAR_SAVE, "r_shadow_shadowmapping_bias", "0.03", "shadowmap bias parameter (this is multiplied by nearclip * 1024 / lodsize)"};
318 cvar_t r_shadow_shadowmapping_polygonfactor = {CVAR_SAVE, "r_shadow_shadowmapping_polygonfactor", "2", "slope-dependent shadowmapping bias"};
319 cvar_t r_shadow_shadowmapping_polygonoffset = {CVAR_SAVE, "r_shadow_shadowmapping_polygonoffset", "0", "constant shadowmapping bias"};
320 cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
321 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)"};
322 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)"};
323 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "1", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
324 cvar_t r_coronas_occlusionsizescale = {CVAR_SAVE, "r_coronas_occlusionsizescale", "0.1", "size of light source for corona occlusion checksm the proportion of hidden pixels controls corona intensity"};
325 cvar_t r_coronas_occlusionquery = {CVAR_SAVE, "r_coronas_occlusionquery", "1", "use GL_ARB_occlusion_query extension if supported (fades coronas according to visibility)"};
326 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
327 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
328 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
329 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
330 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
331 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
332 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
333 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
334 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
336 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
337 #define ATTENTABLESIZE 256
338 // 1D gradient, 2D circle and 3D sphere attenuation textures
339 #define ATTEN1DSIZE 32
340 #define ATTEN2DSIZE 64
341 #define ATTEN3DSIZE 32
343 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
344 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
345 static float r_shadow_attentable[ATTENTABLESIZE+1];
347 rtlight_t *r_shadow_compilingrtlight;
348 static memexpandablearray_t r_shadow_worldlightsarray;
349 dlight_t *r_shadow_selectedlight;
350 dlight_t r_shadow_bufferlight;
351 vec3_t r_editlights_cursorlocation;
353 extern int con_vislines;
355 void R_Shadow_UncompileWorldLights(void);
356 void R_Shadow_ClearWorldLights(void);
357 void R_Shadow_SaveWorldLights(void);
358 void R_Shadow_LoadWorldLights(void);
359 void R_Shadow_LoadLightsFile(void);
360 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
361 void R_Shadow_EditLights_Reload_f(void);
362 void R_Shadow_ValidateCvars(void);
363 static void R_Shadow_MakeTextures(void);
365 #define EDLIGHTSPRSIZE 8
366 skinframe_t *r_editlights_sprcursor;
367 skinframe_t *r_editlights_sprlight;
368 skinframe_t *r_editlights_sprnoshadowlight;
369 skinframe_t *r_editlights_sprcubemaplight;
370 skinframe_t *r_editlights_sprcubemapnoshadowlight;
371 skinframe_t *r_editlights_sprselection;
373 void R_Shadow_SetShadowMode(void)
375 r_shadow_shadowmapmaxsize = bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4);
376 r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer != 0;
377 r_shadow_shadowmapfilterquality = r_shadow_shadowmapping_filterquality.integer;
378 r_shadow_shadowmaptexturetype = r_shadow_shadowmapping_texturetype.integer;
379 r_shadow_shadowmapdepthbits = r_shadow_shadowmapping_depthbits.integer;
380 r_shadow_shadowmapborder = bound(0, r_shadow_shadowmapping_bordersize.integer, 16);
381 r_shadow_shadowmaplod = -1;
382 r_shadow_shadowmapsize = 0;
383 r_shadow_shadowmapsampler = false;
384 r_shadow_shadowmappcf = 0;
385 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
386 switch(vid.renderpath)
388 case RENDERPATH_GL20:
389 case RENDERPATH_CGGL:
390 if ((r_shadow_shadowmapping.integer || r_shadow_deferred.integer) && vid.support.ext_framebuffer_object)
392 if(r_shadow_shadowmapfilterquality < 0)
394 if(vid.support.amd_texture_texture4 || vid.support.arb_texture_gather)
395 r_shadow_shadowmappcf = 1;
396 else if(strstr(gl_vendor, "NVIDIA") || strstr(gl_renderer, "Radeon HD"))
398 r_shadow_shadowmapsampler = vid.support.arb_shadow;
399 r_shadow_shadowmappcf = 1;
401 else if(strstr(gl_vendor, "ATI"))
402 r_shadow_shadowmappcf = 1;
404 r_shadow_shadowmapsampler = vid.support.arb_shadow;
408 switch (r_shadow_shadowmapfilterquality)
411 r_shadow_shadowmapsampler = vid.support.arb_shadow;
414 r_shadow_shadowmapsampler = vid.support.arb_shadow;
415 r_shadow_shadowmappcf = 1;
418 r_shadow_shadowmappcf = 1;
421 r_shadow_shadowmappcf = 2;
425 switch (r_shadow_shadowmaptexturetype)
428 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
431 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE;
434 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE;
437 if((vid.support.amd_texture_texture4 || vid.support.arb_texture_gather) && r_shadow_shadowmappcf && !r_shadow_shadowmapsampler)
438 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
439 else if(vid.support.arb_texture_rectangle)
440 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE;
442 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
447 case RENDERPATH_GL13:
449 case RENDERPATH_GL11:
454 qboolean R_Shadow_ShadowMappingEnabled(void)
456 switch (r_shadow_shadowmode)
458 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
459 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
460 case R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE:
467 void R_Shadow_FreeShadowMaps(void)
471 R_Shadow_SetShadowMode();
473 if (!vid.support.ext_framebuffer_object || !vid.support.arb_fragment_shader)
478 if (r_shadow_fborectangle)
479 qglDeleteFramebuffersEXT(1, &r_shadow_fborectangle);CHECKGLERROR
480 r_shadow_fborectangle = 0;
483 qglDeleteFramebuffersEXT(1, &r_shadow_fbo2d);CHECKGLERROR
485 for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
486 if (r_shadow_fbocubeside[i])
487 qglDeleteFramebuffersEXT(1, &r_shadow_fbocubeside[i]);CHECKGLERROR
488 memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
490 if (r_shadow_shadowmaprectangletexture)
491 R_FreeTexture(r_shadow_shadowmaprectangletexture);
492 r_shadow_shadowmaprectangletexture = NULL;
494 if (r_shadow_shadowmap2dtexture)
495 R_FreeTexture(r_shadow_shadowmap2dtexture);
496 r_shadow_shadowmap2dtexture = NULL;
498 for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
499 if (r_shadow_shadowmapcubetexture[i])
500 R_FreeTexture(r_shadow_shadowmapcubetexture[i]);
501 memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
503 if (r_shadow_shadowmapvsdcttexture)
504 R_FreeTexture(r_shadow_shadowmapvsdcttexture);
505 r_shadow_shadowmapvsdcttexture = NULL;
510 void r_shadow_start(void)
512 // allocate vertex processing arrays
513 r_shadow_attenuationgradienttexture = NULL;
514 r_shadow_attenuation2dtexture = NULL;
515 r_shadow_attenuation3dtexture = NULL;
516 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
517 r_shadow_shadowmaprectangletexture = NULL;
518 r_shadow_shadowmap2dtexture = NULL;
519 memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
520 r_shadow_shadowmapvsdcttexture = NULL;
521 r_shadow_shadowmapmaxsize = 0;
522 r_shadow_shadowmapsize = 0;
523 r_shadow_shadowmaplod = 0;
524 r_shadow_shadowmapfilterquality = -1;
525 r_shadow_shadowmaptexturetype = -1;
526 r_shadow_shadowmapdepthbits = 0;
527 r_shadow_shadowmapvsdct = false;
528 r_shadow_shadowmapsampler = false;
529 r_shadow_shadowmappcf = 0;
530 r_shadow_fborectangle = 0;
532 memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
534 R_Shadow_FreeShadowMaps();
536 r_shadow_texturepool = NULL;
537 r_shadow_filters_texturepool = NULL;
538 R_Shadow_ValidateCvars();
539 R_Shadow_MakeTextures();
540 maxshadowtriangles = 0;
541 shadowelements = NULL;
542 maxshadowvertices = 0;
543 shadowvertex3f = NULL;
551 shadowmarklist = NULL;
556 shadowsideslist = NULL;
557 r_shadow_buffer_numleafpvsbytes = 0;
558 r_shadow_buffer_visitingleafpvs = NULL;
559 r_shadow_buffer_leafpvs = NULL;
560 r_shadow_buffer_leaflist = NULL;
561 r_shadow_buffer_numsurfacepvsbytes = 0;
562 r_shadow_buffer_surfacepvs = NULL;
563 r_shadow_buffer_surfacelist = NULL;
564 r_shadow_buffer_surfacesides = NULL;
565 r_shadow_buffer_numshadowtrispvsbytes = 0;
566 r_shadow_buffer_shadowtrispvs = NULL;
567 r_shadow_buffer_numlighttrispvsbytes = 0;
568 r_shadow_buffer_lighttrispvs = NULL;
570 r_shadow_usingdeferredprepass = false;
571 r_shadow_prepass_width = r_shadow_prepass_height = 0;
574 static void R_Shadow_FreeDeferred(void);
575 void r_shadow_shutdown(void)
578 R_Shadow_UncompileWorldLights();
580 R_Shadow_FreeShadowMaps();
582 r_shadow_usingdeferredprepass = false;
583 if (r_shadow_prepass_width)
584 R_Shadow_FreeDeferred();
585 r_shadow_prepass_width = r_shadow_prepass_height = 0;
588 r_shadow_attenuationgradienttexture = NULL;
589 r_shadow_attenuation2dtexture = NULL;
590 r_shadow_attenuation3dtexture = NULL;
591 R_FreeTexturePool(&r_shadow_texturepool);
592 R_FreeTexturePool(&r_shadow_filters_texturepool);
593 maxshadowtriangles = 0;
595 Mem_Free(shadowelements);
596 shadowelements = NULL;
598 Mem_Free(shadowvertex3f);
599 shadowvertex3f = NULL;
602 Mem_Free(vertexupdate);
605 Mem_Free(vertexremap);
611 Mem_Free(shadowmark);
614 Mem_Free(shadowmarklist);
615 shadowmarklist = NULL;
620 Mem_Free(shadowsides);
623 Mem_Free(shadowsideslist);
624 shadowsideslist = NULL;
625 r_shadow_buffer_numleafpvsbytes = 0;
626 if (r_shadow_buffer_visitingleafpvs)
627 Mem_Free(r_shadow_buffer_visitingleafpvs);
628 r_shadow_buffer_visitingleafpvs = NULL;
629 if (r_shadow_buffer_leafpvs)
630 Mem_Free(r_shadow_buffer_leafpvs);
631 r_shadow_buffer_leafpvs = NULL;
632 if (r_shadow_buffer_leaflist)
633 Mem_Free(r_shadow_buffer_leaflist);
634 r_shadow_buffer_leaflist = NULL;
635 r_shadow_buffer_numsurfacepvsbytes = 0;
636 if (r_shadow_buffer_surfacepvs)
637 Mem_Free(r_shadow_buffer_surfacepvs);
638 r_shadow_buffer_surfacepvs = NULL;
639 if (r_shadow_buffer_surfacelist)
640 Mem_Free(r_shadow_buffer_surfacelist);
641 r_shadow_buffer_surfacelist = NULL;
642 if (r_shadow_buffer_surfacesides)
643 Mem_Free(r_shadow_buffer_surfacesides);
644 r_shadow_buffer_surfacesides = NULL;
645 r_shadow_buffer_numshadowtrispvsbytes = 0;
646 if (r_shadow_buffer_shadowtrispvs)
647 Mem_Free(r_shadow_buffer_shadowtrispvs);
648 r_shadow_buffer_numlighttrispvsbytes = 0;
649 if (r_shadow_buffer_lighttrispvs)
650 Mem_Free(r_shadow_buffer_lighttrispvs);
653 void r_shadow_newmap(void)
655 if (r_shadow_lightcorona) R_SkinFrame_MarkUsed(r_shadow_lightcorona);
656 if (r_editlights_sprcursor) R_SkinFrame_MarkUsed(r_editlights_sprcursor);
657 if (r_editlights_sprlight) R_SkinFrame_MarkUsed(r_editlights_sprlight);
658 if (r_editlights_sprnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprnoshadowlight);
659 if (r_editlights_sprcubemaplight) R_SkinFrame_MarkUsed(r_editlights_sprcubemaplight);
660 if (r_editlights_sprcubemapnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprcubemapnoshadowlight);
661 if (r_editlights_sprselection) R_SkinFrame_MarkUsed(r_editlights_sprselection);
662 if (cl.worldmodel && strncmp(cl.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
663 R_Shadow_EditLights_Reload_f();
666 void R_Shadow_Init(void)
668 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
669 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
670 Cvar_RegisterVariable(&r_shadow_usenormalmap);
671 Cvar_RegisterVariable(&r_shadow_debuglight);
672 Cvar_RegisterVariable(&r_shadow_deferred);
673 Cvar_RegisterVariable(&r_shadow_deferred_8bitrange);
674 // Cvar_RegisterVariable(&r_shadow_deferred_fp);
675 Cvar_RegisterVariable(&r_shadow_gloss);
676 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
677 Cvar_RegisterVariable(&r_shadow_glossintensity);
678 Cvar_RegisterVariable(&r_shadow_glossexponent);
679 Cvar_RegisterVariable(&r_shadow_gloss2exponent);
680 Cvar_RegisterVariable(&r_shadow_glossexact);
681 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
682 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
683 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
684 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
685 Cvar_RegisterVariable(&r_shadow_projectdistance);
686 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
687 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
688 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
689 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
690 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
691 Cvar_RegisterVariable(&r_shadow_realtime_world);
692 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
693 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
694 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
695 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
696 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
697 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
698 Cvar_RegisterVariable(&r_shadow_scissor);
699 Cvar_RegisterVariable(&r_shadow_shadowmapping);
700 Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
701 Cvar_RegisterVariable(&r_shadow_shadowmapping_texturetype);
702 Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
703 Cvar_RegisterVariable(&r_shadow_shadowmapping_depthbits);
704 Cvar_RegisterVariable(&r_shadow_shadowmapping_precision);
705 Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
706 Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
707 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
708 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
709 Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
710 Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
711 Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
712 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonfactor);
713 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonoffset);
714 Cvar_RegisterVariable(&r_shadow_polygonfactor);
715 Cvar_RegisterVariable(&r_shadow_polygonoffset);
716 Cvar_RegisterVariable(&r_shadow_texture3d);
717 Cvar_RegisterVariable(&r_coronas);
718 Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
719 Cvar_RegisterVariable(&r_coronas_occlusionquery);
720 Cvar_RegisterVariable(&gl_flashblend);
721 Cvar_RegisterVariable(&gl_ext_separatestencil);
722 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
723 if (gamemode == GAME_TENEBRAE)
725 Cvar_SetValue("r_shadow_gloss", 2);
726 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
728 R_Shadow_EditLights_Init();
729 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
730 maxshadowtriangles = 0;
731 shadowelements = NULL;
732 maxshadowvertices = 0;
733 shadowvertex3f = NULL;
741 shadowmarklist = NULL;
746 shadowsideslist = NULL;
747 r_shadow_buffer_numleafpvsbytes = 0;
748 r_shadow_buffer_visitingleafpvs = NULL;
749 r_shadow_buffer_leafpvs = NULL;
750 r_shadow_buffer_leaflist = NULL;
751 r_shadow_buffer_numsurfacepvsbytes = 0;
752 r_shadow_buffer_surfacepvs = NULL;
753 r_shadow_buffer_surfacelist = NULL;
754 r_shadow_buffer_surfacesides = NULL;
755 r_shadow_buffer_shadowtrispvs = NULL;
756 r_shadow_buffer_lighttrispvs = NULL;
757 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
760 matrix4x4_t matrix_attenuationxyz =
763 {0.5, 0.0, 0.0, 0.5},
764 {0.0, 0.5, 0.0, 0.5},
765 {0.0, 0.0, 0.5, 0.5},
770 matrix4x4_t matrix_attenuationz =
773 {0.0, 0.0, 0.5, 0.5},
774 {0.0, 0.0, 0.0, 0.5},
775 {0.0, 0.0, 0.0, 0.5},
780 void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles, int vertscale, int triscale)
782 numvertices = ((numvertices + 255) & ~255) * vertscale;
783 numtriangles = ((numtriangles + 255) & ~255) * triscale;
784 // make sure shadowelements is big enough for this volume
785 if (maxshadowtriangles < numtriangles)
787 maxshadowtriangles = numtriangles;
789 Mem_Free(shadowelements);
790 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[3]));
792 // make sure shadowvertex3f is big enough for this volume
793 if (maxshadowvertices < numvertices)
795 maxshadowvertices = numvertices;
797 Mem_Free(shadowvertex3f);
798 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[3]));
802 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
804 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
805 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
806 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
807 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
808 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
810 if (r_shadow_buffer_visitingleafpvs)
811 Mem_Free(r_shadow_buffer_visitingleafpvs);
812 if (r_shadow_buffer_leafpvs)
813 Mem_Free(r_shadow_buffer_leafpvs);
814 if (r_shadow_buffer_leaflist)
815 Mem_Free(r_shadow_buffer_leaflist);
816 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
817 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
818 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
819 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
821 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
823 if (r_shadow_buffer_surfacepvs)
824 Mem_Free(r_shadow_buffer_surfacepvs);
825 if (r_shadow_buffer_surfacelist)
826 Mem_Free(r_shadow_buffer_surfacelist);
827 if (r_shadow_buffer_surfacesides)
828 Mem_Free(r_shadow_buffer_surfacesides);
829 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
830 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
831 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
832 r_shadow_buffer_surfacesides = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
834 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
836 if (r_shadow_buffer_shadowtrispvs)
837 Mem_Free(r_shadow_buffer_shadowtrispvs);
838 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
839 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
841 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
843 if (r_shadow_buffer_lighttrispvs)
844 Mem_Free(r_shadow_buffer_lighttrispvs);
845 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
846 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
850 void R_Shadow_PrepareShadowMark(int numtris)
852 // make sure shadowmark is big enough for this volume
853 if (maxshadowmark < numtris)
855 maxshadowmark = numtris;
857 Mem_Free(shadowmark);
859 Mem_Free(shadowmarklist);
860 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
861 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
865 // if shadowmarkcount wrapped we clear the array and adjust accordingly
866 if (shadowmarkcount == 0)
869 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
874 void R_Shadow_PrepareShadowSides(int numtris)
876 if (maxshadowsides < numtris)
878 maxshadowsides = numtris;
880 Mem_Free(shadowsides);
882 Mem_Free(shadowsideslist);
883 shadowsides = (unsigned char *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsides));
884 shadowsideslist = (int *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsideslist));
889 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)
892 int outtriangles = 0, outvertices = 0;
895 float ratio, direction[3], projectvector[3];
897 if (projectdirection)
898 VectorScale(projectdirection, projectdistance, projectvector);
900 VectorClear(projectvector);
902 // create the vertices
903 if (projectdirection)
905 for (i = 0;i < numshadowmarktris;i++)
907 element = inelement3i + shadowmarktris[i] * 3;
908 for (j = 0;j < 3;j++)
910 if (vertexupdate[element[j]] != vertexupdatenum)
912 vertexupdate[element[j]] = vertexupdatenum;
913 vertexremap[element[j]] = outvertices;
914 vertex = invertex3f + element[j] * 3;
915 // project one copy of the vertex according to projectvector
916 VectorCopy(vertex, outvertex3f);
917 VectorAdd(vertex, projectvector, (outvertex3f + 3));
926 for (i = 0;i < numshadowmarktris;i++)
928 element = inelement3i + shadowmarktris[i] * 3;
929 for (j = 0;j < 3;j++)
931 if (vertexupdate[element[j]] != vertexupdatenum)
933 vertexupdate[element[j]] = vertexupdatenum;
934 vertexremap[element[j]] = outvertices;
935 vertex = invertex3f + element[j] * 3;
936 // project one copy of the vertex to the sphere radius of the light
937 // (FIXME: would projecting it to the light box be better?)
938 VectorSubtract(vertex, projectorigin, direction);
939 ratio = projectdistance / VectorLength(direction);
940 VectorCopy(vertex, outvertex3f);
941 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
949 if (r_shadow_frontsidecasting.integer)
951 for (i = 0;i < numshadowmarktris;i++)
953 int remappedelement[3];
955 const int *neighbortriangle;
957 markindex = shadowmarktris[i] * 3;
958 element = inelement3i + markindex;
959 neighbortriangle = inneighbor3i + markindex;
960 // output the front and back triangles
961 outelement3i[0] = vertexremap[element[0]];
962 outelement3i[1] = vertexremap[element[1]];
963 outelement3i[2] = vertexremap[element[2]];
964 outelement3i[3] = vertexremap[element[2]] + 1;
965 outelement3i[4] = vertexremap[element[1]] + 1;
966 outelement3i[5] = vertexremap[element[0]] + 1;
970 // output the sides (facing outward from this triangle)
971 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
973 remappedelement[0] = vertexremap[element[0]];
974 remappedelement[1] = vertexremap[element[1]];
975 outelement3i[0] = remappedelement[1];
976 outelement3i[1] = remappedelement[0];
977 outelement3i[2] = remappedelement[0] + 1;
978 outelement3i[3] = remappedelement[1];
979 outelement3i[4] = remappedelement[0] + 1;
980 outelement3i[5] = remappedelement[1] + 1;
985 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
987 remappedelement[1] = vertexremap[element[1]];
988 remappedelement[2] = vertexremap[element[2]];
989 outelement3i[0] = remappedelement[2];
990 outelement3i[1] = remappedelement[1];
991 outelement3i[2] = remappedelement[1] + 1;
992 outelement3i[3] = remappedelement[2];
993 outelement3i[4] = remappedelement[1] + 1;
994 outelement3i[5] = remappedelement[2] + 1;
999 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1001 remappedelement[0] = vertexremap[element[0]];
1002 remappedelement[2] = vertexremap[element[2]];
1003 outelement3i[0] = remappedelement[0];
1004 outelement3i[1] = remappedelement[2];
1005 outelement3i[2] = remappedelement[2] + 1;
1006 outelement3i[3] = remappedelement[0];
1007 outelement3i[4] = remappedelement[2] + 1;
1008 outelement3i[5] = remappedelement[0] + 1;
1017 for (i = 0;i < numshadowmarktris;i++)
1019 int remappedelement[3];
1021 const int *neighbortriangle;
1023 markindex = shadowmarktris[i] * 3;
1024 element = inelement3i + markindex;
1025 neighbortriangle = inneighbor3i + markindex;
1026 // output the front and back triangles
1027 outelement3i[0] = vertexremap[element[2]];
1028 outelement3i[1] = vertexremap[element[1]];
1029 outelement3i[2] = vertexremap[element[0]];
1030 outelement3i[3] = vertexremap[element[0]] + 1;
1031 outelement3i[4] = vertexremap[element[1]] + 1;
1032 outelement3i[5] = vertexremap[element[2]] + 1;
1036 // output the sides (facing outward from this triangle)
1037 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
1039 remappedelement[0] = vertexremap[element[0]];
1040 remappedelement[1] = vertexremap[element[1]];
1041 outelement3i[0] = remappedelement[0];
1042 outelement3i[1] = remappedelement[1];
1043 outelement3i[2] = remappedelement[1] + 1;
1044 outelement3i[3] = remappedelement[0];
1045 outelement3i[4] = remappedelement[1] + 1;
1046 outelement3i[5] = remappedelement[0] + 1;
1051 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1053 remappedelement[1] = vertexremap[element[1]];
1054 remappedelement[2] = vertexremap[element[2]];
1055 outelement3i[0] = remappedelement[1];
1056 outelement3i[1] = remappedelement[2];
1057 outelement3i[2] = remappedelement[2] + 1;
1058 outelement3i[3] = remappedelement[1];
1059 outelement3i[4] = remappedelement[2] + 1;
1060 outelement3i[5] = remappedelement[1] + 1;
1065 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1067 remappedelement[0] = vertexremap[element[0]];
1068 remappedelement[2] = vertexremap[element[2]];
1069 outelement3i[0] = remappedelement[2];
1070 outelement3i[1] = remappedelement[0];
1071 outelement3i[2] = remappedelement[0] + 1;
1072 outelement3i[3] = remappedelement[2];
1073 outelement3i[4] = remappedelement[0] + 1;
1074 outelement3i[5] = remappedelement[2] + 1;
1082 *outnumvertices = outvertices;
1083 return outtriangles;
1086 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)
1089 int outtriangles = 0, outvertices = 0;
1091 const float *vertex;
1092 float ratio, direction[3], projectvector[3];
1095 if (projectdirection)
1096 VectorScale(projectdirection, projectdistance, projectvector);
1098 VectorClear(projectvector);
1100 for (i = 0;i < numshadowmarktris;i++)
1102 int remappedelement[3];
1104 const int *neighbortriangle;
1106 markindex = shadowmarktris[i] * 3;
1107 neighbortriangle = inneighbor3i + markindex;
1108 side[0] = shadowmark[neighbortriangle[0]] == shadowmarkcount;
1109 side[1] = shadowmark[neighbortriangle[1]] == shadowmarkcount;
1110 side[2] = shadowmark[neighbortriangle[2]] == shadowmarkcount;
1111 if (side[0] + side[1] + side[2] == 0)
1115 element = inelement3i + markindex;
1117 // create the vertices
1118 for (j = 0;j < 3;j++)
1120 if (side[j] + side[j+1] == 0)
1123 if (vertexupdate[k] != vertexupdatenum)
1125 vertexupdate[k] = vertexupdatenum;
1126 vertexremap[k] = outvertices;
1127 vertex = invertex3f + k * 3;
1128 VectorCopy(vertex, outvertex3f);
1129 if (projectdirection)
1131 // project one copy of the vertex according to projectvector
1132 VectorAdd(vertex, projectvector, (outvertex3f + 3));
1136 // project one copy of the vertex to the sphere radius of the light
1137 // (FIXME: would projecting it to the light box be better?)
1138 VectorSubtract(vertex, projectorigin, direction);
1139 ratio = projectdistance / VectorLength(direction);
1140 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1147 // output the sides (facing outward from this triangle)
1150 remappedelement[0] = vertexremap[element[0]];
1151 remappedelement[1] = vertexremap[element[1]];
1152 outelement3i[0] = remappedelement[1];
1153 outelement3i[1] = remappedelement[0];
1154 outelement3i[2] = remappedelement[0] + 1;
1155 outelement3i[3] = remappedelement[1];
1156 outelement3i[4] = remappedelement[0] + 1;
1157 outelement3i[5] = remappedelement[1] + 1;
1164 remappedelement[1] = vertexremap[element[1]];
1165 remappedelement[2] = vertexremap[element[2]];
1166 outelement3i[0] = remappedelement[2];
1167 outelement3i[1] = remappedelement[1];
1168 outelement3i[2] = remappedelement[1] + 1;
1169 outelement3i[3] = remappedelement[2];
1170 outelement3i[4] = remappedelement[1] + 1;
1171 outelement3i[5] = remappedelement[2] + 1;
1178 remappedelement[0] = vertexremap[element[0]];
1179 remappedelement[2] = vertexremap[element[2]];
1180 outelement3i[0] = remappedelement[0];
1181 outelement3i[1] = remappedelement[2];
1182 outelement3i[2] = remappedelement[2] + 1;
1183 outelement3i[3] = remappedelement[0];
1184 outelement3i[4] = remappedelement[2] + 1;
1185 outelement3i[5] = remappedelement[0] + 1;
1192 *outnumvertices = outvertices;
1193 return outtriangles;
1196 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)
1202 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1204 tend = firsttriangle + numtris;
1205 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1207 // surface box entirely inside light box, no box cull
1208 if (projectdirection)
1210 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1212 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
1213 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1214 shadowmarklist[numshadowmark++] = t;
1219 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1220 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
1221 shadowmarklist[numshadowmark++] = t;
1226 // surface box not entirely inside light box, cull each triangle
1227 if (projectdirection)
1229 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1231 v[0] = invertex3f + e[0] * 3;
1232 v[1] = invertex3f + e[1] * 3;
1233 v[2] = invertex3f + e[2] * 3;
1234 TriangleNormal(v[0], v[1], v[2], normal);
1235 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1236 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1237 shadowmarklist[numshadowmark++] = t;
1242 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1244 v[0] = invertex3f + e[0] * 3;
1245 v[1] = invertex3f + e[1] * 3;
1246 v[2] = invertex3f + e[2] * 3;
1247 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1248 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1249 shadowmarklist[numshadowmark++] = t;
1255 qboolean R_Shadow_UseZPass(vec3_t mins, vec3_t maxs)
1260 if (r_shadow_compilingrtlight || !r_shadow_frontsidecasting.integer || !r_shadow_usezpassifpossible.integer)
1262 // check if the shadow volume intersects the near plane
1264 // a ray between the eye and light origin may intersect the caster,
1265 // indicating that the shadow may touch the eye location, however we must
1266 // test the near plane (a polygon), not merely the eye location, so it is
1267 // easiest to enlarge the caster bounding shape slightly for this.
1273 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)
1275 int i, tris, outverts;
1276 if (projectdistance < 0.1)
1278 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
1281 if (!numverts || !nummarktris)
1283 // make sure shadowelements is big enough for this volume
1284 if (maxshadowtriangles < nummarktris*8 || maxshadowvertices < numverts*2)
1285 R_Shadow_ResizeShadowArrays(numverts, nummarktris, 2, 8);
1287 if (maxvertexupdate < numverts)
1289 maxvertexupdate = numverts;
1291 Mem_Free(vertexupdate);
1293 Mem_Free(vertexremap);
1294 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1295 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1296 vertexupdatenum = 0;
1299 if (vertexupdatenum == 0)
1301 vertexupdatenum = 1;
1302 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
1303 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
1306 for (i = 0;i < nummarktris;i++)
1307 shadowmark[marktris[i]] = shadowmarkcount;
1309 if (r_shadow_compilingrtlight)
1311 // if we're compiling an rtlight, capture the mesh
1312 //tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1313 //Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zpass, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1314 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1315 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zfail, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1317 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
1319 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1320 R_Mesh_VertexPointer(shadowvertex3f, 0, 0);
1321 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1325 // decide which type of shadow to generate and set stencil mode
1326 R_Shadow_RenderMode_StencilShadowVolumes(R_Shadow_UseZPass(trismins, trismaxs));
1327 // generate the sides or a solid volume, depending on type
1328 if (r_shadow_rendermode >= R_SHADOW_RENDERMODE_ZPASS_STENCIL && r_shadow_rendermode <= R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE)
1329 tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1331 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1332 r_refdef.stats.lights_dynamicshadowtriangles += tris;
1333 r_refdef.stats.lights_shadowtriangles += tris;
1335 R_Mesh_VertexPointer(shadowvertex3f, 0, 0);
1336 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
1338 // increment stencil if frontface is infront of depthbuffer
1339 GL_CullFace(r_refdef.view.cullface_front);
1340 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1341 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1342 // decrement stencil if backface is infront of depthbuffer
1343 GL_CullFace(r_refdef.view.cullface_back);
1344 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1346 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
1348 // decrement stencil if backface is behind depthbuffer
1349 GL_CullFace(r_refdef.view.cullface_front);
1350 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1351 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1352 // increment stencil if frontface is behind depthbuffer
1353 GL_CullFace(r_refdef.view.cullface_back);
1354 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1356 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1361 int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias)
1363 // p1, p2, p3 are in the cubemap's local coordinate system
1364 // bias = border/(size - border)
1367 float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1368 dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2),
1369 dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3);
1370 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1372 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1373 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1374 | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1375 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1377 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1378 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1379 | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1381 dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1382 dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2),
1383 dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3);
1384 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1386 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1387 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1388 | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1389 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1391 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1392 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1393 | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1395 dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1396 dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2),
1397 dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3);
1398 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1400 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1401 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1402 | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1403 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1405 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1406 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1407 | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1412 int R_Shadow_CalcBBoxSideMask(const vec3_t mins, const vec3_t maxs, const matrix4x4_t *worldtolight, const matrix4x4_t *radiustolight, float bias)
1414 vec3_t center, radius, lightcenter, lightradius, pmin, pmax;
1415 float dp1, dn1, ap1, an1, dp2, dn2, ap2, an2;
1418 VectorSubtract(maxs, mins, radius);
1419 VectorScale(radius, 0.5f, radius);
1420 VectorAdd(mins, radius, center);
1421 Matrix4x4_Transform(worldtolight, center, lightcenter);
1422 Matrix4x4_Transform3x3(radiustolight, radius, lightradius);
1423 VectorSubtract(lightcenter, lightradius, pmin);
1424 VectorAdd(lightcenter, lightradius, pmax);
1426 dp1 = pmax[0] + pmax[1], dn1 = pmax[0] - pmin[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1427 dp2 = pmin[0] + pmin[1], dn2 = pmin[0] - pmax[1], ap2 = fabs(dp2), an2 = fabs(dn2);
1428 if(ap1 > bias*an1 && ap2 > bias*an2)
1430 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1431 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1432 if(an1 > bias*ap1 && an2 > bias*ap2)
1434 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1435 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1437 dp1 = pmax[1] + pmax[2], dn1 = pmax[1] - pmin[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1438 dp2 = pmin[1] + pmin[2], dn2 = pmin[1] - pmax[2], ap2 = fabs(dp2), an2 = fabs(dn2);
1439 if(ap1 > bias*an1 && ap2 > bias*an2)
1441 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1442 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1443 if(an1 > bias*ap1 && an2 > bias*ap2)
1445 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1446 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1448 dp1 = pmax[2] + pmax[0], dn1 = pmax[2] - pmin[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1449 dp2 = pmin[2] + pmin[0], dn2 = pmin[2] - pmax[0], ap2 = fabs(dp2), an2 = fabs(dn2);
1450 if(ap1 > bias*an1 && ap2 > bias*an2)
1452 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1453 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1454 if(an1 > bias*ap1 && an2 > bias*ap2)
1456 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1457 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1462 #define R_Shadow_CalcEntitySideMask(ent, worldtolight, radiustolight, bias) R_Shadow_CalcBBoxSideMask((ent)->mins, (ent)->maxs, worldtolight, radiustolight, bias)
1464 int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
1466 // p is in the cubemap's local coordinate system
1467 // bias = border/(size - border)
1468 float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn);
1469 float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn);
1470 float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn);
1472 if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
1473 if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
1474 if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
1475 if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
1476 if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
1477 if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
1481 int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
1485 int sides = 0x3F, masks[6] = { 3<<4, 3<<4, 3<<0, 3<<0, 3<<2, 3<<2 };
1486 float scale = (size - 2*border)/size, len;
1487 float bias = border / (float)(size - border), dp, dn, ap, an;
1488 // check if cone enclosing side would cross frustum plane
1489 scale = 2 / (scale*scale + 2);
1490 for (i = 0;i < 5;i++)
1492 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) > -0.03125)
1494 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[i].normal, n);
1495 len = scale*VectorLength2(n);
1496 if(n[0]*n[0] > len) sides &= n[0] < 0 ? ~(1<<0) : ~(2 << 0);
1497 if(n[1]*n[1] > len) sides &= n[1] < 0 ? ~(1<<2) : ~(2 << 2);
1498 if(n[2]*n[2] > len) sides &= n[2] < 0 ? ~(1<<4) : ~(2 << 4);
1500 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[4]) >= r_refdef.farclip - r_refdef.nearclip + 0.03125)
1502 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[4].normal, n);
1503 len = scale*VectorLength(n);
1504 if(n[0]*n[0] > len) sides &= n[0] >= 0 ? ~(1<<0) : ~(2 << 0);
1505 if(n[1]*n[1] > len) sides &= n[1] >= 0 ? ~(1<<2) : ~(2 << 2);
1506 if(n[2]*n[2] > len) sides &= n[2] >= 0 ? ~(1<<4) : ~(2 << 4);
1508 // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results
1509 // check if frustum corners/origin cross plane sides
1511 // infinite version, assumes frustum corners merely give direction and extend to infinite distance
1512 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.origin, p);
1513 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1514 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1515 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1516 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1517 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1518 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1519 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1520 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1521 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1522 for (i = 0;i < 4;i++)
1524 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.frustumcorner[i], n);
1525 VectorSubtract(n, p, n);
1526 dp = n[0] + n[1], dn = n[0] - n[1], ap = fabs(dp), an = fabs(dn);
1527 if(ap > 0) masks[0] |= dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2);
1528 if(an > 0) masks[1] |= dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2);
1529 dp = n[1] + n[2], dn = n[1] - n[2], ap = fabs(dp), an = fabs(dn);
1530 if(ap > 0) masks[2] |= dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4);
1531 if(an > 0) masks[3] |= dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4);
1532 dp = n[2] + n[0], dn = n[2] - n[0], ap = fabs(dp), an = fabs(dn);
1533 if(ap > 0) masks[4] |= dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0);
1534 if(an > 0) masks[5] |= dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0);
1537 // finite version, assumes corners are a finite distance from origin dependent on far plane
1538 for (i = 0;i < 5;i++)
1540 Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p);
1541 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1542 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1543 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1544 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1545 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1546 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1547 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1548 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1549 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1552 return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5];
1555 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)
1563 int mask, surfacemask = 0;
1564 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1566 bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
1567 tend = firsttriangle + numtris;
1568 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1570 // surface box entirely inside light box, no box cull
1571 if (projectdirection)
1573 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1575 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1576 TriangleNormal(v[0], v[1], v[2], normal);
1577 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1579 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1580 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1581 surfacemask |= mask;
1584 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;
1585 shadowsides[numshadowsides] = mask;
1586 shadowsideslist[numshadowsides++] = t;
1593 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1595 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1596 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]))
1598 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1599 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1600 surfacemask |= mask;
1603 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;
1604 shadowsides[numshadowsides] = mask;
1605 shadowsideslist[numshadowsides++] = t;
1613 // surface box not entirely inside light box, cull each triangle
1614 if (projectdirection)
1616 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1618 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1619 TriangleNormal(v[0], v[1], v[2], normal);
1620 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1621 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1623 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1624 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1625 surfacemask |= mask;
1628 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;
1629 shadowsides[numshadowsides] = mask;
1630 shadowsideslist[numshadowsides++] = t;
1637 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1639 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1640 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1641 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1643 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1644 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1645 surfacemask |= mask;
1648 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;
1649 shadowsides[numshadowsides] = mask;
1650 shadowsideslist[numshadowsides++] = t;
1659 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)
1661 int i, j, outtriangles = 0;
1662 int *outelement3i[6];
1663 if (!numverts || !numsidetris || !r_shadow_compilingrtlight)
1665 outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5];
1666 // make sure shadowelements is big enough for this mesh
1667 if (maxshadowtriangles < outtriangles)
1668 R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1);
1670 // compute the offset and size of the separate index lists for each cubemap side
1672 for (i = 0;i < 6;i++)
1674 outelement3i[i] = shadowelements + outtriangles * 3;
1675 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles;
1676 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i];
1677 outtriangles += sidetotals[i];
1680 // gather up the (sparse) triangles into separate index lists for each cubemap side
1681 for (i = 0;i < numsidetris;i++)
1683 const int *element = elements + sidetris[i] * 3;
1684 for (j = 0;j < 6;j++)
1686 if (sides[i] & (1 << j))
1688 outelement3i[j][0] = element[0];
1689 outelement3i[j][1] = element[1];
1690 outelement3i[j][2] = element[2];
1691 outelement3i[j] += 3;
1696 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, outtriangles, shadowelements);
1699 static void R_Shadow_MakeTextures_MakeCorona(void)
1703 unsigned char pixels[32][32][4];
1704 for (y = 0;y < 32;y++)
1706 dy = (y - 15.5f) * (1.0f / 16.0f);
1707 for (x = 0;x < 32;x++)
1709 dx = (x - 15.5f) * (1.0f / 16.0f);
1710 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1711 a = bound(0, a, 255);
1712 pixels[y][x][0] = a;
1713 pixels[y][x][1] = a;
1714 pixels[y][x][2] = a;
1715 pixels[y][x][3] = 255;
1718 r_shadow_lightcorona = R_SkinFrame_LoadInternalBGRA("lightcorona", TEXF_FORCELINEAR, &pixels[0][0][0], 32, 32);
1721 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1723 float dist = sqrt(x*x+y*y+z*z);
1724 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1725 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1726 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1729 static void R_Shadow_MakeTextures(void)
1732 float intensity, dist;
1734 R_Shadow_FreeShadowMaps();
1735 R_FreeTexturePool(&r_shadow_texturepool);
1736 r_shadow_texturepool = R_AllocTexturePool();
1737 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1738 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1739 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1740 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1741 for (x = 0;x <= ATTENTABLESIZE;x++)
1743 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1744 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1745 r_shadow_attentable[x] = bound(0, intensity, 1);
1747 // 1D gradient texture
1748 for (x = 0;x < ATTEN1DSIZE;x++)
1749 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1750 r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, NULL);
1751 // 2D circle texture
1752 for (y = 0;y < ATTEN2DSIZE;y++)
1753 for (x = 0;x < ATTEN2DSIZE;x++)
1754 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);
1755 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, NULL);
1756 // 3D sphere texture
1757 if (r_shadow_texture3d.integer && vid.support.ext_texture_3d)
1759 for (z = 0;z < ATTEN3DSIZE;z++)
1760 for (y = 0;y < ATTEN3DSIZE;y++)
1761 for (x = 0;x < ATTEN3DSIZE;x++)
1762 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));
1763 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, NULL);
1766 r_shadow_attenuation3dtexture = NULL;
1769 R_Shadow_MakeTextures_MakeCorona();
1771 // Editor light sprites
1772 r_editlights_sprcursor = R_SkinFrame_LoadInternal8bit("gfx/editlights/cursor", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1789 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1790 r_editlights_sprlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/light", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1807 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1808 r_editlights_sprnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/noshadow", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1825 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1826 r_editlights_sprcubemaplight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemaplight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1843 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1844 r_editlights_sprcubemapnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemapnoshadowlight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1861 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1862 r_editlights_sprselection = R_SkinFrame_LoadInternal8bit("gfx/editlights/selection", TEXF_ALPHA | TEXF_CLAMP, (unsigned char *)
1879 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1882 void R_Shadow_ValidateCvars(void)
1884 if (r_shadow_texture3d.integer && !vid.support.ext_texture_3d)
1885 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1886 if (gl_ext_separatestencil.integer && !vid.support.ati_separate_stencil)
1887 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
1888 if (gl_ext_stenciltwoside.integer && !vid.support.ext_stencil_two_side)
1889 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1892 void R_Shadow_RenderMode_Begin(void)
1898 R_Shadow_ValidateCvars();
1900 if (!r_shadow_attenuation2dtexture
1901 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1902 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1903 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1904 R_Shadow_MakeTextures();
1907 R_Mesh_ColorPointer(NULL, 0, 0);
1908 R_Mesh_ResetTextureState();
1909 GL_BlendFunc(GL_ONE, GL_ZERO);
1910 GL_DepthRange(0, 1);
1911 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1913 GL_DepthMask(false);
1914 GL_Color(0, 0, 0, 1);
1915 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1917 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1919 if (gl_ext_separatestencil.integer && vid.support.ati_separate_stencil)
1921 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
1922 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
1924 else if (gl_ext_stenciltwoside.integer && vid.support.ext_stencil_two_side)
1926 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
1927 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
1931 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
1932 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
1935 switch(vid.renderpath)
1937 case RENDERPATH_GL20:
1938 case RENDERPATH_CGGL:
1939 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1941 case RENDERPATH_GL13:
1942 case RENDERPATH_GL11:
1943 if (r_textureunits.integer >= 2 && vid.texunits >= 2 && r_shadow_texture3d.integer && r_shadow_attenuation3dtexture)
1944 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN;
1945 else if (r_textureunits.integer >= 3 && vid.texunits >= 3)
1946 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN;
1947 else if (r_textureunits.integer >= 2 && vid.texunits >= 2)
1948 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN;
1950 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1956 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
1957 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
1958 r_shadow_drawbuffer = drawbuffer;
1959 r_shadow_readbuffer = readbuffer;
1961 r_shadow_cullface_front = r_refdef.view.cullface_front;
1962 r_shadow_cullface_back = r_refdef.view.cullface_back;
1965 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
1967 rsurface.rtlight = rtlight;
1970 void R_Shadow_RenderMode_Reset(void)
1973 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE)
1975 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1977 if (vid.support.ext_framebuffer_object)
1979 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);CHECKGLERROR
1982 qglDrawBuffer(r_shadow_drawbuffer);CHECKGLERROR
1983 qglReadBuffer(r_shadow_readbuffer);CHECKGLERROR
1985 R_SetViewport(&r_refdef.view.viewport);
1986 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
1987 R_Mesh_ColorPointer(NULL, 0, 0);
1988 R_Mesh_ResetTextureState();
1989 GL_DepthRange(0, 1);
1991 GL_DepthMask(false);
1992 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1993 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1994 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
1995 qglStencilMask(255);CHECKGLERROR
1996 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
1997 qglStencilFunc(GL_ALWAYS, 128, 255);CHECKGLERROR
1998 r_refdef.view.cullface_front = r_shadow_cullface_front;
1999 r_refdef.view.cullface_back = r_shadow_cullface_back;
2000 GL_CullFace(r_refdef.view.cullface_back);
2001 GL_Color(1, 1, 1, 1);
2002 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
2003 GL_BlendFunc(GL_ONE, GL_ZERO);
2004 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
2005 r_shadow_usingshadowmaprect = false;
2006 r_shadow_usingshadowmapcube = false;
2007 r_shadow_usingshadowmap2d = false;
2008 r_shadow_usingshadowmaportho = false;
2012 void R_Shadow_ClearStencil(void)
2015 GL_Clear(GL_STENCIL_BUFFER_BIT);
2016 r_refdef.stats.lights_clears++;
2019 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
2021 r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
2022 if (r_shadow_rendermode == mode)
2025 R_Shadow_RenderMode_Reset();
2026 GL_ColorMask(0, 0, 0, 0);
2027 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2028 R_SetupShader_DepthOrShadow();
2029 qglDepthFunc(GL_LESS);CHECKGLERROR
2030 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2031 r_shadow_rendermode = mode;
2036 case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
2037 GL_CullFace(GL_NONE);
2038 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
2039 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
2041 case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
2042 GL_CullFace(GL_NONE);
2043 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
2044 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
2046 case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
2047 GL_CullFace(GL_NONE);
2048 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
2049 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
2050 qglStencilMask(255);CHECKGLERROR
2051 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
2052 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
2053 qglStencilMask(255);CHECKGLERROR
2054 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
2056 case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
2057 GL_CullFace(GL_NONE);
2058 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
2059 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
2060 qglStencilMask(255);CHECKGLERROR
2061 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
2062 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
2063 qglStencilMask(255);CHECKGLERROR
2064 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
2069 static void R_Shadow_MakeVSDCT(void)
2071 // maps to a 2x3 texture rectangle with normalized coordinates
2076 // stores abs(dir.xy), offset.xy/2.5
2077 unsigned char data[4*6] =
2079 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
2080 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
2081 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
2082 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
2083 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
2084 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
2086 r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, NULL);
2089 static void R_Shadow_MakeShadowMap(int side, int size)
2092 switch (r_shadow_shadowmode)
2094 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2095 if (r_shadow_shadowmap2dtexture) return;
2096 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);
2097 qglGenFramebuffersEXT(1, &r_shadow_fbo2d);CHECKGLERROR
2098 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbo2d);CHECKGLERROR
2099 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_shadowmap2dtexture), 0);CHECKGLERROR
2101 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
2102 if (r_shadow_shadowmaprectangletexture) return;
2103 r_shadow_shadowmaprectangletexture = R_LoadTextureShadowMapRectangle(r_shadow_texturepool, "shadowmap", size*2, size*3, r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
2104 qglGenFramebuffersEXT(1, &r_shadow_fborectangle);CHECKGLERROR
2105 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fborectangle);CHECKGLERROR
2106 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, R_GetTexture(r_shadow_shadowmaprectangletexture), 0);CHECKGLERROR
2108 case R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE:
2109 if (r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]) return;
2110 r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod] = R_LoadTextureShadowMapCube(r_shadow_texturepool, "shadowmapcube", size, r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
2111 qglGenFramebuffersEXT(1, &r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR
2112 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR
2113 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + side, R_GetTexture(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]), 0);CHECKGLERROR
2118 // render depth into the fbo, do not render color at all
2119 qglDrawBuffer(GL_NONE);CHECKGLERROR
2120 qglReadBuffer(GL_NONE);CHECKGLERROR
2121 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2122 if (status != GL_FRAMEBUFFER_COMPLETE_EXT && (r_shadow_shadowmapping.integer || r_shadow_deferred.integer))
2124 Con_Printf("R_Shadow_MakeShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2125 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2126 Cvar_SetValueQuick(&r_shadow_deferred, 0);
2130 void R_Shadow_RenderMode_ShadowMap(int side, int clear, int size)
2132 float nearclip, farclip, bias;
2133 r_viewport_t viewport;
2137 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
2139 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
2140 r_shadow_shadowmap_parameters[1] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
2141 r_shadow_shadowmap_parameters[3] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
2142 r_shadow_shadowmapside = side;
2143 r_shadow_shadowmapsize = size;
2144 switch (r_shadow_shadowmode)
2146 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2147 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2148 r_shadow_shadowmap_parameters[2] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2149 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
2150 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D) goto init_done;
2152 // complex unrolled cube approach (more flexible)
2153 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2154 R_Shadow_MakeVSDCT();
2155 if (!r_shadow_shadowmap2dtexture)
2156 R_Shadow_MakeShadowMap(side, r_shadow_shadowmapmaxsize);
2158 if (r_shadow_shadowmap2dtexture) fbo = r_shadow_fbo2d;
2159 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
2160 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
2161 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
2163 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
2164 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2165 r_shadow_shadowmap_parameters[2] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2166 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
2167 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE) goto init_done;
2169 // complex unrolled cube approach (more flexible)
2170 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2171 R_Shadow_MakeVSDCT();
2172 if (!r_shadow_shadowmaprectangletexture)
2173 R_Shadow_MakeShadowMap(side, r_shadow_shadowmapmaxsize);
2175 if(r_shadow_shadowmaprectangletexture) fbo = r_shadow_fborectangle;
2176 r_shadow_shadowmap_texturescale[0] = 1.0f;
2177 r_shadow_shadowmap_texturescale[1] = 1.0f;
2178 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE;
2180 case R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE:
2181 r_shadow_shadowmap_parameters[0] = 1.0f;
2182 r_shadow_shadowmap_parameters[2] = 1.0f;
2183 R_Viewport_InitCubeSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, nearclip, farclip, NULL);
2184 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE) goto init_done;
2186 // simple cube approach
2187 if (!r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod])
2188 R_Shadow_MakeShadowMap(side, size);
2190 if (r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]) fbo = r_shadow_fbocubeside[r_shadow_shadowmaplod];
2191 r_shadow_shadowmap_texturescale[0] = 0.0f;
2192 r_shadow_shadowmap_texturescale[1] = 0.0f;
2193 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE;
2199 R_Shadow_RenderMode_Reset();
2202 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);CHECKGLERROR
2203 R_SetupShader_DepthOrShadow();
2207 R_SetupShader_ShowDepth();
2208 qglClearColor(1,1,1,1);CHECKGLERROR
2211 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
2218 R_SetViewport(&viewport);
2219 switch (r_shadow_rendermode)
2221 case R_SHADOW_RENDERMODE_SHADOWMAP2D:
2222 case R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE:
2223 flipped = (side & 1) ^ (side >> 2);
2224 r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
2225 r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
2226 GL_CullFace(r_refdef.view.cullface_back);
2227 if ((clear & ((2 << side) - 1)) == (1 << side)) // only clear if the side is the first in the mask
2229 // get tightest scissor rectangle that encloses all viewports in the clear mask
2230 int x1 = clear & 0x15 ? 0 : size;
2231 int x2 = clear & 0x2A ? 2 * size : size;
2232 int y1 = clear & 0x03 ? 0 : (clear & 0xC ? size : 2 * size);
2233 int y2 = clear & 0x30 ? 3 * size : (clear & 0xC ? 2 * size : size);
2234 GL_Scissor(x1, y1, x2 - x1, y2 - y1);
2235 GL_Clear(GL_DEPTH_BUFFER_BIT);
2237 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2239 case R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE:
2240 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + side, R_GetTexture(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]), 0);CHECKGLERROR
2241 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2243 GL_Clear(GL_DEPTH_BUFFER_BIT);
2251 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
2255 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2256 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2257 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2258 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2261 R_Shadow_RenderMode_Reset();
2262 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2265 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2269 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2270 // only draw light where this geometry was already rendered AND the
2271 // stencil is 128 (values other than this mean shadow)
2272 qglStencilFunc(GL_EQUAL, 128, 255);CHECKGLERROR
2274 r_shadow_rendermode = r_shadow_lightingrendermode;
2275 // do global setup needed for the chosen lighting mode
2276 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2278 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2283 switch (r_shadow_shadowmode)
2285 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2286 r_shadow_usingshadowmap2d = true;
2288 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
2289 r_shadow_usingshadowmaprect = true;
2291 case R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE:
2292 r_shadow_usingshadowmapcube = true;
2298 R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
2302 static const unsigned short bboxelements[36] =
2312 static const float bboxpoints[8][3] =
2324 void R_Shadow_RenderMode_DrawDeferredLight(qboolean stenciltest, qboolean shadowmapping)
2327 float vertex3f[8*3];
2328 const matrix4x4_t *matrix = &rsurface.rtlight->matrix_lighttoworld;
2330 R_Shadow_RenderMode_Reset();
2331 r_shadow_rendermode = r_shadow_lightingrendermode;
2332 // do global setup needed for the chosen lighting mode
2334 R_EntityMatrix(&identitymatrix);
2335 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2338 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2339 // only draw light where this geometry was already rendered AND the
2340 // stencil is 128 (values other than this mean shadow)
2341 qglStencilFunc(GL_EQUAL, 128, 255);CHECKGLERROR
2343 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepasslightingfbo);CHECKGLERROR
2346 switch (r_shadow_shadowmode)
2348 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2349 r_shadow_usingshadowmap2d = true;
2351 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
2352 r_shadow_usingshadowmaprect = true;
2354 case R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE:
2355 r_shadow_usingshadowmapcube = true;
2362 // render the lighting
2363 R_SetupShader_DeferredLight(rsurface.rtlight);
2364 for (i = 0;i < 8;i++)
2365 Matrix4x4_Transform(matrix, bboxpoints[i], vertex3f + i*3);
2367 R_Mesh_VertexPointer(vertex3f, 0, 0);
2368 R_Mesh_ColorPointer(NULL, 0, 0);
2369 GL_ColorMask(1,1,1,1);
2370 GL_DepthMask(false);
2371 GL_DepthRange(0, 1);
2372 GL_PolygonOffset(0, 0);
2374 qglDepthFunc(GL_GREATER);CHECKGLERROR
2375 GL_CullFace(r_refdef.view.cullface_back);
2376 R_Mesh_Draw(0, 8, 0, 12, NULL, bboxelements, 0, 0);
2380 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
2383 R_Shadow_RenderMode_Reset();
2384 GL_BlendFunc(GL_ONE, GL_ONE);
2385 GL_DepthRange(0, 1);
2386 GL_DepthTest(r_showshadowvolumes.integer < 2);
2387 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
2388 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2389 GL_CullFace(GL_NONE);
2390 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
2393 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
2396 R_Shadow_RenderMode_Reset();
2397 GL_BlendFunc(GL_ONE, GL_ONE);
2398 GL_DepthRange(0, 1);
2399 GL_DepthTest(r_showlighting.integer < 2);
2400 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2403 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2407 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2408 qglStencilFunc(GL_EQUAL, 128, 255);CHECKGLERROR
2410 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2413 void R_Shadow_RenderMode_End(void)
2416 R_Shadow_RenderMode_Reset();
2417 R_Shadow_RenderMode_ActiveLight(NULL);
2419 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2420 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2423 int bboxedges[12][2] =
2442 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2444 int i, ix1, iy1, ix2, iy2;
2445 float x1, y1, x2, y2;
2447 float vertex[20][3];
2456 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2457 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2458 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2459 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2461 if (!r_shadow_scissor.integer)
2464 // if view is inside the light box, just say yes it's visible
2465 if (BoxesOverlap(r_refdef.view.origin, r_refdef.view.origin, mins, maxs))
2468 x1 = y1 = x2 = y2 = 0;
2470 // transform all corners that are infront of the nearclip plane
2471 VectorNegate(r_refdef.view.frustum[4].normal, plane4f);
2472 plane4f[3] = r_refdef.view.frustum[4].dist;
2474 for (i = 0;i < 8;i++)
2476 Vector4Set(corner[i], (i & 1) ? maxs[0] : mins[0], (i & 2) ? maxs[1] : mins[1], (i & 4) ? maxs[2] : mins[2], 1);
2477 dist[i] = DotProduct4(corner[i], plane4f);
2478 sign[i] = dist[i] > 0;
2481 VectorCopy(corner[i], vertex[numvertices]);
2485 // if some points are behind the nearclip, add clipped edge points to make
2486 // sure that the scissor boundary is complete
2487 if (numvertices > 0 && numvertices < 8)
2489 // add clipped edge points
2490 for (i = 0;i < 12;i++)
2492 j = bboxedges[i][0];
2493 k = bboxedges[i][1];
2494 if (sign[j] != sign[k])
2496 f = dist[j] / (dist[j] - dist[k]);
2497 VectorLerp(corner[j], f, corner[k], vertex[numvertices]);
2503 // if we have no points to check, the light is behind the view plane
2507 // if we have some points to transform, check what screen area is covered
2508 x1 = y1 = x2 = y2 = 0;
2510 //Con_Printf("%i vertices to transform...\n", numvertices);
2511 for (i = 0;i < numvertices;i++)
2513 VectorCopy(vertex[i], v);
2514 R_Viewport_TransformToScreen(&r_refdef.view.viewport, v, v2);
2515 //Con_Printf("%.3f %.3f %.3f %.3f transformed to %.3f %.3f %.3f %.3f\n", v[0], v[1], v[2], v[3], v2[0], v2[1], v2[2], v2[3]);
2518 if (x1 > v2[0]) x1 = v2[0];
2519 if (x2 < v2[0]) x2 = v2[0];
2520 if (y1 > v2[1]) y1 = v2[1];
2521 if (y2 < v2[1]) y2 = v2[1];
2530 // now convert the scissor rectangle to integer screen coordinates
2531 ix1 = (int)(x1 - 1.0f);
2532 iy1 = vid.height - (int)(y2 - 1.0f);
2533 ix2 = (int)(x2 + 1.0f);
2534 iy2 = vid.height - (int)(y1 + 1.0f);
2535 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
2537 // clamp it to the screen
2538 if (ix1 < r_refdef.view.viewport.x) ix1 = r_refdef.view.viewport.x;
2539 if (iy1 < r_refdef.view.viewport.y) iy1 = r_refdef.view.viewport.y;
2540 if (ix2 > r_refdef.view.viewport.x + r_refdef.view.viewport.width) ix2 = r_refdef.view.viewport.x + r_refdef.view.viewport.width;
2541 if (iy2 > r_refdef.view.viewport.y + r_refdef.view.viewport.height) iy2 = r_refdef.view.viewport.y + r_refdef.view.viewport.height;
2543 // if it is inside out, it's not visible
2544 if (ix2 <= ix1 || iy2 <= iy1)
2547 // the light area is visible, set up the scissor rectangle
2548 r_shadow_lightscissor[0] = ix1;
2549 r_shadow_lightscissor[1] = iy1;
2550 r_shadow_lightscissor[2] = ix2 - ix1;
2551 r_shadow_lightscissor[3] = iy2 - iy1;
2553 r_refdef.stats.lights_scissored++;
2557 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, int numtriangles, const int *element3i, const float *diffusecolor, const float *ambientcolor)
2559 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
2560 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
2561 float *color4f = rsurface.array_color4f + 4 * firstvertex;
2562 float dist, dot, distintensity, shadeintensity, v[3], n[3];
2563 switch (r_shadow_rendermode)
2565 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2566 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2567 if (VectorLength2(diffusecolor) > 0)
2569 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2571 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2572 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2573 if ((dot = DotProduct(n, v)) < 0)
2575 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2576 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
2579 VectorCopy(ambientcolor, color4f);
2580 if (r_refdef.fogenabled)
2583 f = RSurf_FogVertex(vertex3f);
2584 VectorScale(color4f, f, color4f);
2591 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2593 VectorCopy(ambientcolor, color4f);
2594 if (r_refdef.fogenabled)
2597 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2598 f = RSurf_FogVertex(vertex3f);
2599 VectorScale(color4f, f, color4f);
2605 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2606 if (VectorLength2(diffusecolor) > 0)
2608 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2610 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2611 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2613 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2614 if ((dot = DotProduct(n, v)) < 0)
2616 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2617 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2618 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2619 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2623 color4f[0] = ambientcolor[0] * distintensity;
2624 color4f[1] = ambientcolor[1] * distintensity;
2625 color4f[2] = ambientcolor[2] * distintensity;
2627 if (r_refdef.fogenabled)
2630 f = RSurf_FogVertex(vertex3f);
2631 VectorScale(color4f, f, color4f);
2635 VectorClear(color4f);
2641 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2643 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2644 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2646 color4f[0] = ambientcolor[0] * distintensity;
2647 color4f[1] = ambientcolor[1] * distintensity;
2648 color4f[2] = ambientcolor[2] * distintensity;
2649 if (r_refdef.fogenabled)
2652 f = RSurf_FogVertex(vertex3f);
2653 VectorScale(color4f, f, color4f);
2657 VectorClear(color4f);
2662 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2663 if (VectorLength2(diffusecolor) > 0)
2665 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2667 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2668 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2670 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2671 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2672 if ((dot = DotProduct(n, v)) < 0)
2674 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2675 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2676 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2677 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2681 color4f[0] = ambientcolor[0] * distintensity;
2682 color4f[1] = ambientcolor[1] * distintensity;
2683 color4f[2] = ambientcolor[2] * distintensity;
2685 if (r_refdef.fogenabled)
2688 f = RSurf_FogVertex(vertex3f);
2689 VectorScale(color4f, f, color4f);
2693 VectorClear(color4f);
2699 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2701 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2702 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2704 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2705 color4f[0] = ambientcolor[0] * distintensity;
2706 color4f[1] = ambientcolor[1] * distintensity;
2707 color4f[2] = ambientcolor[2] * distintensity;
2708 if (r_refdef.fogenabled)
2711 f = RSurf_FogVertex(vertex3f);
2712 VectorScale(color4f, f, color4f);
2716 VectorClear(color4f);
2726 static void R_Shadow_RenderLighting_VisibleLighting(int firstvertex, int numvertices, int firsttriangle, int numtriangles, const int *element3i, const unsigned short *element3s, int element3i_bufferobject, int element3s_bufferobject)
2728 // used to display how many times a surface is lit for level design purposes
2729 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2732 static void R_Shadow_RenderLighting_Light_GLSL(int firstvertex, int numvertices, int firsttriangle, int numtriangles, const int *element3i, const unsigned short *element3s, int element3i_bufferobject, int element3s_bufferobject, const vec3_t lightcolor, float ambientscale, float diffusescale, float specularscale)
2734 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2735 R_SetupShader_Surface(lightcolor, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT);
2736 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2738 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2740 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2741 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2743 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
2747 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
2754 int newnumtriangles;
2758 int maxtriangles = 4096;
2759 static int newelements[4096*3];
2760 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, numtriangles, element3i, diffusecolor2, ambientcolor2);
2761 for (renders = 0;renders < 4;renders++)
2766 newnumtriangles = 0;
2768 // due to low fillrate on the cards this vertex lighting path is
2769 // designed for, we manually cull all triangles that do not
2770 // contain a lit vertex
2771 // this builds batches of triangles from multiple surfaces and
2772 // renders them at once
2773 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
2775 if (VectorLength2(rsurface.array_color4f + e[0] * 4) + VectorLength2(rsurface.array_color4f + e[1] * 4) + VectorLength2(rsurface.array_color4f + e[2] * 4) >= 0.01)
2777 if (newnumtriangles)
2779 newfirstvertex = min(newfirstvertex, e[0]);
2780 newlastvertex = max(newlastvertex, e[0]);
2784 newfirstvertex = e[0];
2785 newlastvertex = e[0];
2787 newfirstvertex = min(newfirstvertex, e[1]);
2788 newlastvertex = max(newlastvertex, e[1]);
2789 newfirstvertex = min(newfirstvertex, e[2]);
2790 newlastvertex = max(newlastvertex, e[2]);
2796 if (newnumtriangles >= maxtriangles)
2798 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
2799 newnumtriangles = 0;
2805 if (newnumtriangles >= 1)
2807 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
2810 // if we couldn't find any lit triangles, exit early
2813 // now reduce the intensity for the next overbright pass
2814 // we have to clamp to 0 here incase the drivers have improper
2815 // handling of negative colors
2816 // (some old drivers even have improper handling of >1 color)
2818 for (i = 0, c = rsurface.array_color4f + 4 * firstvertex;i < numvertices;i++, c += 4)
2820 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
2822 c[0] = max(0, c[0] - 1);
2823 c[1] = max(0, c[1] - 1);
2824 c[2] = max(0, c[2] - 1);
2836 static void R_Shadow_RenderLighting_Light_Vertex(int firstvertex, int numvertices, int numtriangles, const int *element3i, const vec3_t lightcolor, float ambientscale, float diffusescale)
2838 // OpenGL 1.1 path (anything)
2839 float ambientcolorbase[3], diffusecolorbase[3];
2840 float ambientcolorpants[3], diffusecolorpants[3];
2841 float ambientcolorshirt[3], diffusecolorshirt[3];
2842 const float *surfacecolor = rsurface.texture->dlightcolor;
2843 const float *surfacepants = rsurface.colormap_pantscolor;
2844 const float *surfaceshirt = rsurface.colormap_shirtcolor;
2845 rtexture_t *basetexture = rsurface.texture->basetexture;
2846 rtexture_t *pantstexture = rsurface.texture->pantstexture;
2847 rtexture_t *shirttexture = rsurface.texture->shirttexture;
2848 qboolean dopants = pantstexture && VectorLength2(surfacepants) >= (1.0f / 1048576.0f);
2849 qboolean doshirt = shirttexture && VectorLength2(surfaceshirt) >= (1.0f / 1048576.0f);
2850 ambientscale *= 2 * r_refdef.view.colorscale;
2851 diffusescale *= 2 * r_refdef.view.colorscale;
2852 ambientcolorbase[0] = lightcolor[0] * ambientscale * surfacecolor[0];ambientcolorbase[1] = lightcolor[1] * ambientscale * surfacecolor[1];ambientcolorbase[2] = lightcolor[2] * ambientscale * surfacecolor[2];
2853 diffusecolorbase[0] = lightcolor[0] * diffusescale * surfacecolor[0];diffusecolorbase[1] = lightcolor[1] * diffusescale * surfacecolor[1];diffusecolorbase[2] = lightcolor[2] * diffusescale * surfacecolor[2];
2854 ambientcolorpants[0] = ambientcolorbase[0] * surfacepants[0];ambientcolorpants[1] = ambientcolorbase[1] * surfacepants[1];ambientcolorpants[2] = ambientcolorbase[2] * surfacepants[2];
2855 diffusecolorpants[0] = diffusecolorbase[0] * surfacepants[0];diffusecolorpants[1] = diffusecolorbase[1] * surfacepants[1];diffusecolorpants[2] = diffusecolorbase[2] * surfacepants[2];
2856 ambientcolorshirt[0] = ambientcolorbase[0] * surfaceshirt[0];ambientcolorshirt[1] = ambientcolorbase[1] * surfaceshirt[1];ambientcolorshirt[2] = ambientcolorbase[2] * surfaceshirt[2];
2857 diffusecolorshirt[0] = diffusecolorbase[0] * surfaceshirt[0];diffusecolorshirt[1] = diffusecolorbase[1] * surfaceshirt[1];diffusecolorshirt[2] = diffusecolorbase[2] * surfaceshirt[2];
2858 R_Mesh_TexBind(0, basetexture);
2859 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
2860 R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
2861 R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
2862 switch(r_shadow_rendermode)
2864 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2865 R_Mesh_TexBind(1, r_shadow_attenuation3dtexture);
2866 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
2867 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
2868 R_Mesh_TexCoordPointer(1, 3, rsurface.vertex3f, rsurface.vertex3f_bufferobject, rsurface.vertex3f_bufferoffset);
2870 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2871 R_Mesh_TexBind(2, r_shadow_attenuation2dtexture);
2872 R_Mesh_TexMatrix(2, &rsurface.entitytoattenuationz);
2873 R_Mesh_TexCombine(2, GL_MODULATE, GL_MODULATE, 1, 1);
2874 R_Mesh_TexCoordPointer(2, 3, rsurface.vertex3f, rsurface.vertex3f_bufferobject, rsurface.vertex3f_bufferoffset);
2876 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2877 R_Mesh_TexBind(1, r_shadow_attenuation2dtexture);
2878 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
2879 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
2880 R_Mesh_TexCoordPointer(1, 3, rsurface.vertex3f, rsurface.vertex3f_bufferobject, rsurface.vertex3f_bufferoffset);
2882 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2887 //R_Mesh_TexBind(0, basetexture);
2888 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorbase, ambientcolorbase);
2891 R_Mesh_TexBind(0, pantstexture);
2892 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorpants, ambientcolorpants);
2896 R_Mesh_TexBind(0, shirttexture);
2897 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorshirt, ambientcolorshirt);
2901 extern cvar_t gl_lightmaps;
2902 void R_Shadow_RenderLighting(int firstvertex, int numvertices, int firsttriangle, int numtriangles, const int *element3i, const unsigned short *element3s, int element3i_bufferobject, int element3s_bufferobject)
2904 float ambientscale, diffusescale, specularscale;
2906 float lightcolor[3];
2907 VectorCopy(rsurface.rtlight->currentcolor, lightcolor);
2908 ambientscale = rsurface.rtlight->ambientscale;
2909 diffusescale = rsurface.rtlight->diffusescale;
2910 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
2911 if (!r_shadow_usenormalmap.integer)
2913 ambientscale += 1.0f * diffusescale;
2917 if ((ambientscale + diffusescale) * VectorLength2(lightcolor) + specularscale * VectorLength2(lightcolor) < (1.0f / 1048576.0f))
2919 negated = (lightcolor[0] + lightcolor[1] + lightcolor[2] < 0) && vid.support.ext_blend_subtract;
2922 VectorNegate(lightcolor, lightcolor);
2923 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
2925 RSurf_SetupDepthAndCulling();
2926 switch (r_shadow_rendermode)
2928 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2929 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2930 R_Shadow_RenderLighting_VisibleLighting(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2932 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2933 R_Shadow_RenderLighting_Light_GLSL(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolor, ambientscale, diffusescale, specularscale);
2935 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2936 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2937 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2938 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2939 R_Shadow_RenderLighting_Light_Vertex(firstvertex, numvertices, numtriangles, element3i + firsttriangle * 3, lightcolor, ambientscale, diffusescale);
2942 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2946 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
2949 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)
2951 matrix4x4_t tempmatrix = *matrix;
2952 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
2954 // if this light has been compiled before, free the associated data
2955 R_RTLight_Uncompile(rtlight);
2957 // clear it completely to avoid any lingering data
2958 memset(rtlight, 0, sizeof(*rtlight));
2960 // copy the properties
2961 rtlight->matrix_lighttoworld = tempmatrix;
2962 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
2963 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
2964 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
2965 VectorCopy(color, rtlight->color);
2966 rtlight->cubemapname[0] = 0;
2967 if (cubemapname && cubemapname[0])
2968 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
2969 rtlight->shadow = shadow;
2970 rtlight->corona = corona;
2971 rtlight->style = style;
2972 rtlight->isstatic = isstatic;
2973 rtlight->coronasizescale = coronasizescale;
2974 rtlight->ambientscale = ambientscale;
2975 rtlight->diffusescale = diffusescale;
2976 rtlight->specularscale = specularscale;
2977 rtlight->flags = flags;
2979 // compute derived data
2980 //rtlight->cullradius = rtlight->radius;
2981 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2982 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2983 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2984 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2985 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2986 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2987 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2990 // compiles rtlight geometry
2991 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2992 void R_RTLight_Compile(rtlight_t *rtlight)
2995 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
2996 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
2997 entity_render_t *ent = r_refdef.scene.worldentity;
2998 dp_model_t *model = r_refdef.scene.worldmodel;
2999 unsigned char *data;
3002 // compile the light
3003 rtlight->compiled = true;
3004 rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
3005 rtlight->static_numleafs = 0;
3006 rtlight->static_numleafpvsbytes = 0;
3007 rtlight->static_leaflist = NULL;
3008 rtlight->static_leafpvs = NULL;
3009 rtlight->static_numsurfaces = 0;
3010 rtlight->static_surfacelist = NULL;
3011 rtlight->static_shadowmap_receivers = 0x3F;
3012 rtlight->static_shadowmap_casters = 0x3F;
3013 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3014 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3015 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3016 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3017 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3018 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3020 if (model && model->GetLightInfo)
3022 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
3023 r_shadow_compilingrtlight = rtlight;
3024 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);
3025 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
3026 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
3027 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3028 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
3029 rtlight->static_numsurfaces = numsurfaces;
3030 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
3031 rtlight->static_numleafs = numleafs;
3032 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
3033 rtlight->static_numleafpvsbytes = numleafpvsbytes;
3034 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
3035 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
3036 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
3037 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
3038 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3039 if (rtlight->static_numsurfaces)
3040 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3041 if (rtlight->static_numleafs)
3042 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3043 if (rtlight->static_numleafpvsbytes)
3044 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3045 if (rtlight->static_numshadowtrispvsbytes)
3046 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3047 if (rtlight->static_numlighttrispvsbytes)
3048 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3049 switch (rtlight->shadowmode)
3051 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
3052 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
3053 case R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE:
3054 if (model->CompileShadowMap && rtlight->shadow)
3055 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3058 if (model->CompileShadowVolume && rtlight->shadow)
3059 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3062 // now we're done compiling the rtlight
3063 r_shadow_compilingrtlight = NULL;
3067 // use smallest available cullradius - box radius or light radius
3068 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3069 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3071 shadowzpasstris = 0;
3072 if (rtlight->static_meshchain_shadow_zpass)
3073 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
3074 shadowzpasstris += mesh->numtriangles;
3076 shadowzfailtris = 0;
3077 if (rtlight->static_meshchain_shadow_zfail)
3078 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
3079 shadowzfailtris += mesh->numtriangles;
3082 if (rtlight->static_numlighttrispvsbytes)
3083 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3084 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3088 if (rtlight->static_numlighttrispvsbytes)
3089 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3090 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3093 if (developer_extra.integer)
3094 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);
3097 void R_RTLight_Uncompile(rtlight_t *rtlight)
3099 if (rtlight->compiled)
3101 if (rtlight->static_meshchain_shadow_zpass)
3102 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
3103 rtlight->static_meshchain_shadow_zpass = NULL;
3104 if (rtlight->static_meshchain_shadow_zfail)
3105 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
3106 rtlight->static_meshchain_shadow_zfail = NULL;
3107 if (rtlight->static_meshchain_shadow_shadowmap)
3108 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
3109 rtlight->static_meshchain_shadow_shadowmap = NULL;
3110 // these allocations are grouped
3111 if (rtlight->static_surfacelist)
3112 Mem_Free(rtlight->static_surfacelist);
3113 rtlight->static_numleafs = 0;
3114 rtlight->static_numleafpvsbytes = 0;
3115 rtlight->static_leaflist = NULL;
3116 rtlight->static_leafpvs = NULL;
3117 rtlight->static_numsurfaces = 0;
3118 rtlight->static_surfacelist = NULL;
3119 rtlight->static_numshadowtrispvsbytes = 0;
3120 rtlight->static_shadowtrispvs = NULL;
3121 rtlight->static_numlighttrispvsbytes = 0;
3122 rtlight->static_lighttrispvs = NULL;
3123 rtlight->compiled = false;
3127 void R_Shadow_UncompileWorldLights(void)
3131 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3132 for (lightindex = 0;lightindex < range;lightindex++)
3134 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3137 R_RTLight_Uncompile(&light->rtlight);
3141 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3145 // reset the count of frustum planes
3146 // see rtlight->cached_frustumplanes definition for how much this array
3148 rtlight->cached_numfrustumplanes = 0;
3150 // haven't implemented a culling path for ortho rendering
3151 if (!r_refdef.view.useperspective)
3153 // check if the light is on screen and copy the 4 planes if it is
3154 for (i = 0;i < 4;i++)
3155 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3158 for (i = 0;i < 4;i++)
3159 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3164 // generate a deformed frustum that includes the light origin, this is
3165 // used to cull shadow casting surfaces that can not possibly cast a
3166 // shadow onto the visible light-receiving surfaces, which can be a
3169 // if the light origin is onscreen the result will be 4 planes exactly
3170 // if the light origin is offscreen on only one axis the result will
3171 // be exactly 5 planes (split-side case)
3172 // if the light origin is offscreen on two axes the result will be
3173 // exactly 4 planes (stretched corner case)
3174 for (i = 0;i < 4;i++)
3176 // quickly reject standard frustum planes that put the light
3177 // origin outside the frustum
3178 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3181 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3183 // if all the standard frustum planes were accepted, the light is onscreen
3184 // otherwise we need to generate some more planes below...
3185 if (rtlight->cached_numfrustumplanes < 4)
3187 // at least one of the stock frustum planes failed, so we need to
3188 // create one or two custom planes to enclose the light origin
3189 for (i = 0;i < 4;i++)
3191 // create a plane using the view origin and light origin, and a
3192 // single point from the frustum corner set
3193 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3194 VectorNormalize(plane.normal);
3195 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3196 // see if this plane is backwards and flip it if so
3197 for (j = 0;j < 4;j++)
3198 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3202 VectorNegate(plane.normal, plane.normal);
3204 // flipped plane, test again to see if it is now valid
3205 for (j = 0;j < 4;j++)
3206 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3208 // if the plane is still not valid, then it is dividing the
3209 // frustum and has to be rejected
3213 // we have created a valid plane, compute extra info
3214 PlaneClassify(&plane);
3216 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3218 // if we've found 5 frustum planes then we have constructed a
3219 // proper split-side case and do not need to keep searching for
3220 // planes to enclose the light origin
3221 if (rtlight->cached_numfrustumplanes == 5)
3229 for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
3231 plane = rtlight->cached_frustumplanes[i];
3232 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));
3237 // now add the light-space box planes if the light box is rotated, as any
3238 // caster outside the oriented light box is irrelevant (even if it passed
3239 // the worldspace light box, which is axial)
3240 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3242 for (i = 0;i < 6;i++)
3246 v[i >> 1] = (i & 1) ? -1 : 1;
3247 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3248 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3249 plane.dist = VectorNormalizeLength(plane.normal);
3250 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3251 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3257 // add the world-space reduced box planes
3258 for (i = 0;i < 6;i++)
3260 VectorClear(plane.normal);
3261 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3262 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
3263 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3272 // reduce all plane distances to tightly fit the rtlight cull box, which
3274 VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3275 VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3276 VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3277 VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3278 VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3279 VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3280 VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3281 VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3282 oldnum = rtlight->cached_numfrustumplanes;
3283 rtlight->cached_numfrustumplanes = 0;
3284 for (j = 0;j < oldnum;j++)
3286 // find the nearest point on the box to this plane
3287 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
3288 for (i = 1;i < 8;i++)
3290 dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
3291 if (bestdist > dist)
3294 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);
3295 // if the nearest point is near or behind the plane, we want this
3296 // plane, otherwise the plane is useless as it won't cull anything
3297 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
3299 PlaneClassify(&rtlight->cached_frustumplanes[j]);
3300 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
3307 void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
3311 RSurf_ActiveWorldEntity();
3313 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3316 GL_CullFace(GL_NONE);
3317 mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3318 for (;mesh;mesh = mesh->next)
3320 if (!mesh->sidetotals[r_shadow_shadowmapside])
3322 r_refdef.stats.lights_shadowtriangles += mesh->sidetotals[r_shadow_shadowmapside];
3323 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
3324 R_Mesh_Draw(0, mesh->numverts, mesh->sideoffsets[r_shadow_shadowmapside], mesh->sidetotals[r_shadow_shadowmapside], mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3328 else if (r_refdef.scene.worldentity->model)
3329 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);
3331 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3334 void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3336 qboolean zpass = false;
3339 int surfacelistindex;
3340 msurface_t *surface;
3342 RSurf_ActiveWorldEntity();
3344 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3347 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
3349 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
3350 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
3352 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
3353 for (;mesh;mesh = mesh->next)
3355 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
3356 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
3357 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
3359 // increment stencil if frontface is infront of depthbuffer
3360 GL_CullFace(r_refdef.view.cullface_back);
3361 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
3362 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3363 // decrement stencil if backface is infront of depthbuffer
3364 GL_CullFace(r_refdef.view.cullface_front);
3365 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
3367 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
3369 // decrement stencil if backface is behind depthbuffer
3370 GL_CullFace(r_refdef.view.cullface_front);
3371 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
3372 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3373 // increment stencil if frontface is behind depthbuffer
3374 GL_CullFace(r_refdef.view.cullface_back);
3375 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
3377 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3381 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh)
3383 // use the shadow trispvs calculated earlier by GetLightInfo to cull world triangles on this dynamic light
3384 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
3385 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
3387 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
3388 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
3389 if (CHECKPVSBIT(trispvs, t))
3390 shadowmarklist[numshadowmark++] = t;
3392 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);
3394 else if (numsurfaces)
3395 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);
3397 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3400 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3402 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3403 vec_t relativeshadowradius;
3404 RSurf_ActiveModelEntity(ent, false, false, false);
3405 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3406 // we need to re-init the shader for each entity because the matrix changed
3407 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3408 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3409 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3410 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3411 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3412 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3413 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3414 switch (r_shadow_rendermode)
3416 case R_SHADOW_RENDERMODE_SHADOWMAP2D:
3417 case R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE:
3418 case R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE:
3419 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
3422 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3425 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3428 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3430 // set up properties for rendering light onto this entity
3431 RSurf_ActiveModelEntity(ent, true, true, false);
3432 GL_AlphaTest(false);
3433 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3434 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3435 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3436 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3439 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
3441 if (!r_refdef.scene.worldmodel->DrawLight)
3444 // set up properties for rendering light onto this entity
3445 RSurf_ActiveWorldEntity();
3446 GL_AlphaTest(false);
3447 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3448 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3449 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3450 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3452 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
3454 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3457 void R_Shadow_DrawEntityLight(entity_render_t *ent)
3459 dp_model_t *model = ent->model;
3460 if (!model->DrawLight)
3463 R_Shadow_SetupEntityLight(ent);
3465 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3467 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3470 void R_Shadow_PrepareLight(rtlight_t *rtlight)
3474 int numleafs, numsurfaces;
3475 int *leaflist, *surfacelist;
3476 unsigned char *leafpvs;
3477 unsigned char *shadowtrispvs;
3478 unsigned char *lighttrispvs;
3479 //unsigned char *surfacesides;
3480 int numlightentities;
3481 int numlightentities_noselfshadow;
3482 int numshadowentities;
3483 int numshadowentities_noselfshadow;
3484 static entity_render_t *lightentities[MAX_EDICTS];
3485 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3486 static entity_render_t *shadowentities[MAX_EDICTS];
3487 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3489 rtlight->draw = false;
3491 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3492 // skip lights that are basically invisible (color 0 0 0)
3493 if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
3496 // loading is done before visibility checks because loading should happen
3497 // all at once at the start of a level, not when it stalls gameplay.
3498 // (especially important to benchmarks)
3500 if (rtlight->isstatic && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
3502 if (rtlight->compiled)
3503 R_RTLight_Uncompile(rtlight);
3504 R_RTLight_Compile(rtlight);
3508 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
3510 // look up the light style value at this time
3511 f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3512 VectorScale(rtlight->color, f, rtlight->currentcolor);
3514 if (rtlight->selected)
3516 f = 2 + sin(realtime * M_PI * 4.0);
3517 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3521 // if lightstyle is currently off, don't draw the light
3522 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3525 // if the light box is offscreen, skip it
3526 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3529 VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
3530 VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
3532 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3534 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3536 // compiled light, world available and can receive realtime lighting
3537 // retrieve leaf information
3538 numleafs = rtlight->static_numleafs;
3539 leaflist = rtlight->static_leaflist;
3540 leafpvs = rtlight->static_leafpvs;
3541 numsurfaces = rtlight->static_numsurfaces;
3542 surfacelist = rtlight->static_surfacelist;
3543 //surfacesides = NULL;
3544 shadowtrispvs = rtlight->static_shadowtrispvs;
3545 lighttrispvs = rtlight->static_lighttrispvs;
3547 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3549 // dynamic light, world available and can receive realtime lighting
3550 // calculate lit surfaces and leafs
3551 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);
3552 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3553 leaflist = r_shadow_buffer_leaflist;
3554 leafpvs = r_shadow_buffer_leafpvs;
3555 surfacelist = r_shadow_buffer_surfacelist;
3556 //surfacesides = r_shadow_buffer_surfacesides;
3557 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3558 lighttrispvs = r_shadow_buffer_lighttrispvs;
3559 // if the reduced leaf bounds are offscreen, skip it
3560 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3571 //surfacesides = NULL;
3572 shadowtrispvs = NULL;
3573 lighttrispvs = NULL;
3575 // check if light is illuminating any visible leafs
3578 for (i = 0;i < numleafs;i++)
3579 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3585 // make a list of lit entities and shadow casting entities
3586 numlightentities = 0;
3587 numlightentities_noselfshadow = 0;
3588 numshadowentities = 0;
3589 numshadowentities_noselfshadow = 0;
3591 // add dynamic entities that are lit by the light
3592 for (i = 0;i < r_refdef.scene.numentities;i++)
3595 entity_render_t *ent = r_refdef.scene.entities[i];
3597 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3599 // skip the object entirely if it is not within the valid
3600 // shadow-casting region (which includes the lit region)
3601 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
3603 if (!(model = ent->model))
3605 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
3607 // this entity wants to receive light, is visible, and is
3608 // inside the light box
3609 // TODO: check if the surfaces in the model can receive light
3610 // so now check if it's in a leaf seen by the light
3611 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))
3613 if (ent->flags & RENDER_NOSELFSHADOW)
3614 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
3616 lightentities[numlightentities++] = ent;
3617 // since it is lit, it probably also casts a shadow...
3618 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3619 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3620 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3622 // note: exterior models without the RENDER_NOSELFSHADOW
3623 // flag still create a RENDER_NOSELFSHADOW shadow but
3624 // are lit normally, this means that they are
3625 // self-shadowing but do not shadow other
3626 // RENDER_NOSELFSHADOW entities such as the gun
3627 // (very weird, but keeps the player shadow off the gun)
3628 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3629 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3631 shadowentities[numshadowentities++] = ent;
3634 else if (ent->flags & RENDER_SHADOW)
3636 // this entity is not receiving light, but may still need to
3638 // TODO: check if the surfaces in the model can cast shadow
3639 // now check if it is in a leaf seen by the light
3640 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))
3642 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3643 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3644 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3646 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3647 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3649 shadowentities[numshadowentities++] = ent;
3654 // return if there's nothing at all to light
3655 if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
3658 // count this light in the r_speeds
3659 r_refdef.stats.lights++;
3661 // flag it as worth drawing later
3662 rtlight->draw = true;
3664 // cache all the animated entities that cast a shadow but are not visible
3665 for (i = 0;i < numshadowentities;i++)
3666 if (!shadowentities[i]->animcache_vertex3f)
3667 R_AnimCache_GetEntity(shadowentities[i], false, false);
3668 for (i = 0;i < numshadowentities_noselfshadow;i++)
3669 if (!shadowentities_noselfshadow[i]->animcache_vertex3f)
3670 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
3672 // allocate some temporary memory for rendering this light later in the frame
3673 // reusable buffers need to be copied, static data can be used as-is
3674 rtlight->cached_numlightentities = numlightentities;
3675 rtlight->cached_numlightentities_noselfshadow = numlightentities_noselfshadow;
3676 rtlight->cached_numshadowentities = numshadowentities;
3677 rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
3678 rtlight->cached_numsurfaces = numsurfaces;
3679 rtlight->cached_lightentities = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
3680 rtlight->cached_lightentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
3681 rtlight->cached_shadowentities = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
3682 rtlight->cached_shadowentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
3683 if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
3685 int numshadowtrispvsbytes = (((r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles) + 7) >> 3);
3686 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
3687 rtlight->cached_shadowtrispvs = (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
3688 rtlight->cached_lighttrispvs = (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
3689 rtlight->cached_surfacelist = (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
3693 // compiled light data
3694 rtlight->cached_shadowtrispvs = shadowtrispvs;
3695 rtlight->cached_lighttrispvs = lighttrispvs;
3696 rtlight->cached_surfacelist = surfacelist;
3700 void R_Shadow_DrawLight(rtlight_t *rtlight)
3704 unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
3705 int numlightentities;
3706 int numlightentities_noselfshadow;
3707 int numshadowentities;
3708 int numshadowentities_noselfshadow;
3709 entity_render_t **lightentities;
3710 entity_render_t **lightentities_noselfshadow;
3711 entity_render_t **shadowentities;
3712 entity_render_t **shadowentities_noselfshadow;
3714 static unsigned char entitysides[MAX_EDICTS];
3715 static unsigned char entitysides_noselfshadow[MAX_EDICTS];
3716 vec3_t nearestpoint;
3718 qboolean castshadows;
3721 // check if we cached this light this frame (meaning it is worth drawing)
3725 // if R_FrameData_Store ran out of space we skip anything dependent on it
3726 if (r_framedata_failed)
3729 numlightentities = rtlight->cached_numlightentities;
3730 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
3731 numshadowentities = rtlight->cached_numshadowentities;
3732 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
3733 numsurfaces = rtlight->cached_numsurfaces;
3734 lightentities = rtlight->cached_lightentities;
3735 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
3736 shadowentities = rtlight->cached_shadowentities;
3737 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
3738 shadowtrispvs = rtlight->cached_shadowtrispvs;
3739 lighttrispvs = rtlight->cached_lighttrispvs;
3740 surfacelist = rtlight->cached_surfacelist;
3742 // set up a scissor rectangle for this light
3743 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3746 // don't let sound skip if going slow
3747 if (r_refdef.scene.extraupdate)
3750 // make this the active rtlight for rendering purposes
3751 R_Shadow_RenderMode_ActiveLight(rtlight);
3753 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
3755 // optionally draw visible shape of the shadow volumes
3756 // for performance analysis by level designers
3757 R_Shadow_RenderMode_VisibleShadowVolumes();
3759 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
3760 for (i = 0;i < numshadowentities;i++)
3761 R_Shadow_DrawEntityShadow(shadowentities[i]);
3762 for (i = 0;i < numshadowentities_noselfshadow;i++)
3763 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3764 R_Shadow_RenderMode_VisibleLighting(false, false);
3767 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
3769 // optionally draw the illuminated areas
3770 // for performance analysis by level designers
3771 R_Shadow_RenderMode_VisibleLighting(false, false);
3773 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3774 for (i = 0;i < numlightentities;i++)
3775 R_Shadow_DrawEntityLight(lightentities[i]);
3776 for (i = 0;i < numlightentities_noselfshadow;i++)
3777 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3780 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
3782 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
3783 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
3784 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
3785 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
3787 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance/rtlight->radius));
3788 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
3789 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
3791 if (castshadows && (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE))
3797 int receivermask = 0;
3798 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
3799 Matrix4x4_Abs(&radiustolight);
3801 r_shadow_shadowmaplod = 0;
3802 for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
3803 if ((r_shadow_shadowmapmaxsize >> i) > lodlinear)
3804 r_shadow_shadowmaplod = i;
3806 if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
3807 size = max(1, r_shadow_shadowmapmaxsize >> r_shadow_shadowmaplod);
3809 size = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
3811 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
3813 surfacesides = NULL;
3816 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3818 castermask = rtlight->static_shadowmap_casters;
3819 receivermask = rtlight->static_shadowmap_receivers;
3823 surfacesides = r_shadow_buffer_surfacesides;
3824 for(i = 0;i < numsurfaces;i++)
3826 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
3827 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3828 castermask |= surfacesides[i];
3829 receivermask |= surfacesides[i];
3833 if (receivermask < 0x3F)
3835 for (i = 0;i < numlightentities;i++)
3836 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3837 if (receivermask < 0x3F)
3838 for(i = 0; i < numlightentities_noselfshadow;i++)
3839 receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3842 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
3846 for (i = 0;i < numshadowentities;i++)
3847 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3848 for (i = 0;i < numshadowentities_noselfshadow;i++)
3849 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3852 //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
3854 // render shadow casters into 6 sided depth texture
3855 for (side = 0;side < 6;side++) if (receivermask & (1 << side))
3857 R_Shadow_RenderMode_ShadowMap(side, receivermask, size);
3858 if (! (castermask & (1 << side))) continue;
3860 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
3861 for (i = 0;i < numshadowentities;i++) if (entitysides[i] & (1 << side))
3862 R_Shadow_DrawEntityShadow(shadowentities[i]);
3865 if (numlightentities_noselfshadow)
3867 // render lighting using the depth texture as shadowmap
3868 // draw lighting in the unmasked areas
3869 R_Shadow_RenderMode_Lighting(false, false, true);
3870 for (i = 0;i < numlightentities_noselfshadow;i++)
3871 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3874 // render shadow casters into 6 sided depth texture
3875 if (numshadowentities_noselfshadow)
3877 for (side = 0;side < 6;side++) if ((receivermask & castermask) & (1 << side))
3879 R_Shadow_RenderMode_ShadowMap(side, 0, size);
3880 for (i = 0;i < numshadowentities_noselfshadow;i++) if (entitysides_noselfshadow[i] & (1 << side))
3881 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3885 // render lighting using the depth texture as shadowmap
3886 // draw lighting in the unmasked areas
3887 R_Shadow_RenderMode_Lighting(false, false, true);
3888 // draw lighting in the unmasked areas
3890 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3891 for (i = 0;i < numlightentities;i++)
3892 R_Shadow_DrawEntityLight(lightentities[i]);
3894 else if (castshadows && vid.stencil)
3896 // draw stencil shadow volumes to mask off pixels that are in shadow
3897 // so that they won't receive lighting
3898 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
3899 R_Shadow_ClearStencil();
3902 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
3903 for (i = 0;i < numshadowentities;i++)
3904 R_Shadow_DrawEntityShadow(shadowentities[i]);
3906 // draw lighting in the unmasked areas
3907 R_Shadow_RenderMode_Lighting(true, false, false);
3908 for (i = 0;i < numlightentities_noselfshadow;i++)
3909 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3911 for (i = 0;i < numshadowentities_noselfshadow;i++)
3912 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3914 // draw lighting in the unmasked areas
3915 R_Shadow_RenderMode_Lighting(true, false, false);
3917 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3918 for (i = 0;i < numlightentities;i++)
3919 R_Shadow_DrawEntityLight(lightentities[i]);
3923 // draw lighting in the unmasked areas
3924 R_Shadow_RenderMode_Lighting(false, false, false);
3926 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3927 for (i = 0;i < numlightentities;i++)
3928 R_Shadow_DrawEntityLight(lightentities[i]);
3929 for (i = 0;i < numlightentities_noselfshadow;i++)
3930 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3933 if (r_shadow_usingdeferredprepass)
3935 // when rendering deferred lighting, we simply rasterize the box
3936 if (castshadows && (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE))
3937 R_Shadow_RenderMode_DrawDeferredLight(false, true);
3938 else if (castshadows && vid.stencil)
3939 R_Shadow_RenderMode_DrawDeferredLight(true, false);
3941 R_Shadow_RenderMode_DrawDeferredLight(false, false);
3945 static void R_Shadow_FreeDeferred(void)
3947 if (r_shadow_prepassgeometryfbo)
3948 qglDeleteFramebuffersEXT(1, &r_shadow_prepassgeometryfbo);CHECKGLERROR
3949 r_shadow_prepassgeometryfbo = 0;
3951 if (r_shadow_prepasslightingfbo)
3952 qglDeleteFramebuffersEXT(1, &r_shadow_prepasslightingfbo);CHECKGLERROR
3953 r_shadow_prepasslightingfbo = 0;
3955 if (r_shadow_prepassgeometrydepthtexture)
3956 R_FreeTexture(r_shadow_prepassgeometrydepthtexture);
3957 r_shadow_prepassgeometrydepthtexture = NULL;
3959 if (r_shadow_prepassgeometrynormalmaptexture)
3960 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
3961 r_shadow_prepassgeometrynormalmaptexture = NULL;
3963 if (r_shadow_prepasslightingdiffusetexture)
3964 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
3965 r_shadow_prepasslightingdiffusetexture = NULL;
3967 if (r_shadow_prepasslightingspeculartexture)
3968 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
3969 r_shadow_prepasslightingspeculartexture = NULL;
3972 void R_Shadow_DrawPrepass(void)
3980 entity_render_t *ent;
3982 GL_AlphaTest(false);
3983 R_Mesh_ColorPointer(NULL, 0, 0);
3984 R_Mesh_ResetTextureState();
3986 GL_ColorMask(1,1,1,1);
3987 GL_BlendFunc(GL_ONE, GL_ZERO);
3990 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepassgeometryfbo);CHECKGLERROR
3991 qglClearColor(0.5f,0.5f,0.5f,1.0f);CHECKGLERROR
3992 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);CHECKGLERROR
3994 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
3995 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
3996 if (r_timereport_active)
3997 R_TimeReport("prepassworld");
3999 for (i = 0;i < r_refdef.scene.numentities;i++)
4001 if (!r_refdef.viewcache.entityvisible[i])
4003 ent = r_refdef.scene.entities[i];
4004 if (ent->model && ent->model->DrawPrepass != NULL)
4005 ent->model->DrawPrepass(ent);
4008 if (r_timereport_active)
4009 R_TimeReport("prepassmodels");
4011 GL_DepthMask(false);
4012 GL_ColorMask(1,1,1,1);
4015 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepasslightingfbo);CHECKGLERROR
4016 qglClearColor(0.0f,0.0f,0.0f,0.0f);CHECKGLERROR
4017 GL_Clear(GL_COLOR_BUFFER_BIT);CHECKGLERROR
4018 if (r_refdef.fogenabled)
4019 qglClearColor(r_refdef.fogcolor[0],r_refdef.fogcolor[1],r_refdef.fogcolor[2],0);CHECKGLERROR
4021 R_Shadow_RenderMode_Begin();
4023 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4024 if (r_shadow_debuglight.integer >= 0)
4026 lightindex = r_shadow_debuglight.integer;
4027 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4028 if (light && (light->flags & flag))
4029 R_Shadow_DrawLight(&light->rtlight);
4033 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4034 for (lightindex = 0;lightindex < range;lightindex++)
4036 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4037 if (light && (light->flags & flag))
4038 R_Shadow_DrawLight(&light->rtlight);
4041 if (r_refdef.scene.rtdlight)
4042 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4043 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4045 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);CHECKGLERROR
4046 if (r_refdef.fogenabled)
4047 qglClearColor(r_refdef.fogcolor[0],r_refdef.fogcolor[1],r_refdef.fogcolor[2],0);CHECKGLERROR
4049 R_Shadow_RenderMode_End();
4051 if (r_timereport_active)
4052 R_TimeReport("prepasslights");
4055 void R_Shadow_DrawLightSprites(void);
4056 void R_Shadow_PrepareLights(void)
4066 if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4) ||
4067 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
4068 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0) ||
4069 r_shadow_shadowmaptexturetype != r_shadow_shadowmapping_texturetype.integer ||
4070 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
4071 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
4072 r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
4073 R_Shadow_FreeShadowMaps();
4075 r_shadow_usingshadowmaportho = false;
4077 switch (vid.renderpath)
4079 case RENDERPATH_GL20:
4080 case RENDERPATH_CGGL:
4081 if (!r_shadow_deferred.integer || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_STENCIL || !vid.support.ext_framebuffer_object || vid.maxdrawbuffers < 2)
4083 r_shadow_usingdeferredprepass = false;
4084 if (r_shadow_prepass_width)
4085 R_Shadow_FreeDeferred();
4086 r_shadow_prepass_width = r_shadow_prepass_height = 0;
4090 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
4092 R_Shadow_FreeDeferred();
4094 r_shadow_usingdeferredprepass = true;
4095 r_shadow_prepass_width = vid.width;
4096 r_shadow_prepass_height = vid.height;
4097 r_shadow_prepassgeometrydepthtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "prepassgeometrydepthmap", vid.width, vid.height, 24, false);
4098 r_shadow_prepassgeometrynormalmaptexture = R_LoadTexture2D(r_shadow_texturepool, "prepassgeometrynormalmap", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, NULL);
4099 r_shadow_prepasslightingdiffusetexture = R_LoadTexture2D(r_shadow_texturepool, "prepasslightingdiffuse", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, NULL);
4100 r_shadow_prepasslightingspeculartexture = R_LoadTexture2D(r_shadow_texturepool, "prepasslightingspecular", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, NULL);
4102 // set up the geometry pass fbo (depth + normalmap)
4103 qglGenFramebuffersEXT(1, &r_shadow_prepassgeometryfbo);CHECKGLERROR
4104 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepassgeometryfbo);CHECKGLERROR
4105 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_prepassgeometrydepthtexture), 0);CHECKGLERROR
4106 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_prepassgeometrynormalmaptexture), 0);CHECKGLERROR
4107 // render depth into one texture and normalmap into the other
4108 if (qglDrawBuffersARB)
4110 qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);CHECKGLERROR
4111 qglReadBuffer(GL_NONE);CHECKGLERROR
4113 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4114 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4116 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4117 Cvar_SetValueQuick(&r_shadow_deferred, 0);
4118 r_shadow_usingdeferredprepass = false;
4121 // set up the lighting pass fbo (diffuse + specular)
4122 qglGenFramebuffersEXT(1, &r_shadow_prepasslightingfbo);CHECKGLERROR
4123 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepasslightingfbo);CHECKGLERROR
4124 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_prepassgeometrydepthtexture), 0);CHECKGLERROR
4125 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_prepasslightingdiffusetexture), 0);CHECKGLERROR
4126 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_prepasslightingspeculartexture), 0);CHECKGLERROR
4127 // render diffuse into one texture and specular into another,
4128 // with depth and normalmap bound as textures,
4129 // with depth bound as attachment as well
4130 if (qglDrawBuffersARB)
4132 qglDrawBuffersARB(2, r_shadow_prepasslightingdrawbuffers);CHECKGLERROR
4133 qglReadBuffer(GL_NONE);CHECKGLERROR
4135 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4136 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4138 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4139 Cvar_SetValueQuick(&r_shadow_deferred, 0);
4140 r_shadow_usingdeferredprepass = false;
4144 case RENDERPATH_GL13:
4145 case RENDERPATH_GL11:
4146 r_shadow_usingdeferredprepass = false;
4150 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);
4152 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4153 if (r_shadow_debuglight.integer >= 0)
4155 lightindex = r_shadow_debuglight.integer;
4156 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4157 if (light && (light->flags & flag))
4158 R_Shadow_PrepareLight(&light->rtlight);
4162 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4163 for (lightindex = 0;lightindex < range;lightindex++)
4165 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4166 if (light && (light->flags & flag))
4167 R_Shadow_PrepareLight(&light->rtlight);
4170 if (r_refdef.scene.rtdlight)
4172 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4173 R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
4175 else if(gl_flashblend.integer)
4177 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4179 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
4180 f = (rtlight->style >= 0 ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4181 VectorScale(rtlight->color, f, rtlight->currentcolor);
4185 if (r_editlights.integer)
4186 R_Shadow_DrawLightSprites();
4189 void R_Shadow_DrawLights(void)
4197 R_Shadow_RenderMode_Begin();
4199 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4200 if (r_shadow_debuglight.integer >= 0)
4202 lightindex = r_shadow_debuglight.integer;
4203 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4204 if (light && (light->flags & flag))
4205 R_Shadow_DrawLight(&light->rtlight);
4209 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4210 for (lightindex = 0;lightindex < range;lightindex++)
4212 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4213 if (light && (light->flags & flag))
4214 R_Shadow_DrawLight(&light->rtlight);
4217 if (r_refdef.scene.rtdlight)
4218 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4219 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4221 R_Shadow_RenderMode_End();
4224 extern const float r_screenvertex3f[12];
4225 extern void R_SetupView(qboolean allowwaterclippingplane);
4226 extern void R_ResetViewRendering3D(void);
4227 extern void R_ResetViewRendering2D(void);
4228 extern cvar_t r_shadows;
4229 extern cvar_t r_shadows_darken;
4230 extern cvar_t r_shadows_drawafterrtlighting;
4231 extern cvar_t r_shadows_castfrombmodels;
4232 extern cvar_t r_shadows_throwdistance;
4233 extern cvar_t r_shadows_throwdirection;
4234 extern cvar_t r_shadows_focus;
4235 extern cvar_t r_shadows_shadowmapscale;
4237 void R_Shadow_PrepareModelShadows(void)
4240 float scale, size, radius, dot1, dot2;
4241 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
4242 entity_render_t *ent;
4244 if (!r_refdef.scene.numentities)
4247 switch (r_shadow_shadowmode)
4249 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4250 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
4252 case R_SHADOW_SHADOWMODE_STENCIL:
4253 for (i = 0;i < r_refdef.scene.numentities;i++)
4255 ent = r_refdef.scene.entities[i];
4256 if (!ent->animcache_vertex3f && ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4257 R_AnimCache_GetEntity(ent, false, false);
4264 size = 2*r_shadow_shadowmapmaxsize;
4265 scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
4266 radius = 0.5f * size / scale;
4268 Math_atov(r_shadows_throwdirection.string, shadowdir);
4269 VectorNormalize(shadowdir);
4270 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4271 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4272 if (fabs(dot1) <= fabs(dot2))
4273 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4275 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4276 VectorNormalize(shadowforward);
4277 CrossProduct(shadowdir, shadowforward, shadowright);
4278 Math_atov(r_shadows_focus.string, shadowfocus);
4279 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4280 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4281 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4282 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4283 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4285 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4287 shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4288 shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4289 shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4290 shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4291 shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4292 shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4294 for (i = 0;i < r_refdef.scene.numentities;i++)
4296 ent = r_refdef.scene.entities[i];
4297 if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
4299 // cast shadows from anything of the map (submodels are optional)
4300 if (!ent->animcache_vertex3f && ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4301 R_AnimCache_GetEntity(ent, false, false);
4305 void R_DrawModelShadowMaps(void)
4308 float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
4309 entity_render_t *ent;
4310 vec3_t relativelightorigin;
4311 vec3_t relativelightdirection, relativeforward, relativeright;
4312 vec3_t relativeshadowmins, relativeshadowmaxs;
4313 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
4315 matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
4316 r_viewport_t viewport;
4319 if (!r_refdef.scene.numentities)
4322 switch (r_shadow_shadowmode)
4324 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4325 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
4332 R_ResetViewRendering3D();
4333 R_Shadow_RenderMode_Begin();
4334 R_Shadow_RenderMode_ActiveLight(NULL);
4336 switch (r_shadow_shadowmode)
4338 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4339 if (!r_shadow_shadowmap2dtexture)
4340 R_Shadow_MakeShadowMap(0, r_shadow_shadowmapmaxsize);
4341 fbo = r_shadow_fbo2d;
4342 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
4343 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
4344 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
4346 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
4347 if (!r_shadow_shadowmaprectangletexture)
4348 R_Shadow_MakeShadowMap(0, r_shadow_shadowmapmaxsize);
4349 fbo = r_shadow_fborectangle;
4350 r_shadow_shadowmap_texturescale[0] = 1.0f;
4351 r_shadow_shadowmap_texturescale[1] = 1.0f;
4352 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE;
4358 size = 2*r_shadow_shadowmapmaxsize;
4359 scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
4360 radius = 0.5f / scale;
4361 nearclip = -r_shadows_throwdistance.value;
4362 farclip = r_shadows_throwdistance.value;
4363 bias = r_shadow_shadowmapping_bias.value * r_shadow_shadowmapping_nearclip.value / (2 * r_shadows_throwdistance.value) * (1024.0f / size);
4365 r_shadow_shadowmap_parameters[0] = size;
4366 r_shadow_shadowmap_parameters[1] = size;
4367 r_shadow_shadowmap_parameters[2] = 1.0;
4368 r_shadow_shadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
4370 Math_atov(r_shadows_throwdirection.string, shadowdir);
4371 VectorNormalize(shadowdir);
4372 Math_atov(r_shadows_focus.string, shadowfocus);
4373 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4374 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4375 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4376 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4377 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4378 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4379 if (fabs(dot1) <= fabs(dot2))
4380 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4382 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4383 VectorNormalize(shadowforward);
4384 VectorM(scale, shadowforward, &m[0]);
4385 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4387 m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
4388 CrossProduct(shadowdir, shadowforward, shadowright);
4389 VectorM(scale, shadowright, &m[4]);
4390 m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
4391 VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
4392 m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
4393 Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
4394 Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
4395 R_Viewport_InitOrtho(&viewport, &cameramatrix, 0, 0, size, size, 0, 0, 1, 1, 0, -1, NULL);
4397 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4400 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);CHECKGLERROR
4401 R_SetupShader_ShowDepth();
4403 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);CHECKGLERROR
4404 R_SetupShader_DepthOrShadow();
4407 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
4410 R_SetViewport(&viewport);
4411 GL_Scissor(viewport.x, viewport.y, min(viewport.width + r_shadow_shadowmapborder, 2*r_shadow_shadowmapmaxsize), viewport.height + r_shadow_shadowmapborder);
4414 qglClearColor(1,1,1,1);
4415 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
4417 GL_Clear(GL_DEPTH_BUFFER_BIT);
4419 GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
4422 for (i = 0;i < r_refdef.scene.numentities;i++)
4424 ent = r_refdef.scene.entities[i];
4426 // cast shadows from anything of the map (submodels are optional)
4427 if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4429 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4430 Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
4431 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4432 Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
4433 Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
4434 relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4435 relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4436 relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4437 relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4438 relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4439 relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4440 RSurf_ActiveModelEntity(ent, false, false, false);
4441 ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
4442 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4446 R_Shadow_RenderMode_End();
4448 Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
4449 Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
4450 Matrix4x4_CreateScale3(&scalematrix, size, -size, 1);
4451 Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
4452 Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
4453 Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
4455 r_shadow_usingshadowmaportho = true;
4456 switch (r_shadow_shadowmode)
4458 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4459 r_shadow_usingshadowmap2d = true;
4461 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
4462 r_shadow_usingshadowmaprect = true;
4469 void R_DrawModelShadows(void)
4472 float relativethrowdistance;
4473 entity_render_t *ent;
4474 vec3_t relativelightorigin;
4475 vec3_t relativelightdirection;
4476 vec3_t relativeshadowmins, relativeshadowmaxs;
4477 vec3_t tmp, shadowdir;
4479 if (!r_refdef.scene.numentities || !vid.stencil || r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL)
4483 R_ResetViewRendering3D();
4484 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4485 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4486 R_Shadow_RenderMode_Begin();
4487 R_Shadow_RenderMode_ActiveLight(NULL);
4488 r_shadow_lightscissor[0] = r_refdef.view.x;
4489 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
4490 r_shadow_lightscissor[2] = r_refdef.view.width;
4491 r_shadow_lightscissor[3] = r_refdef.view.height;
4492 R_Shadow_RenderMode_StencilShadowVolumes(false);
4495 if (r_shadows.integer == 2)
4497 Math_atov(r_shadows_throwdirection.string, shadowdir);
4498 VectorNormalize(shadowdir);
4501 R_Shadow_ClearStencil();
4503 for (i = 0;i < r_refdef.scene.numentities;i++)
4505 ent = r_refdef.scene.entities[i];
4507 // cast shadows from anything of the map (submodels are optional)
4508 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4510 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4511 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
4512 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
4513 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
4514 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4517 if(ent->entitynumber != 0)
4519 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
4520 int entnum, entnum2, recursion;
4521 entnum = entnum2 = ent->entitynumber;
4522 for(recursion = 32; recursion > 0; --recursion)
4524 entnum2 = cl.entities[entnum].state_current.tagentity;
4525 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
4530 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
4532 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
4533 // transform into modelspace of OUR entity
4534 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
4535 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
4538 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4541 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4544 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
4545 RSurf_ActiveModelEntity(ent, false, false, false);
4546 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4547 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4551 // not really the right mode, but this will disable any silly stencil features
4552 R_Shadow_RenderMode_End();
4554 // set up ortho view for rendering this pass
4555 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4556 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4557 //GL_ScissorTest(true);
4558 //R_EntityMatrix(&identitymatrix);
4559 //R_Mesh_ResetTextureState();
4560 R_ResetViewRendering2D();
4561 R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
4562 R_Mesh_ColorPointer(NULL, 0, 0);
4563 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
4565 // set up a darkening blend on shadowed areas
4566 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4567 //GL_DepthRange(0, 1);
4568 //GL_DepthTest(false);
4569 //GL_DepthMask(false);
4570 //GL_PolygonOffset(0, 0);CHECKGLERROR
4571 GL_Color(0, 0, 0, r_shadows_darken.value);
4572 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4573 //qglDepthFunc(GL_ALWAYS);CHECKGLERROR
4574 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
4575 qglStencilMask(255);CHECKGLERROR
4576 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
4577 qglStencilFunc(GL_NOTEQUAL, 128, 255);CHECKGLERROR
4579 // apply the blend to the shadowed areas
4580 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
4582 // restore the viewport
4583 R_SetViewport(&r_refdef.view.viewport);
4585 // restore other state to normal
4586 //R_Shadow_RenderMode_End();
4589 void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4592 vec3_t centerorigin;
4594 // if it's too close, skip it
4595 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
4597 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4600 if (usequery && r_numqueries + 2 <= r_maxqueries)
4602 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4603 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4604 // 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
4605 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4608 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use qglDepthFunc instead
4609 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
4610 qglDepthFunc(GL_ALWAYS);
4611 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4612 R_Mesh_VertexPointer(vertex3f, 0, 0);
4613 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
4614 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4615 qglDepthFunc(GL_LEQUAL);
4616 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
4617 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4618 R_Mesh_VertexPointer(vertex3f, 0, 0);
4619 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
4620 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4623 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4626 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
4628 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4631 GLint allpixels = 0, visiblepixels = 0;
4632 // now we have to check the query result
4633 if (rtlight->corona_queryindex_visiblepixels)
4636 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
4637 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
4639 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
4640 if (visiblepixels < 1 || allpixels < 1)
4642 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
4643 cscale *= rtlight->corona_visibility;
4647 // FIXME: these traces should scan all render entities instead of cl.world
4648 if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
4651 VectorScale(rtlight->currentcolor, cscale, color);
4652 if (VectorLength(color) > (1.0f / 256.0f))
4655 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
4658 VectorNegate(color, color);
4659 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
4661 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4662 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);
4663 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4665 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
4669 void R_Shadow_DrawCoronas(void)
4677 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4679 if (r_waterstate.renderingscene)
4681 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4682 R_EntityMatrix(&identitymatrix);
4684 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4686 // check occlusion of coronas
4687 // use GL_ARB_occlusion_query if available
4688 // otherwise use raytraces
4690 usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
4693 GL_ColorMask(0,0,0,0);
4694 if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
4695 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
4698 r_maxqueries = (range + r_refdef.scene.numlights) * 4;
4699 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
4701 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
4704 RSurf_ActiveWorldEntity();
4705 GL_BlendFunc(GL_ONE, GL_ZERO);
4706 GL_CullFace(GL_NONE);
4707 GL_DepthMask(false);
4708 GL_DepthRange(0, 1);
4709 GL_PolygonOffset(0, 0);
4711 R_Mesh_ColorPointer(NULL, 0, 0);
4712 R_Mesh_ResetTextureState();
4713 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
4715 for (lightindex = 0;lightindex < range;lightindex++)
4717 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4720 rtlight = &light->rtlight;
4721 rtlight->corona_visibility = 0;
4722 rtlight->corona_queryindex_visiblepixels = 0;
4723 rtlight->corona_queryindex_allpixels = 0;
4724 if (!(rtlight->flags & flag))
4726 if (rtlight->corona <= 0)
4728 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4730 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4732 for (i = 0;i < r_refdef.scene.numlights;i++)
4734 rtlight = r_refdef.scene.lights[i];
4735 rtlight->corona_visibility = 0;
4736 rtlight->corona_queryindex_visiblepixels = 0;
4737 rtlight->corona_queryindex_allpixels = 0;
4738 if (!(rtlight->flags & flag))
4740 if (rtlight->corona <= 0)
4742 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4745 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4747 // now draw the coronas using the query data for intensity info
4748 for (lightindex = 0;lightindex < range;lightindex++)
4750 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4753 rtlight = &light->rtlight;
4754 if (rtlight->corona_visibility <= 0)
4756 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4758 for (i = 0;i < r_refdef.scene.numlights;i++)
4760 rtlight = r_refdef.scene.lights[i];
4761 if (rtlight->corona_visibility <= 0)
4763 if (gl_flashblend.integer)
4764 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4766 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4772 dlight_t *R_Shadow_NewWorldLight(void)
4774 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4777 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)
4780 // validate parameters
4781 if (style < 0 || style >= MAX_LIGHTSTYLES)
4783 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
4789 // copy to light properties
4790 VectorCopy(origin, light->origin);
4791 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4792 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4793 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4795 light->color[0] = max(color[0], 0);
4796 light->color[1] = max(color[1], 0);
4797 light->color[2] = max(color[2], 0);
4799 light->color[0] = color[0];
4800 light->color[1] = color[1];
4801 light->color[2] = color[2];
4802 light->radius = max(radius, 0);
4803 light->style = style;
4804 light->shadow = shadowenable;
4805 light->corona = corona;
4806 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4807 light->coronasizescale = coronasizescale;
4808 light->ambientscale = ambientscale;
4809 light->diffusescale = diffusescale;
4810 light->specularscale = specularscale;
4811 light->flags = flags;
4813 // update renderable light data
4814 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4815 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);
4818 void R_Shadow_FreeWorldLight(dlight_t *light)
4820 if (r_shadow_selectedlight == light)
4821 r_shadow_selectedlight = NULL;
4822 R_RTLight_Uncompile(&light->rtlight);
4823 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4826 void R_Shadow_ClearWorldLights(void)
4830 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4831 for (lightindex = 0;lightindex < range;lightindex++)
4833 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4835 R_Shadow_FreeWorldLight(light);
4837 r_shadow_selectedlight = NULL;
4840 void R_Shadow_SelectLight(dlight_t *light)
4842 if (r_shadow_selectedlight)
4843 r_shadow_selectedlight->selected = false;
4844 r_shadow_selectedlight = light;
4845 if (r_shadow_selectedlight)
4846 r_shadow_selectedlight->selected = true;
4849 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4851 // this is never batched (there can be only one)
4853 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
4854 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4855 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4858 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4863 skinframe_t *skinframe;
4866 // this is never batched (due to the ent parameter changing every time)
4867 // so numsurfaces == 1 and surfacelist[0] == lightnumber
4868 const dlight_t *light = (dlight_t *)ent;
4871 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
4874 VectorScale(light->color, intensity, spritecolor);
4875 if (VectorLength(spritecolor) < 0.1732f)
4876 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
4877 if (VectorLength(spritecolor) > 1.0f)
4878 VectorNormalize(spritecolor);
4880 // draw light sprite
4881 if (light->cubemapname[0] && !light->shadow)
4882 skinframe = r_editlights_sprcubemapnoshadowlight;
4883 else if (light->cubemapname[0])
4884 skinframe = r_editlights_sprcubemaplight;
4885 else if (!light->shadow)
4886 skinframe = r_editlights_sprnoshadowlight;
4888 skinframe = r_editlights_sprlight;
4890 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);
4891 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4893 // draw selection sprite if light is selected
4894 if (light->selected)
4896 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4897 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4898 // VorteX todo: add normalmode/realtime mode light overlay sprites?
4902 void R_Shadow_DrawLightSprites(void)
4906 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4907 for (lightindex = 0;lightindex < range;lightindex++)
4909 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4911 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
4913 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
4916 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
4921 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
4922 if (lightindex >= range)
4924 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4927 rtlight = &light->rtlight;
4928 //if (!(rtlight->flags & flag))
4930 VectorCopy(rtlight->shadoworigin, origin);
4931 *radius = rtlight->radius;
4932 VectorCopy(rtlight->color, color);
4936 void R_Shadow_SelectLightInView(void)
4938 float bestrating, rating, temp[3];
4942 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4945 for (lightindex = 0;lightindex < range;lightindex++)
4947 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4950 VectorSubtract(light->origin, r_refdef.view.origin, temp);
4951 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
4954 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
4955 if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1.0f)
4957 bestrating = rating;
4962 R_Shadow_SelectLight(best);
4965 void R_Shadow_LoadWorldLights(void)
4967 int n, a, style, shadow, flags;
4968 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
4969 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
4970 if (cl.worldmodel == NULL)
4972 Con_Print("No map loaded.\n");
4975 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4976 strlcat (name, ".rtlights", sizeof (name));
4977 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4987 for (;COM_Parse(t, true) && strcmp(
4988 if (COM_Parse(t, true))
4990 if (com_token[0] == '!')
4993 origin[0] = atof(com_token+1);
4996 origin[0] = atof(com_token);
5001 while (*s && *s != '\n' && *s != '\r')
5007 // check for modifier flags
5014 #if _MSC_VER >= 1400
5015 #define sscanf sscanf_s
5017 cubemapname[sizeof(cubemapname)-1] = 0;
5018 #if MAX_QPATH != 128
5019 #error update this code if MAX_QPATH changes
5021 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
5022 #if _MSC_VER >= 1400
5023 , sizeof(cubemapname)
5025 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
5028 flags = LIGHTFLAG_REALTIMEMODE;
5036 coronasizescale = 0.25f;
5038 VectorClear(angles);
5041 if (a < 9 || !strcmp(cubemapname, "\"\""))
5043 // remove quotes on cubemapname
5044 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
5047 namelen = strlen(cubemapname) - 2;
5048 memmove(cubemapname, cubemapname + 1, namelen);
5049 cubemapname[namelen] = '\0';
5053 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);
5056 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5064 Con_Printf("invalid rtlights file \"%s\"\n", name);
5065 Mem_Free(lightsstring);
5069 void R_Shadow_SaveWorldLights(void)
5073 size_t bufchars, bufmaxchars;
5075 char name[MAX_QPATH];
5076 char line[MAX_INPUTLINE];
5077 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
5078 // I hate lines which are 3 times my screen size :( --blub
5081 if (cl.worldmodel == NULL)
5083 Con_Print("No map loaded.\n");
5086 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
5087 strlcat (name, ".rtlights", sizeof (name));
5088 bufchars = bufmaxchars = 0;
5090 for (lightindex = 0;lightindex < range;lightindex++)
5092 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5095 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
5096 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);
5097 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
5098 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]);
5100 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);
5101 if (bufchars + strlen(line) > bufmaxchars)
5103 bufmaxchars = bufchars + strlen(line) + 2048;
5105 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
5109 memcpy(buf, oldbuf, bufchars);
5115 memcpy(buf + bufchars, line, strlen(line));
5116 bufchars += strlen(line);
5120 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
5125 void R_Shadow_LoadLightsFile(void)
5128 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
5129 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
5130 if (cl.worldmodel == NULL)
5132 Con_Print("No map loaded.\n");
5135 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
5136 strlcat (name, ".lights", sizeof (name));
5137 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5145 while (*s && *s != '\n' && *s != '\r')
5151 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);
5155 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);
5158 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
5159 radius = bound(15, radius, 4096);
5160 VectorScale(color, (2.0f / (8388608.0f)), color);
5161 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5169 Con_Printf("invalid lights file \"%s\"\n", name);
5170 Mem_Free(lightsstring);
5174 // tyrlite/hmap2 light types in the delay field
5175 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
5177 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
5189 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
5190 char key[256], value[MAX_INPUTLINE];
5192 if (cl.worldmodel == NULL)
5194 Con_Print("No map loaded.\n");
5197 // try to load a .ent file first
5198 FS_StripExtension (cl.worldmodel->name, key, sizeof (key));
5199 strlcat (key, ".ent", sizeof (key));
5200 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
5201 // and if that is not found, fall back to the bsp file entity string
5203 data = cl.worldmodel->brush.entities;
5206 for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
5208 type = LIGHTTYPE_MINUSX;
5209 origin[0] = origin[1] = origin[2] = 0;
5210 originhack[0] = originhack[1] = originhack[2] = 0;
5211 angles[0] = angles[1] = angles[2] = 0;
5212 color[0] = color[1] = color[2] = 1;
5213 light[0] = light[1] = light[2] = 1;light[3] = 300;
5214 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
5224 if (!COM_ParseToken_Simple(&data, false, false))
5226 if (com_token[0] == '}')
5227 break; // end of entity
5228 if (com_token[0] == '_')
5229 strlcpy(key, com_token + 1, sizeof(key));
5231 strlcpy(key, com_token, sizeof(key));
5232 while (key[strlen(key)-1] == ' ') // remove trailing spaces
5233 key[strlen(key)-1] = 0;
5234 if (!COM_ParseToken_Simple(&data, false, false))
5236 strlcpy(value, com_token, sizeof(value));
5238 // now that we have the key pair worked out...
5239 if (!strcmp("light", key))
5241 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5245 light[0] = vec[0] * (1.0f / 256.0f);
5246 light[1] = vec[0] * (1.0f / 256.0f);
5247 light[2] = vec[0] * (1.0f / 256.0f);
5253 light[0] = vec[0] * (1.0f / 255.0f);
5254 light[1] = vec[1] * (1.0f / 255.0f);
5255 light[2] = vec[2] * (1.0f / 255.0f);
5259 else if (!strcmp("delay", key))
5261 else if (!strcmp("origin", key))
5262 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5263 else if (!strcmp("angle", key))
5264 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5265 else if (!strcmp("angles", key))
5266 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5267 else if (!strcmp("color", key))
5268 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5269 else if (!strcmp("wait", key))
5270 fadescale = atof(value);
5271 else if (!strcmp("classname", key))
5273 if (!strncmp(value, "light", 5))
5276 if (!strcmp(value, "light_fluoro"))
5281 overridecolor[0] = 1;
5282 overridecolor[1] = 1;
5283 overridecolor[2] = 1;
5285 if (!strcmp(value, "light_fluorospark"))
5290 overridecolor[0] = 1;
5291 overridecolor[1] = 1;
5292 overridecolor[2] = 1;
5294 if (!strcmp(value, "light_globe"))
5299 overridecolor[0] = 1;
5300 overridecolor[1] = 0.8;
5301 overridecolor[2] = 0.4;
5303 if (!strcmp(value, "light_flame_large_yellow"))
5308 overridecolor[0] = 1;
5309 overridecolor[1] = 0.5;
5310 overridecolor[2] = 0.1;
5312 if (!strcmp(value, "light_flame_small_yellow"))
5317 overridecolor[0] = 1;
5318 overridecolor[1] = 0.5;
5319 overridecolor[2] = 0.1;
5321 if (!strcmp(value, "light_torch_small_white"))
5326 overridecolor[0] = 1;
5327 overridecolor[1] = 0.5;
5328 overridecolor[2] = 0.1;
5330 if (!strcmp(value, "light_torch_small_walltorch"))
5335 overridecolor[0] = 1;
5336 overridecolor[1] = 0.5;
5337 overridecolor[2] = 0.1;
5341 else if (!strcmp("style", key))
5342 style = atoi(value);
5343 else if (!strcmp("skin", key))
5344 skin = (int)atof(value);
5345 else if (!strcmp("pflags", key))
5346 pflags = (int)atof(value);
5347 //else if (!strcmp("effects", key))
5348 // effects = (int)atof(value);
5349 else if (cl.worldmodel->type == mod_brushq3)
5351 if (!strcmp("scale", key))
5352 lightscale = atof(value);
5353 if (!strcmp("fade", key))
5354 fadescale = atof(value);
5359 if (lightscale <= 0)
5363 if (color[0] == color[1] && color[0] == color[2])
5365 color[0] *= overridecolor[0];
5366 color[1] *= overridecolor[1];
5367 color[2] *= overridecolor[2];
5369 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5370 color[0] = color[0] * light[0];
5371 color[1] = color[1] * light[1];
5372 color[2] = color[2] * light[2];
5375 case LIGHTTYPE_MINUSX:
5377 case LIGHTTYPE_RECIPX:
5379 VectorScale(color, (1.0f / 16.0f), color);
5381 case LIGHTTYPE_RECIPXX:
5383 VectorScale(color, (1.0f / 16.0f), color);
5386 case LIGHTTYPE_NONE:
5390 case LIGHTTYPE_MINUSXX:
5393 VectorAdd(origin, originhack, origin);
5395 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);
5398 Mem_Free(entfiledata);
5402 void R_Shadow_SetCursorLocationForView(void)
5405 vec3_t dest, endpos;
5407 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5408 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
5409 if (trace.fraction < 1)
5411 dist = trace.fraction * r_editlights_cursordistance.value;
5412 push = r_editlights_cursorpushback.value;
5416 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5417 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5421 VectorClear( endpos );
5423 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5424 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5425 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5428 void R_Shadow_UpdateWorldLightSelection(void)
5430 if (r_editlights.integer)
5432 R_Shadow_SetCursorLocationForView();
5433 R_Shadow_SelectLightInView();
5436 R_Shadow_SelectLight(NULL);
5439 void R_Shadow_EditLights_Clear_f(void)
5441 R_Shadow_ClearWorldLights();
5444 void R_Shadow_EditLights_Reload_f(void)
5448 strlcpy(r_shadow_mapname, cl.worldmodel->name, sizeof(r_shadow_mapname));
5449 R_Shadow_ClearWorldLights();
5450 R_Shadow_LoadWorldLights();
5451 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5453 R_Shadow_LoadLightsFile();
5454 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5455 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5459 void R_Shadow_EditLights_Save_f(void)
5463 R_Shadow_SaveWorldLights();
5466 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
5468 R_Shadow_ClearWorldLights();
5469 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5472 void R_Shadow_EditLights_ImportLightsFile_f(void)
5474 R_Shadow_ClearWorldLights();
5475 R_Shadow_LoadLightsFile();
5478 void R_Shadow_EditLights_Spawn_f(void)
5481 if (!r_editlights.integer)
5483 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5486 if (Cmd_Argc() != 1)
5488 Con_Print("r_editlights_spawn does not take parameters\n");
5491 color[0] = color[1] = color[2] = 1;
5492 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5495 void R_Shadow_EditLights_Edit_f(void)
5497 vec3_t origin, angles, color;
5498 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5499 int style, shadows, flags, normalmode, realtimemode;
5500 char cubemapname[MAX_INPUTLINE];
5501 if (!r_editlights.integer)
5503 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5506 if (!r_shadow_selectedlight)
5508 Con_Print("No selected light.\n");
5511 VectorCopy(r_shadow_selectedlight->origin, origin);
5512 VectorCopy(r_shadow_selectedlight->angles, angles);
5513 VectorCopy(r_shadow_selectedlight->color, color);
5514 radius = r_shadow_selectedlight->radius;
5515 style = r_shadow_selectedlight->style;
5516 if (r_shadow_selectedlight->cubemapname)
5517 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5520 shadows = r_shadow_selectedlight->shadow;
5521 corona = r_shadow_selectedlight->corona;
5522 coronasizescale = r_shadow_selectedlight->coronasizescale;
5523 ambientscale = r_shadow_selectedlight->ambientscale;
5524 diffusescale = r_shadow_selectedlight->diffusescale;
5525 specularscale = r_shadow_selectedlight->specularscale;
5526 flags = r_shadow_selectedlight->flags;
5527 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5528 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5529 if (!strcmp(Cmd_Argv(1), "origin"))
5531 if (Cmd_Argc() != 5)
5533 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5536 origin[0] = atof(Cmd_Argv(2));
5537 origin[1] = atof(Cmd_Argv(3));
5538 origin[2] = atof(Cmd_Argv(4));
5540 else if (!strcmp(Cmd_Argv(1), "originx"))
5542 if (Cmd_Argc() != 3)
5544 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5547 origin[0] = atof(Cmd_Argv(2));
5549 else if (!strcmp(Cmd_Argv(1), "originy"))
5551 if (Cmd_Argc() != 3)
5553 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5556 origin[1] = atof(Cmd_Argv(2));
5558 else if (!strcmp(Cmd_Argv(1), "originz"))
5560 if (Cmd_Argc() != 3)
5562 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5565 origin[2] = atof(Cmd_Argv(2));
5567 else if (!strcmp(Cmd_Argv(1), "move"))
5569 if (Cmd_Argc() != 5)
5571 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5574 origin[0] += atof(Cmd_Argv(2));
5575 origin[1] += atof(Cmd_Argv(3));
5576 origin[2] += atof(Cmd_Argv(4));
5578 else if (!strcmp(Cmd_Argv(1), "movex"))
5580 if (Cmd_Argc() != 3)
5582 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5585 origin[0] += atof(Cmd_Argv(2));
5587 else if (!strcmp(Cmd_Argv(1), "movey"))
5589 if (Cmd_Argc() != 3)
5591 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5594 origin[1] += atof(Cmd_Argv(2));
5596 else if (!strcmp(Cmd_Argv(1), "movez"))
5598 if (Cmd_Argc() != 3)
5600 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5603 origin[2] += atof(Cmd_Argv(2));
5605 else if (!strcmp(Cmd_Argv(1), "angles"))
5607 if (Cmd_Argc() != 5)
5609 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5612 angles[0] = atof(Cmd_Argv(2));
5613 angles[1] = atof(Cmd_Argv(3));
5614 angles[2] = atof(Cmd_Argv(4));
5616 else if (!strcmp(Cmd_Argv(1), "anglesx"))
5618 if (Cmd_Argc() != 3)
5620 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5623 angles[0] = atof(Cmd_Argv(2));
5625 else if (!strcmp(Cmd_Argv(1), "anglesy"))
5627 if (Cmd_Argc() != 3)
5629 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5632 angles[1] = atof(Cmd_Argv(2));
5634 else if (!strcmp(Cmd_Argv(1), "anglesz"))
5636 if (Cmd_Argc() != 3)
5638 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5641 angles[2] = atof(Cmd_Argv(2));
5643 else if (!strcmp(Cmd_Argv(1), "color"))
5645 if (Cmd_Argc() != 5)
5647 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
5650 color[0] = atof(Cmd_Argv(2));
5651 color[1] = atof(Cmd_Argv(3));
5652 color[2] = atof(Cmd_Argv(4));
5654 else if (!strcmp(Cmd_Argv(1), "radius"))
5656 if (Cmd_Argc() != 3)
5658 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5661 radius = atof(Cmd_Argv(2));
5663 else if (!strcmp(Cmd_Argv(1), "colorscale"))
5665 if (Cmd_Argc() == 3)
5667 double scale = atof(Cmd_Argv(2));
5674 if (Cmd_Argc() != 5)
5676 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
5679 color[0] *= atof(Cmd_Argv(2));
5680 color[1] *= atof(Cmd_Argv(3));
5681 color[2] *= atof(Cmd_Argv(4));
5684 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
5686 if (Cmd_Argc() != 3)
5688 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5691 radius *= atof(Cmd_Argv(2));
5693 else if (!strcmp(Cmd_Argv(1), "style"))
5695 if (Cmd_Argc() != 3)
5697 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5700 style = atoi(Cmd_Argv(2));
5702 else if (!strcmp(Cmd_Argv(1), "cubemap"))
5706 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5709 if (Cmd_Argc() == 3)
5710 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
5714 else if (!strcmp(Cmd_Argv(1), "shadows"))
5716 if (Cmd_Argc() != 3)
5718 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5721 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5723 else if (!strcmp(Cmd_Argv(1), "corona"))
5725 if (Cmd_Argc() != 3)
5727 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5730 corona = atof(Cmd_Argv(2));
5732 else if (!strcmp(Cmd_Argv(1), "coronasize"))
5734 if (Cmd_Argc() != 3)
5736 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5739 coronasizescale = atof(Cmd_Argv(2));
5741 else if (!strcmp(Cmd_Argv(1), "ambient"))
5743 if (Cmd_Argc() != 3)
5745 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5748 ambientscale = atof(Cmd_Argv(2));
5750 else if (!strcmp(Cmd_Argv(1), "diffuse"))
5752 if (Cmd_Argc() != 3)
5754 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5757 diffusescale = atof(Cmd_Argv(2));
5759 else if (!strcmp(Cmd_Argv(1), "specular"))
5761 if (Cmd_Argc() != 3)
5763 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5766 specularscale = atof(Cmd_Argv(2));
5768 else if (!strcmp(Cmd_Argv(1), "normalmode"))
5770 if (Cmd_Argc() != 3)
5772 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5775 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5777 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
5779 if (Cmd_Argc() != 3)
5781 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5784 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5788 Con_Print("usage: r_editlights_edit [property] [value]\n");
5789 Con_Print("Selected light's properties:\n");
5790 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5791 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5792 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5793 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
5794 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
5795 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
5796 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5797 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
5798 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
5799 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
5800 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
5801 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
5802 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5803 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5806 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5807 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5810 void R_Shadow_EditLights_EditAll_f(void)
5816 if (!r_editlights.integer)
5818 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5822 // EditLights doesn't seem to have a "remove" command or something so:
5823 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5824 for (lightindex = 0;lightindex < range;lightindex++)
5826 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5829 R_Shadow_SelectLight(light);
5830 R_Shadow_EditLights_Edit_f();
5834 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
5836 int lightnumber, lightcount;
5837 size_t lightindex, range;
5841 if (!r_editlights.integer)
5843 x = vid_conwidth.value - 240;
5845 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
5848 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5849 for (lightindex = 0;lightindex < range;lightindex++)
5851 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5854 if (light == r_shadow_selectedlight)
5855 lightnumber = lightindex;
5858 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;
5859 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;
5861 if (r_shadow_selectedlight == NULL)
5863 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;
5864 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;
5865 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;
5866 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;
5867 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;
5868 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;
5869 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;
5870 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;
5871 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;
5872 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;
5873 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;
5874 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;
5875 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;
5876 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;
5877 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;
5880 void R_Shadow_EditLights_ToggleShadow_f(void)
5882 if (!r_editlights.integer)
5884 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5887 if (!r_shadow_selectedlight)
5889 Con_Print("No selected light.\n");
5892 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);
5895 void R_Shadow_EditLights_ToggleCorona_f(void)
5897 if (!r_editlights.integer)
5899 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5902 if (!r_shadow_selectedlight)
5904 Con_Print("No selected light.\n");
5907 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);
5910 void R_Shadow_EditLights_Remove_f(void)
5912 if (!r_editlights.integer)
5914 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
5917 if (!r_shadow_selectedlight)
5919 Con_Print("No selected light.\n");
5922 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
5923 r_shadow_selectedlight = NULL;
5926 void R_Shadow_EditLights_Help_f(void)
5929 "Documentation on r_editlights system:\n"
5931 "r_editlights : enable/disable editing mode\n"
5932 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
5933 "r_editlights_cursorpushback : push back cursor this far from surface\n"
5934 "r_editlights_cursorpushoff : push cursor off surface this far\n"
5935 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
5936 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
5938 "r_editlights_help : this help\n"
5939 "r_editlights_clear : remove all lights\n"
5940 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
5941 "r_editlights_save : save to .rtlights file\n"
5942 "r_editlights_spawn : create a light with default settings\n"
5943 "r_editlights_edit command : edit selected light - more documentation below\n"
5944 "r_editlights_remove : remove selected light\n"
5945 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
5946 "r_editlights_importlightentitiesfrommap : reload light entities\n"
5947 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
5949 "origin x y z : set light location\n"
5950 "originx x: set x component of light location\n"
5951 "originy y: set y component of light location\n"
5952 "originz z: set z component of light location\n"
5953 "move x y z : adjust light location\n"
5954 "movex x: adjust x component of light location\n"
5955 "movey y: adjust y component of light location\n"
5956 "movez z: adjust z component of light location\n"
5957 "angles x y z : set light angles\n"
5958 "anglesx x: set x component of light angles\n"
5959 "anglesy y: set y component of light angles\n"
5960 "anglesz z: set z component of light angles\n"
5961 "color r g b : set color of light (can be brighter than 1 1 1)\n"
5962 "radius radius : set radius (size) of light\n"
5963 "colorscale grey : multiply color of light (1 does nothing)\n"
5964 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
5965 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
5966 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
5967 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
5968 "cubemap basename : set filter cubemap of light (not yet supported)\n"
5969 "shadows 1/0 : turn on/off shadows\n"
5970 "corona n : set corona intensity\n"
5971 "coronasize n : set corona size (0-1)\n"
5972 "ambient n : set ambient intensity (0-1)\n"
5973 "diffuse n : set diffuse intensity (0-1)\n"
5974 "specular n : set specular intensity (0-1)\n"
5975 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
5976 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
5977 "<nothing> : print light properties to console\n"
5981 void R_Shadow_EditLights_CopyInfo_f(void)
5983 if (!r_editlights.integer)
5985 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
5988 if (!r_shadow_selectedlight)
5990 Con_Print("No selected light.\n");
5993 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
5994 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
5995 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
5996 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
5997 if (r_shadow_selectedlight->cubemapname)
5998 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
6000 r_shadow_bufferlight.cubemapname[0] = 0;
6001 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
6002 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
6003 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
6004 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
6005 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
6006 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
6007 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
6010 void R_Shadow_EditLights_PasteInfo_f(void)
6012 if (!r_editlights.integer)
6014 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
6017 if (!r_shadow_selectedlight)
6019 Con_Print("No selected light.\n");
6022 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);
6025 void R_Shadow_EditLights_Init(void)
6027 Cvar_RegisterVariable(&r_editlights);
6028 Cvar_RegisterVariable(&r_editlights_cursordistance);
6029 Cvar_RegisterVariable(&r_editlights_cursorpushback);
6030 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
6031 Cvar_RegisterVariable(&r_editlights_cursorgrid);
6032 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
6033 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
6034 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
6035 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)");
6036 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
6037 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
6038 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
6039 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)");
6040 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
6041 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
6042 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
6043 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
6044 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
6045 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
6046 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)");
6052 =============================================================================
6056 =============================================================================
6059 void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, int dynamic)
6061 VectorClear(diffusecolor);
6062 VectorClear(diffusenormal);
6064 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
6066 ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_refdef.scene.ambient;
6067 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
6070 VectorSet(ambientcolor, 1, 1, 1);
6077 for (i = 0;i < r_refdef.scene.numlights;i++)
6079 light = r_refdef.scene.lights[i];
6080 Matrix4x4_Transform(&light->matrix_worldtolight, p, v);
6081 f = 1 - VectorLength2(v);
6082 if (f > 0 && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
6083 VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);