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];
3490 rtlight->draw = false;
3492 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3493 // skip lights that are basically invisible (color 0 0 0)
3494 nolight = 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 && !nolight && (!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 // skip processing on corona-only lights
3529 // if the light box is offscreen, skip it
3530 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3533 VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
3534 VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
3536 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3538 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3540 // compiled light, world available and can receive realtime lighting
3541 // retrieve leaf information
3542 numleafs = rtlight->static_numleafs;
3543 leaflist = rtlight->static_leaflist;
3544 leafpvs = rtlight->static_leafpvs;
3545 numsurfaces = rtlight->static_numsurfaces;
3546 surfacelist = rtlight->static_surfacelist;
3547 //surfacesides = NULL;
3548 shadowtrispvs = rtlight->static_shadowtrispvs;
3549 lighttrispvs = rtlight->static_lighttrispvs;
3551 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3553 // dynamic light, world available and can receive realtime lighting
3554 // calculate lit surfaces and leafs
3555 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);
3556 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3557 leaflist = r_shadow_buffer_leaflist;
3558 leafpvs = r_shadow_buffer_leafpvs;
3559 surfacelist = r_shadow_buffer_surfacelist;
3560 //surfacesides = r_shadow_buffer_surfacesides;
3561 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3562 lighttrispvs = r_shadow_buffer_lighttrispvs;
3563 // if the reduced leaf bounds are offscreen, skip it
3564 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3575 //surfacesides = NULL;
3576 shadowtrispvs = NULL;
3577 lighttrispvs = NULL;
3579 // check if light is illuminating any visible leafs
3582 for (i = 0;i < numleafs;i++)
3583 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3589 // make a list of lit entities and shadow casting entities
3590 numlightentities = 0;
3591 numlightentities_noselfshadow = 0;
3592 numshadowentities = 0;
3593 numshadowentities_noselfshadow = 0;
3595 // add dynamic entities that are lit by the light
3596 for (i = 0;i < r_refdef.scene.numentities;i++)
3599 entity_render_t *ent = r_refdef.scene.entities[i];
3601 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3603 // skip the object entirely if it is not within the valid
3604 // shadow-casting region (which includes the lit region)
3605 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
3607 if (!(model = ent->model))
3609 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
3611 // this entity wants to receive light, is visible, and is
3612 // inside the light box
3613 // TODO: check if the surfaces in the model can receive light
3614 // so now check if it's in a leaf seen by the light
3615 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))
3617 if (ent->flags & RENDER_NOSELFSHADOW)
3618 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
3620 lightentities[numlightentities++] = ent;
3621 // since it is lit, it probably also casts a shadow...
3622 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3623 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3624 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3626 // note: exterior models without the RENDER_NOSELFSHADOW
3627 // flag still create a RENDER_NOSELFSHADOW shadow but
3628 // are lit normally, this means that they are
3629 // self-shadowing but do not shadow other
3630 // RENDER_NOSELFSHADOW entities such as the gun
3631 // (very weird, but keeps the player shadow off the gun)
3632 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3633 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3635 shadowentities[numshadowentities++] = ent;
3638 else if (ent->flags & RENDER_SHADOW)
3640 // this entity is not receiving light, but may still need to
3642 // TODO: check if the surfaces in the model can cast shadow
3643 // now check if it is in a leaf seen by the light
3644 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))
3646 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3647 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3648 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3650 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3651 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3653 shadowentities[numshadowentities++] = ent;
3658 // return if there's nothing at all to light
3659 if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
3662 // count this light in the r_speeds
3663 r_refdef.stats.lights++;
3665 // flag it as worth drawing later
3666 rtlight->draw = true;
3668 // cache all the animated entities that cast a shadow but are not visible
3669 for (i = 0;i < numshadowentities;i++)
3670 if (!shadowentities[i]->animcache_vertex3f)
3671 R_AnimCache_GetEntity(shadowentities[i], false, false);
3672 for (i = 0;i < numshadowentities_noselfshadow;i++)
3673 if (!shadowentities_noselfshadow[i]->animcache_vertex3f)
3674 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
3676 // allocate some temporary memory for rendering this light later in the frame
3677 // reusable buffers need to be copied, static data can be used as-is
3678 rtlight->cached_numlightentities = numlightentities;
3679 rtlight->cached_numlightentities_noselfshadow = numlightentities_noselfshadow;
3680 rtlight->cached_numshadowentities = numshadowentities;
3681 rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
3682 rtlight->cached_numsurfaces = numsurfaces;
3683 rtlight->cached_lightentities = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
3684 rtlight->cached_lightentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
3685 rtlight->cached_shadowentities = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
3686 rtlight->cached_shadowentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
3687 if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
3689 int numshadowtrispvsbytes = (((r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles) + 7) >> 3);
3690 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
3691 rtlight->cached_shadowtrispvs = (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
3692 rtlight->cached_lighttrispvs = (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
3693 rtlight->cached_surfacelist = (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
3697 // compiled light data
3698 rtlight->cached_shadowtrispvs = shadowtrispvs;
3699 rtlight->cached_lighttrispvs = lighttrispvs;
3700 rtlight->cached_surfacelist = surfacelist;
3704 void R_Shadow_DrawLight(rtlight_t *rtlight)
3708 unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
3709 int numlightentities;
3710 int numlightentities_noselfshadow;
3711 int numshadowentities;
3712 int numshadowentities_noselfshadow;
3713 entity_render_t **lightentities;
3714 entity_render_t **lightentities_noselfshadow;
3715 entity_render_t **shadowentities;
3716 entity_render_t **shadowentities_noselfshadow;
3718 static unsigned char entitysides[MAX_EDICTS];
3719 static unsigned char entitysides_noselfshadow[MAX_EDICTS];
3720 vec3_t nearestpoint;
3722 qboolean castshadows;
3725 // check if we cached this light this frame (meaning it is worth drawing)
3729 // if R_FrameData_Store ran out of space we skip anything dependent on it
3730 if (r_framedata_failed)
3733 numlightentities = rtlight->cached_numlightentities;
3734 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
3735 numshadowentities = rtlight->cached_numshadowentities;
3736 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
3737 numsurfaces = rtlight->cached_numsurfaces;
3738 lightentities = rtlight->cached_lightentities;
3739 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
3740 shadowentities = rtlight->cached_shadowentities;
3741 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
3742 shadowtrispvs = rtlight->cached_shadowtrispvs;
3743 lighttrispvs = rtlight->cached_lighttrispvs;
3744 surfacelist = rtlight->cached_surfacelist;
3746 // set up a scissor rectangle for this light
3747 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3750 // don't let sound skip if going slow
3751 if (r_refdef.scene.extraupdate)
3754 // make this the active rtlight for rendering purposes
3755 R_Shadow_RenderMode_ActiveLight(rtlight);
3757 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
3759 // optionally draw visible shape of the shadow volumes
3760 // for performance analysis by level designers
3761 R_Shadow_RenderMode_VisibleShadowVolumes();
3763 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
3764 for (i = 0;i < numshadowentities;i++)
3765 R_Shadow_DrawEntityShadow(shadowentities[i]);
3766 for (i = 0;i < numshadowentities_noselfshadow;i++)
3767 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3768 R_Shadow_RenderMode_VisibleLighting(false, false);
3771 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
3773 // optionally draw the illuminated areas
3774 // for performance analysis by level designers
3775 R_Shadow_RenderMode_VisibleLighting(false, false);
3777 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3778 for (i = 0;i < numlightentities;i++)
3779 R_Shadow_DrawEntityLight(lightentities[i]);
3780 for (i = 0;i < numlightentities_noselfshadow;i++)
3781 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3784 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
3786 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
3787 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
3788 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
3789 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
3791 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance/rtlight->radius));
3792 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
3793 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
3795 if (castshadows && (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE))
3801 int receivermask = 0;
3802 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
3803 Matrix4x4_Abs(&radiustolight);
3805 r_shadow_shadowmaplod = 0;
3806 for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
3807 if ((r_shadow_shadowmapmaxsize >> i) > lodlinear)
3808 r_shadow_shadowmaplod = i;
3810 if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
3811 size = max(1, r_shadow_shadowmapmaxsize >> r_shadow_shadowmaplod);
3813 size = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
3815 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
3817 surfacesides = NULL;
3820 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3822 castermask = rtlight->static_shadowmap_casters;
3823 receivermask = rtlight->static_shadowmap_receivers;
3827 surfacesides = r_shadow_buffer_surfacesides;
3828 for(i = 0;i < numsurfaces;i++)
3830 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
3831 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3832 castermask |= surfacesides[i];
3833 receivermask |= surfacesides[i];
3837 if (receivermask < 0x3F)
3839 for (i = 0;i < numlightentities;i++)
3840 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3841 if (receivermask < 0x3F)
3842 for(i = 0; i < numlightentities_noselfshadow;i++)
3843 receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3846 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
3850 for (i = 0;i < numshadowentities;i++)
3851 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3852 for (i = 0;i < numshadowentities_noselfshadow;i++)
3853 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3856 //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
3858 // render shadow casters into 6 sided depth texture
3859 for (side = 0;side < 6;side++) if (receivermask & (1 << side))
3861 R_Shadow_RenderMode_ShadowMap(side, receivermask, size);
3862 if (! (castermask & (1 << side))) continue;
3864 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
3865 for (i = 0;i < numshadowentities;i++) if (entitysides[i] & (1 << side))
3866 R_Shadow_DrawEntityShadow(shadowentities[i]);
3869 if (numlightentities_noselfshadow)
3871 // render lighting using the depth texture as shadowmap
3872 // draw lighting in the unmasked areas
3873 R_Shadow_RenderMode_Lighting(false, false, true);
3874 for (i = 0;i < numlightentities_noselfshadow;i++)
3875 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3878 // render shadow casters into 6 sided depth texture
3879 if (numshadowentities_noselfshadow)
3881 for (side = 0;side < 6;side++) if ((receivermask & castermask) & (1 << side))
3883 R_Shadow_RenderMode_ShadowMap(side, 0, size);
3884 for (i = 0;i < numshadowentities_noselfshadow;i++) if (entitysides_noselfshadow[i] & (1 << side))
3885 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3889 // render lighting using the depth texture as shadowmap
3890 // draw lighting in the unmasked areas
3891 R_Shadow_RenderMode_Lighting(false, false, true);
3892 // draw lighting in the unmasked areas
3894 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3895 for (i = 0;i < numlightentities;i++)
3896 R_Shadow_DrawEntityLight(lightentities[i]);
3898 else if (castshadows && vid.stencil)
3900 // draw stencil shadow volumes to mask off pixels that are in shadow
3901 // so that they won't receive lighting
3902 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
3903 R_Shadow_ClearStencil();
3906 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
3907 for (i = 0;i < numshadowentities;i++)
3908 R_Shadow_DrawEntityShadow(shadowentities[i]);
3910 // draw lighting in the unmasked areas
3911 R_Shadow_RenderMode_Lighting(true, false, false);
3912 for (i = 0;i < numlightentities_noselfshadow;i++)
3913 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3915 for (i = 0;i < numshadowentities_noselfshadow;i++)
3916 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3918 // draw lighting in the unmasked areas
3919 R_Shadow_RenderMode_Lighting(true, false, false);
3921 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3922 for (i = 0;i < numlightentities;i++)
3923 R_Shadow_DrawEntityLight(lightentities[i]);
3927 // draw lighting in the unmasked areas
3928 R_Shadow_RenderMode_Lighting(false, false, false);
3930 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3931 for (i = 0;i < numlightentities;i++)
3932 R_Shadow_DrawEntityLight(lightentities[i]);
3933 for (i = 0;i < numlightentities_noselfshadow;i++)
3934 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3937 if (r_shadow_usingdeferredprepass)
3939 // when rendering deferred lighting, we simply rasterize the box
3940 if (castshadows && (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE))
3941 R_Shadow_RenderMode_DrawDeferredLight(false, true);
3942 else if (castshadows && vid.stencil)
3943 R_Shadow_RenderMode_DrawDeferredLight(true, false);
3945 R_Shadow_RenderMode_DrawDeferredLight(false, false);
3949 static void R_Shadow_FreeDeferred(void)
3951 if (r_shadow_prepassgeometryfbo)
3952 qglDeleteFramebuffersEXT(1, &r_shadow_prepassgeometryfbo);CHECKGLERROR
3953 r_shadow_prepassgeometryfbo = 0;
3955 if (r_shadow_prepasslightingfbo)
3956 qglDeleteFramebuffersEXT(1, &r_shadow_prepasslightingfbo);CHECKGLERROR
3957 r_shadow_prepasslightingfbo = 0;
3959 if (r_shadow_prepassgeometrydepthtexture)
3960 R_FreeTexture(r_shadow_prepassgeometrydepthtexture);
3961 r_shadow_prepassgeometrydepthtexture = NULL;
3963 if (r_shadow_prepassgeometrynormalmaptexture)
3964 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
3965 r_shadow_prepassgeometrynormalmaptexture = NULL;
3967 if (r_shadow_prepasslightingdiffusetexture)
3968 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
3969 r_shadow_prepasslightingdiffusetexture = NULL;
3971 if (r_shadow_prepasslightingspeculartexture)
3972 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
3973 r_shadow_prepasslightingspeculartexture = NULL;
3976 void R_Shadow_DrawPrepass(void)
3984 entity_render_t *ent;
3986 GL_AlphaTest(false);
3987 R_Mesh_ColorPointer(NULL, 0, 0);
3988 R_Mesh_ResetTextureState();
3990 GL_ColorMask(1,1,1,1);
3991 GL_BlendFunc(GL_ONE, GL_ZERO);
3994 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepassgeometryfbo);CHECKGLERROR
3995 qglClearColor(0.5f,0.5f,0.5f,1.0f);CHECKGLERROR
3996 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);CHECKGLERROR
3998 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
3999 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
4000 if (r_timereport_active)
4001 R_TimeReport("prepassworld");
4003 for (i = 0;i < r_refdef.scene.numentities;i++)
4005 if (!r_refdef.viewcache.entityvisible[i])
4007 ent = r_refdef.scene.entities[i];
4008 if (ent->model && ent->model->DrawPrepass != NULL)
4009 ent->model->DrawPrepass(ent);
4012 if (r_timereport_active)
4013 R_TimeReport("prepassmodels");
4015 GL_DepthMask(false);
4016 GL_ColorMask(1,1,1,1);
4019 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepasslightingfbo);CHECKGLERROR
4020 qglClearColor(0.0f,0.0f,0.0f,0.0f);CHECKGLERROR
4021 GL_Clear(GL_COLOR_BUFFER_BIT);CHECKGLERROR
4022 if (r_refdef.fogenabled)
4023 qglClearColor(r_refdef.fogcolor[0],r_refdef.fogcolor[1],r_refdef.fogcolor[2],0);CHECKGLERROR
4025 R_Shadow_RenderMode_Begin();
4027 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4028 if (r_shadow_debuglight.integer >= 0)
4030 lightindex = r_shadow_debuglight.integer;
4031 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4032 if (light && (light->flags & flag))
4033 R_Shadow_DrawLight(&light->rtlight);
4037 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4038 for (lightindex = 0;lightindex < range;lightindex++)
4040 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4041 if (light && (light->flags & flag))
4042 R_Shadow_DrawLight(&light->rtlight);
4045 if (r_refdef.scene.rtdlight)
4046 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4047 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4049 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);CHECKGLERROR
4050 if (r_refdef.fogenabled)
4051 qglClearColor(r_refdef.fogcolor[0],r_refdef.fogcolor[1],r_refdef.fogcolor[2],0);CHECKGLERROR
4053 R_Shadow_RenderMode_End();
4055 if (r_timereport_active)
4056 R_TimeReport("prepasslights");
4059 void R_Shadow_DrawLightSprites(void);
4060 void R_Shadow_PrepareLights(void)
4070 if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4) ||
4071 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
4072 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0) ||
4073 r_shadow_shadowmaptexturetype != r_shadow_shadowmapping_texturetype.integer ||
4074 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
4075 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
4076 r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
4077 R_Shadow_FreeShadowMaps();
4079 r_shadow_usingshadowmaportho = false;
4081 switch (vid.renderpath)
4083 case RENDERPATH_GL20:
4084 case RENDERPATH_CGGL:
4085 if (!r_shadow_deferred.integer || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_STENCIL || !vid.support.ext_framebuffer_object || vid.maxdrawbuffers < 2)
4087 r_shadow_usingdeferredprepass = false;
4088 if (r_shadow_prepass_width)
4089 R_Shadow_FreeDeferred();
4090 r_shadow_prepass_width = r_shadow_prepass_height = 0;
4094 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
4096 R_Shadow_FreeDeferred();
4098 r_shadow_usingdeferredprepass = true;
4099 r_shadow_prepass_width = vid.width;
4100 r_shadow_prepass_height = vid.height;
4101 r_shadow_prepassgeometrydepthtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "prepassgeometrydepthmap", vid.width, vid.height, 24, false);
4102 r_shadow_prepassgeometrynormalmaptexture = R_LoadTexture2D(r_shadow_texturepool, "prepassgeometrynormalmap", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, NULL);
4103 r_shadow_prepasslightingdiffusetexture = R_LoadTexture2D(r_shadow_texturepool, "prepasslightingdiffuse", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, NULL);
4104 r_shadow_prepasslightingspeculartexture = R_LoadTexture2D(r_shadow_texturepool, "prepasslightingspecular", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, NULL);
4106 // set up the geometry pass fbo (depth + normalmap)
4107 qglGenFramebuffersEXT(1, &r_shadow_prepassgeometryfbo);CHECKGLERROR
4108 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepassgeometryfbo);CHECKGLERROR
4109 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_prepassgeometrydepthtexture), 0);CHECKGLERROR
4110 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_prepassgeometrynormalmaptexture), 0);CHECKGLERROR
4111 // render depth into one texture and normalmap into the other
4112 if (qglDrawBuffersARB)
4114 qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);CHECKGLERROR
4115 qglReadBuffer(GL_NONE);CHECKGLERROR
4117 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4118 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4120 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4121 Cvar_SetValueQuick(&r_shadow_deferred, 0);
4122 r_shadow_usingdeferredprepass = false;
4125 // set up the lighting pass fbo (diffuse + specular)
4126 qglGenFramebuffersEXT(1, &r_shadow_prepasslightingfbo);CHECKGLERROR
4127 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepasslightingfbo);CHECKGLERROR
4128 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_prepassgeometrydepthtexture), 0);CHECKGLERROR
4129 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_prepasslightingdiffusetexture), 0);CHECKGLERROR
4130 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_prepasslightingspeculartexture), 0);CHECKGLERROR
4131 // render diffuse into one texture and specular into another,
4132 // with depth and normalmap bound as textures,
4133 // with depth bound as attachment as well
4134 if (qglDrawBuffersARB)
4136 qglDrawBuffersARB(2, r_shadow_prepasslightingdrawbuffers);CHECKGLERROR
4137 qglReadBuffer(GL_NONE);CHECKGLERROR
4139 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4140 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4142 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4143 Cvar_SetValueQuick(&r_shadow_deferred, 0);
4144 r_shadow_usingdeferredprepass = false;
4148 case RENDERPATH_GL13:
4149 case RENDERPATH_GL11:
4150 r_shadow_usingdeferredprepass = false;
4154 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);
4156 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4157 if (r_shadow_debuglight.integer >= 0)
4159 lightindex = r_shadow_debuglight.integer;
4160 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4161 if (light && (light->flags & flag))
4162 R_Shadow_PrepareLight(&light->rtlight);
4166 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4167 for (lightindex = 0;lightindex < range;lightindex++)
4169 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4170 if (light && (light->flags & flag))
4171 R_Shadow_PrepareLight(&light->rtlight);
4174 if (r_refdef.scene.rtdlight)
4176 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4177 R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
4179 else if(gl_flashblend.integer)
4181 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4183 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
4184 f = (rtlight->style >= 0 ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4185 VectorScale(rtlight->color, f, rtlight->currentcolor);
4189 if (r_editlights.integer)
4190 R_Shadow_DrawLightSprites();
4193 void R_Shadow_DrawLights(void)
4201 R_Shadow_RenderMode_Begin();
4203 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4204 if (r_shadow_debuglight.integer >= 0)
4206 lightindex = r_shadow_debuglight.integer;
4207 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4208 if (light && (light->flags & flag))
4209 R_Shadow_DrawLight(&light->rtlight);
4213 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4214 for (lightindex = 0;lightindex < range;lightindex++)
4216 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4217 if (light && (light->flags & flag))
4218 R_Shadow_DrawLight(&light->rtlight);
4221 if (r_refdef.scene.rtdlight)
4222 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4223 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4225 R_Shadow_RenderMode_End();
4228 extern const float r_screenvertex3f[12];
4229 extern void R_SetupView(qboolean allowwaterclippingplane);
4230 extern void R_ResetViewRendering3D(void);
4231 extern void R_ResetViewRendering2D(void);
4232 extern cvar_t r_shadows;
4233 extern cvar_t r_shadows_darken;
4234 extern cvar_t r_shadows_drawafterrtlighting;
4235 extern cvar_t r_shadows_castfrombmodels;
4236 extern cvar_t r_shadows_throwdistance;
4237 extern cvar_t r_shadows_throwdirection;
4238 extern cvar_t r_shadows_focus;
4239 extern cvar_t r_shadows_shadowmapscale;
4241 void R_Shadow_PrepareModelShadows(void)
4244 float scale, size, radius, dot1, dot2;
4245 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
4246 entity_render_t *ent;
4248 if (!r_refdef.scene.numentities)
4251 switch (r_shadow_shadowmode)
4253 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4254 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
4256 case R_SHADOW_SHADOWMODE_STENCIL:
4257 for (i = 0;i < r_refdef.scene.numentities;i++)
4259 ent = r_refdef.scene.entities[i];
4260 if (!ent->animcache_vertex3f && ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4261 R_AnimCache_GetEntity(ent, false, false);
4268 size = 2*r_shadow_shadowmapmaxsize;
4269 scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
4270 radius = 0.5f * size / scale;
4272 Math_atov(r_shadows_throwdirection.string, shadowdir);
4273 VectorNormalize(shadowdir);
4274 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4275 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4276 if (fabs(dot1) <= fabs(dot2))
4277 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4279 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4280 VectorNormalize(shadowforward);
4281 CrossProduct(shadowdir, shadowforward, shadowright);
4282 Math_atov(r_shadows_focus.string, shadowfocus);
4283 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4284 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4285 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4286 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4287 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4289 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4291 shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4292 shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4293 shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4294 shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4295 shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4296 shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4298 for (i = 0;i < r_refdef.scene.numentities;i++)
4300 ent = r_refdef.scene.entities[i];
4301 if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
4303 // cast shadows from anything of the map (submodels are optional)
4304 if (!ent->animcache_vertex3f && ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4305 R_AnimCache_GetEntity(ent, false, false);
4309 void R_DrawModelShadowMaps(void)
4312 float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
4313 entity_render_t *ent;
4314 vec3_t relativelightorigin;
4315 vec3_t relativelightdirection, relativeforward, relativeright;
4316 vec3_t relativeshadowmins, relativeshadowmaxs;
4317 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
4319 matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
4320 r_viewport_t viewport;
4323 if (!r_refdef.scene.numentities)
4326 switch (r_shadow_shadowmode)
4328 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4329 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
4336 R_ResetViewRendering3D();
4337 R_Shadow_RenderMode_Begin();
4338 R_Shadow_RenderMode_ActiveLight(NULL);
4340 switch (r_shadow_shadowmode)
4342 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4343 if (!r_shadow_shadowmap2dtexture)
4344 R_Shadow_MakeShadowMap(0, r_shadow_shadowmapmaxsize);
4345 fbo = r_shadow_fbo2d;
4346 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
4347 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
4348 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
4350 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
4351 if (!r_shadow_shadowmaprectangletexture)
4352 R_Shadow_MakeShadowMap(0, r_shadow_shadowmapmaxsize);
4353 fbo = r_shadow_fborectangle;
4354 r_shadow_shadowmap_texturescale[0] = 1.0f;
4355 r_shadow_shadowmap_texturescale[1] = 1.0f;
4356 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE;
4362 size = 2*r_shadow_shadowmapmaxsize;
4363 scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
4364 radius = 0.5f / scale;
4365 nearclip = -r_shadows_throwdistance.value;
4366 farclip = r_shadows_throwdistance.value;
4367 bias = r_shadow_shadowmapping_bias.value * r_shadow_shadowmapping_nearclip.value / (2 * r_shadows_throwdistance.value) * (1024.0f / size);
4369 r_shadow_shadowmap_parameters[0] = size;
4370 r_shadow_shadowmap_parameters[1] = size;
4371 r_shadow_shadowmap_parameters[2] = 1.0;
4372 r_shadow_shadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
4374 Math_atov(r_shadows_throwdirection.string, shadowdir);
4375 VectorNormalize(shadowdir);
4376 Math_atov(r_shadows_focus.string, shadowfocus);
4377 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4378 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4379 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4380 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4381 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4382 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4383 if (fabs(dot1) <= fabs(dot2))
4384 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4386 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4387 VectorNormalize(shadowforward);
4388 VectorM(scale, shadowforward, &m[0]);
4389 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4391 m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
4392 CrossProduct(shadowdir, shadowforward, shadowright);
4393 VectorM(scale, shadowright, &m[4]);
4394 m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
4395 VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
4396 m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
4397 Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
4398 Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
4399 R_Viewport_InitOrtho(&viewport, &cameramatrix, 0, 0, size, size, 0, 0, 1, 1, 0, -1, NULL);
4401 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4404 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);CHECKGLERROR
4405 R_SetupShader_ShowDepth();
4407 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);CHECKGLERROR
4408 R_SetupShader_DepthOrShadow();
4411 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
4414 R_SetViewport(&viewport);
4415 GL_Scissor(viewport.x, viewport.y, min(viewport.width + r_shadow_shadowmapborder, 2*r_shadow_shadowmapmaxsize), viewport.height + r_shadow_shadowmapborder);
4418 qglClearColor(1,1,1,1);
4419 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
4421 GL_Clear(GL_DEPTH_BUFFER_BIT);
4423 GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
4426 for (i = 0;i < r_refdef.scene.numentities;i++)
4428 ent = r_refdef.scene.entities[i];
4430 // cast shadows from anything of the map (submodels are optional)
4431 if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4433 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4434 Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
4435 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4436 Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
4437 Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
4438 relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4439 relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4440 relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4441 relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4442 relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4443 relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4444 RSurf_ActiveModelEntity(ent, false, false, false);
4445 ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
4446 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4450 R_Shadow_RenderMode_End();
4452 Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
4453 Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
4454 Matrix4x4_CreateScale3(&scalematrix, size, -size, 1);
4455 Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
4456 Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
4457 Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
4459 r_shadow_usingshadowmaportho = true;
4460 switch (r_shadow_shadowmode)
4462 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4463 r_shadow_usingshadowmap2d = true;
4465 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
4466 r_shadow_usingshadowmaprect = true;
4473 void R_DrawModelShadows(void)
4476 float relativethrowdistance;
4477 entity_render_t *ent;
4478 vec3_t relativelightorigin;
4479 vec3_t relativelightdirection;
4480 vec3_t relativeshadowmins, relativeshadowmaxs;
4481 vec3_t tmp, shadowdir;
4483 if (!r_refdef.scene.numentities || !vid.stencil || r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL)
4487 R_ResetViewRendering3D();
4488 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4489 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4490 R_Shadow_RenderMode_Begin();
4491 R_Shadow_RenderMode_ActiveLight(NULL);
4492 r_shadow_lightscissor[0] = r_refdef.view.x;
4493 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
4494 r_shadow_lightscissor[2] = r_refdef.view.width;
4495 r_shadow_lightscissor[3] = r_refdef.view.height;
4496 R_Shadow_RenderMode_StencilShadowVolumes(false);
4499 if (r_shadows.integer == 2)
4501 Math_atov(r_shadows_throwdirection.string, shadowdir);
4502 VectorNormalize(shadowdir);
4505 R_Shadow_ClearStencil();
4507 for (i = 0;i < r_refdef.scene.numentities;i++)
4509 ent = r_refdef.scene.entities[i];
4511 // cast shadows from anything of the map (submodels are optional)
4512 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4514 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4515 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
4516 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
4517 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
4518 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4521 if(ent->entitynumber != 0)
4523 if(ent->entitynumber >= MAX_EDICTS) // csqc entity
4525 // FIXME handle this
4526 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4530 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
4531 int entnum, entnum2, recursion;
4532 entnum = entnum2 = ent->entitynumber;
4533 for(recursion = 32; recursion > 0; --recursion)
4535 entnum2 = cl.entities[entnum].state_current.tagentity;
4536 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
4541 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
4543 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
4544 // transform into modelspace of OUR entity
4545 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
4546 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
4549 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4553 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4556 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
4557 RSurf_ActiveModelEntity(ent, false, false, false);
4558 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4559 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4563 // not really the right mode, but this will disable any silly stencil features
4564 R_Shadow_RenderMode_End();
4566 // set up ortho view for rendering this pass
4567 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4568 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4569 //GL_ScissorTest(true);
4570 //R_EntityMatrix(&identitymatrix);
4571 //R_Mesh_ResetTextureState();
4572 R_ResetViewRendering2D();
4573 R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
4574 R_Mesh_ColorPointer(NULL, 0, 0);
4575 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
4577 // set up a darkening blend on shadowed areas
4578 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4579 //GL_DepthRange(0, 1);
4580 //GL_DepthTest(false);
4581 //GL_DepthMask(false);
4582 //GL_PolygonOffset(0, 0);CHECKGLERROR
4583 GL_Color(0, 0, 0, r_shadows_darken.value);
4584 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4585 //qglDepthFunc(GL_ALWAYS);CHECKGLERROR
4586 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
4587 qglStencilMask(255);CHECKGLERROR
4588 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
4589 qglStencilFunc(GL_NOTEQUAL, 128, 255);CHECKGLERROR
4591 // apply the blend to the shadowed areas
4592 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
4594 // restore the viewport
4595 R_SetViewport(&r_refdef.view.viewport);
4597 // restore other state to normal
4598 //R_Shadow_RenderMode_End();
4601 void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4604 vec3_t centerorigin;
4606 // if it's too close, skip it
4607 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
4609 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4612 if (usequery && r_numqueries + 2 <= r_maxqueries)
4614 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4615 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4616 // 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
4617 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4620 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use qglDepthFunc instead
4621 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
4622 qglDepthFunc(GL_ALWAYS);
4623 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4624 R_Mesh_VertexPointer(vertex3f, 0, 0);
4625 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
4626 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4627 qglDepthFunc(GL_LEQUAL);
4628 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
4629 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4630 R_Mesh_VertexPointer(vertex3f, 0, 0);
4631 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
4632 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4635 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4638 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
4640 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4643 GLint allpixels = 0, visiblepixels = 0;
4644 // now we have to check the query result
4645 if (rtlight->corona_queryindex_visiblepixels)
4648 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
4649 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
4651 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
4652 if (visiblepixels < 1 || allpixels < 1)
4654 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
4655 cscale *= rtlight->corona_visibility;
4659 // FIXME: these traces should scan all render entities instead of cl.world
4660 if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
4663 VectorScale(rtlight->currentcolor, cscale, color);
4664 if (VectorLength(color) > (1.0f / 256.0f))
4667 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
4670 VectorNegate(color, color);
4671 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
4673 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4674 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);
4675 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4677 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
4681 void R_Shadow_DrawCoronas(void)
4689 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4691 if (r_waterstate.renderingscene)
4693 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4694 R_EntityMatrix(&identitymatrix);
4696 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4698 // check occlusion of coronas
4699 // use GL_ARB_occlusion_query if available
4700 // otherwise use raytraces
4702 usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
4705 GL_ColorMask(0,0,0,0);
4706 if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
4707 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
4710 r_maxqueries = (range + r_refdef.scene.numlights) * 4;
4711 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
4713 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
4716 RSurf_ActiveWorldEntity();
4717 GL_BlendFunc(GL_ONE, GL_ZERO);
4718 GL_CullFace(GL_NONE);
4719 GL_DepthMask(false);
4720 GL_DepthRange(0, 1);
4721 GL_PolygonOffset(0, 0);
4723 R_Mesh_ColorPointer(NULL, 0, 0);
4724 R_Mesh_ResetTextureState();
4725 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
4727 for (lightindex = 0;lightindex < range;lightindex++)
4729 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4732 rtlight = &light->rtlight;
4733 rtlight->corona_visibility = 0;
4734 rtlight->corona_queryindex_visiblepixels = 0;
4735 rtlight->corona_queryindex_allpixels = 0;
4736 if (!(rtlight->flags & flag))
4738 if (rtlight->corona <= 0)
4740 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4742 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4744 for (i = 0;i < r_refdef.scene.numlights;i++)
4746 rtlight = r_refdef.scene.lights[i];
4747 rtlight->corona_visibility = 0;
4748 rtlight->corona_queryindex_visiblepixels = 0;
4749 rtlight->corona_queryindex_allpixels = 0;
4750 if (!(rtlight->flags & flag))
4752 if (rtlight->corona <= 0)
4754 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4757 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4759 // now draw the coronas using the query data for intensity info
4760 for (lightindex = 0;lightindex < range;lightindex++)
4762 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4765 rtlight = &light->rtlight;
4766 if (rtlight->corona_visibility <= 0)
4768 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4770 for (i = 0;i < r_refdef.scene.numlights;i++)
4772 rtlight = r_refdef.scene.lights[i];
4773 if (rtlight->corona_visibility <= 0)
4775 if (gl_flashblend.integer)
4776 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4778 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4784 dlight_t *R_Shadow_NewWorldLight(void)
4786 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4789 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)
4792 // validate parameters
4793 if (style < 0 || style >= MAX_LIGHTSTYLES)
4795 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
4801 // copy to light properties
4802 VectorCopy(origin, light->origin);
4803 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4804 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4805 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4807 light->color[0] = max(color[0], 0);
4808 light->color[1] = max(color[1], 0);
4809 light->color[2] = max(color[2], 0);
4811 light->color[0] = color[0];
4812 light->color[1] = color[1];
4813 light->color[2] = color[2];
4814 light->radius = max(radius, 0);
4815 light->style = style;
4816 light->shadow = shadowenable;
4817 light->corona = corona;
4818 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4819 light->coronasizescale = coronasizescale;
4820 light->ambientscale = ambientscale;
4821 light->diffusescale = diffusescale;
4822 light->specularscale = specularscale;
4823 light->flags = flags;
4825 // update renderable light data
4826 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4827 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);
4830 void R_Shadow_FreeWorldLight(dlight_t *light)
4832 if (r_shadow_selectedlight == light)
4833 r_shadow_selectedlight = NULL;
4834 R_RTLight_Uncompile(&light->rtlight);
4835 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4838 void R_Shadow_ClearWorldLights(void)
4842 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4843 for (lightindex = 0;lightindex < range;lightindex++)
4845 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4847 R_Shadow_FreeWorldLight(light);
4849 r_shadow_selectedlight = NULL;
4852 void R_Shadow_SelectLight(dlight_t *light)
4854 if (r_shadow_selectedlight)
4855 r_shadow_selectedlight->selected = false;
4856 r_shadow_selectedlight = light;
4857 if (r_shadow_selectedlight)
4858 r_shadow_selectedlight->selected = true;
4861 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4863 // this is never batched (there can be only one)
4865 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
4866 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4867 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4870 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4875 skinframe_t *skinframe;
4878 // this is never batched (due to the ent parameter changing every time)
4879 // so numsurfaces == 1 and surfacelist[0] == lightnumber
4880 const dlight_t *light = (dlight_t *)ent;
4883 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
4886 VectorScale(light->color, intensity, spritecolor);
4887 if (VectorLength(spritecolor) < 0.1732f)
4888 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
4889 if (VectorLength(spritecolor) > 1.0f)
4890 VectorNormalize(spritecolor);
4892 // draw light sprite
4893 if (light->cubemapname[0] && !light->shadow)
4894 skinframe = r_editlights_sprcubemapnoshadowlight;
4895 else if (light->cubemapname[0])
4896 skinframe = r_editlights_sprcubemaplight;
4897 else if (!light->shadow)
4898 skinframe = r_editlights_sprnoshadowlight;
4900 skinframe = r_editlights_sprlight;
4902 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);
4903 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4905 // draw selection sprite if light is selected
4906 if (light->selected)
4908 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4909 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4910 // VorteX todo: add normalmode/realtime mode light overlay sprites?
4914 void R_Shadow_DrawLightSprites(void)
4918 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4919 for (lightindex = 0;lightindex < range;lightindex++)
4921 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4923 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
4925 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
4928 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
4933 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
4934 if (lightindex >= range)
4936 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4939 rtlight = &light->rtlight;
4940 //if (!(rtlight->flags & flag))
4942 VectorCopy(rtlight->shadoworigin, origin);
4943 *radius = rtlight->radius;
4944 VectorCopy(rtlight->color, color);
4948 void R_Shadow_SelectLightInView(void)
4950 float bestrating, rating, temp[3];
4954 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4957 for (lightindex = 0;lightindex < range;lightindex++)
4959 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4962 VectorSubtract(light->origin, r_refdef.view.origin, temp);
4963 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
4966 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
4967 if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1.0f)
4969 bestrating = rating;
4974 R_Shadow_SelectLight(best);
4977 void R_Shadow_LoadWorldLights(void)
4979 int n, a, style, shadow, flags;
4980 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
4981 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
4982 if (cl.worldmodel == NULL)
4984 Con_Print("No map loaded.\n");
4987 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4988 strlcat (name, ".rtlights", sizeof (name));
4989 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4999 for (;COM_Parse(t, true) && strcmp(
5000 if (COM_Parse(t, true))
5002 if (com_token[0] == '!')
5005 origin[0] = atof(com_token+1);
5008 origin[0] = atof(com_token);
5013 while (*s && *s != '\n' && *s != '\r')
5019 // check for modifier flags
5026 #if _MSC_VER >= 1400
5027 #define sscanf sscanf_s
5029 cubemapname[sizeof(cubemapname)-1] = 0;
5030 #if MAX_QPATH != 128
5031 #error update this code if MAX_QPATH changes
5033 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
5034 #if _MSC_VER >= 1400
5035 , sizeof(cubemapname)
5037 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
5040 flags = LIGHTFLAG_REALTIMEMODE;
5048 coronasizescale = 0.25f;
5050 VectorClear(angles);
5053 if (a < 9 || !strcmp(cubemapname, "\"\""))
5055 // remove quotes on cubemapname
5056 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
5059 namelen = strlen(cubemapname) - 2;
5060 memmove(cubemapname, cubemapname + 1, namelen);
5061 cubemapname[namelen] = '\0';
5065 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);
5068 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5076 Con_Printf("invalid rtlights file \"%s\"\n", name);
5077 Mem_Free(lightsstring);
5081 void R_Shadow_SaveWorldLights(void)
5085 size_t bufchars, bufmaxchars;
5087 char name[MAX_QPATH];
5088 char line[MAX_INPUTLINE];
5089 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
5090 // I hate lines which are 3 times my screen size :( --blub
5093 if (cl.worldmodel == NULL)
5095 Con_Print("No map loaded.\n");
5098 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
5099 strlcat (name, ".rtlights", sizeof (name));
5100 bufchars = bufmaxchars = 0;
5102 for (lightindex = 0;lightindex < range;lightindex++)
5104 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5107 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
5108 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);
5109 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
5110 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]);
5112 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);
5113 if (bufchars + strlen(line) > bufmaxchars)
5115 bufmaxchars = bufchars + strlen(line) + 2048;
5117 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
5121 memcpy(buf, oldbuf, bufchars);
5127 memcpy(buf + bufchars, line, strlen(line));
5128 bufchars += strlen(line);
5132 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
5137 void R_Shadow_LoadLightsFile(void)
5140 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
5141 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
5142 if (cl.worldmodel == NULL)
5144 Con_Print("No map loaded.\n");
5147 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
5148 strlcat (name, ".lights", sizeof (name));
5149 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5157 while (*s && *s != '\n' && *s != '\r')
5163 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);
5167 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);
5170 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
5171 radius = bound(15, radius, 4096);
5172 VectorScale(color, (2.0f / (8388608.0f)), color);
5173 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5181 Con_Printf("invalid lights file \"%s\"\n", name);
5182 Mem_Free(lightsstring);
5186 // tyrlite/hmap2 light types in the delay field
5187 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
5189 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
5201 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
5202 char key[256], value[MAX_INPUTLINE];
5204 if (cl.worldmodel == NULL)
5206 Con_Print("No map loaded.\n");
5209 // try to load a .ent file first
5210 FS_StripExtension (cl.worldmodel->name, key, sizeof (key));
5211 strlcat (key, ".ent", sizeof (key));
5212 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
5213 // and if that is not found, fall back to the bsp file entity string
5215 data = cl.worldmodel->brush.entities;
5218 for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
5220 type = LIGHTTYPE_MINUSX;
5221 origin[0] = origin[1] = origin[2] = 0;
5222 originhack[0] = originhack[1] = originhack[2] = 0;
5223 angles[0] = angles[1] = angles[2] = 0;
5224 color[0] = color[1] = color[2] = 1;
5225 light[0] = light[1] = light[2] = 1;light[3] = 300;
5226 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
5236 if (!COM_ParseToken_Simple(&data, false, false))
5238 if (com_token[0] == '}')
5239 break; // end of entity
5240 if (com_token[0] == '_')
5241 strlcpy(key, com_token + 1, sizeof(key));
5243 strlcpy(key, com_token, sizeof(key));
5244 while (key[strlen(key)-1] == ' ') // remove trailing spaces
5245 key[strlen(key)-1] = 0;
5246 if (!COM_ParseToken_Simple(&data, false, false))
5248 strlcpy(value, com_token, sizeof(value));
5250 // now that we have the key pair worked out...
5251 if (!strcmp("light", key))
5253 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5257 light[0] = vec[0] * (1.0f / 256.0f);
5258 light[1] = vec[0] * (1.0f / 256.0f);
5259 light[2] = vec[0] * (1.0f / 256.0f);
5265 light[0] = vec[0] * (1.0f / 255.0f);
5266 light[1] = vec[1] * (1.0f / 255.0f);
5267 light[2] = vec[2] * (1.0f / 255.0f);
5271 else if (!strcmp("delay", key))
5273 else if (!strcmp("origin", key))
5274 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5275 else if (!strcmp("angle", key))
5276 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5277 else if (!strcmp("angles", key))
5278 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5279 else if (!strcmp("color", key))
5280 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5281 else if (!strcmp("wait", key))
5282 fadescale = atof(value);
5283 else if (!strcmp("classname", key))
5285 if (!strncmp(value, "light", 5))
5288 if (!strcmp(value, "light_fluoro"))
5293 overridecolor[0] = 1;
5294 overridecolor[1] = 1;
5295 overridecolor[2] = 1;
5297 if (!strcmp(value, "light_fluorospark"))
5302 overridecolor[0] = 1;
5303 overridecolor[1] = 1;
5304 overridecolor[2] = 1;
5306 if (!strcmp(value, "light_globe"))
5311 overridecolor[0] = 1;
5312 overridecolor[1] = 0.8;
5313 overridecolor[2] = 0.4;
5315 if (!strcmp(value, "light_flame_large_yellow"))
5320 overridecolor[0] = 1;
5321 overridecolor[1] = 0.5;
5322 overridecolor[2] = 0.1;
5324 if (!strcmp(value, "light_flame_small_yellow"))
5329 overridecolor[0] = 1;
5330 overridecolor[1] = 0.5;
5331 overridecolor[2] = 0.1;
5333 if (!strcmp(value, "light_torch_small_white"))
5338 overridecolor[0] = 1;
5339 overridecolor[1] = 0.5;
5340 overridecolor[2] = 0.1;
5342 if (!strcmp(value, "light_torch_small_walltorch"))
5347 overridecolor[0] = 1;
5348 overridecolor[1] = 0.5;
5349 overridecolor[2] = 0.1;
5353 else if (!strcmp("style", key))
5354 style = atoi(value);
5355 else if (!strcmp("skin", key))
5356 skin = (int)atof(value);
5357 else if (!strcmp("pflags", key))
5358 pflags = (int)atof(value);
5359 //else if (!strcmp("effects", key))
5360 // effects = (int)atof(value);
5361 else if (cl.worldmodel->type == mod_brushq3)
5363 if (!strcmp("scale", key))
5364 lightscale = atof(value);
5365 if (!strcmp("fade", key))
5366 fadescale = atof(value);
5371 if (lightscale <= 0)
5375 if (color[0] == color[1] && color[0] == color[2])
5377 color[0] *= overridecolor[0];
5378 color[1] *= overridecolor[1];
5379 color[2] *= overridecolor[2];
5381 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5382 color[0] = color[0] * light[0];
5383 color[1] = color[1] * light[1];
5384 color[2] = color[2] * light[2];
5387 case LIGHTTYPE_MINUSX:
5389 case LIGHTTYPE_RECIPX:
5391 VectorScale(color, (1.0f / 16.0f), color);
5393 case LIGHTTYPE_RECIPXX:
5395 VectorScale(color, (1.0f / 16.0f), color);
5398 case LIGHTTYPE_NONE:
5402 case LIGHTTYPE_MINUSXX:
5405 VectorAdd(origin, originhack, origin);
5407 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);
5410 Mem_Free(entfiledata);
5414 void R_Shadow_SetCursorLocationForView(void)
5417 vec3_t dest, endpos;
5419 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5420 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
5421 if (trace.fraction < 1)
5423 dist = trace.fraction * r_editlights_cursordistance.value;
5424 push = r_editlights_cursorpushback.value;
5428 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5429 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5433 VectorClear( endpos );
5435 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5436 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5437 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5440 void R_Shadow_UpdateWorldLightSelection(void)
5442 if (r_editlights.integer)
5444 R_Shadow_SetCursorLocationForView();
5445 R_Shadow_SelectLightInView();
5448 R_Shadow_SelectLight(NULL);
5451 void R_Shadow_EditLights_Clear_f(void)
5453 R_Shadow_ClearWorldLights();
5456 void R_Shadow_EditLights_Reload_f(void)
5460 strlcpy(r_shadow_mapname, cl.worldmodel->name, sizeof(r_shadow_mapname));
5461 R_Shadow_ClearWorldLights();
5462 R_Shadow_LoadWorldLights();
5463 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5465 R_Shadow_LoadLightsFile();
5466 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5467 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5471 void R_Shadow_EditLights_Save_f(void)
5475 R_Shadow_SaveWorldLights();
5478 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
5480 R_Shadow_ClearWorldLights();
5481 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5484 void R_Shadow_EditLights_ImportLightsFile_f(void)
5486 R_Shadow_ClearWorldLights();
5487 R_Shadow_LoadLightsFile();
5490 void R_Shadow_EditLights_Spawn_f(void)
5493 if (!r_editlights.integer)
5495 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5498 if (Cmd_Argc() != 1)
5500 Con_Print("r_editlights_spawn does not take parameters\n");
5503 color[0] = color[1] = color[2] = 1;
5504 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5507 void R_Shadow_EditLights_Edit_f(void)
5509 vec3_t origin, angles, color;
5510 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5511 int style, shadows, flags, normalmode, realtimemode;
5512 char cubemapname[MAX_INPUTLINE];
5513 if (!r_editlights.integer)
5515 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5518 if (!r_shadow_selectedlight)
5520 Con_Print("No selected light.\n");
5523 VectorCopy(r_shadow_selectedlight->origin, origin);
5524 VectorCopy(r_shadow_selectedlight->angles, angles);
5525 VectorCopy(r_shadow_selectedlight->color, color);
5526 radius = r_shadow_selectedlight->radius;
5527 style = r_shadow_selectedlight->style;
5528 if (r_shadow_selectedlight->cubemapname)
5529 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5532 shadows = r_shadow_selectedlight->shadow;
5533 corona = r_shadow_selectedlight->corona;
5534 coronasizescale = r_shadow_selectedlight->coronasizescale;
5535 ambientscale = r_shadow_selectedlight->ambientscale;
5536 diffusescale = r_shadow_selectedlight->diffusescale;
5537 specularscale = r_shadow_selectedlight->specularscale;
5538 flags = r_shadow_selectedlight->flags;
5539 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5540 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5541 if (!strcmp(Cmd_Argv(1), "origin"))
5543 if (Cmd_Argc() != 5)
5545 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5548 origin[0] = atof(Cmd_Argv(2));
5549 origin[1] = atof(Cmd_Argv(3));
5550 origin[2] = atof(Cmd_Argv(4));
5552 else if (!strcmp(Cmd_Argv(1), "originx"))
5554 if (Cmd_Argc() != 3)
5556 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5559 origin[0] = atof(Cmd_Argv(2));
5561 else if (!strcmp(Cmd_Argv(1), "originy"))
5563 if (Cmd_Argc() != 3)
5565 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5568 origin[1] = atof(Cmd_Argv(2));
5570 else if (!strcmp(Cmd_Argv(1), "originz"))
5572 if (Cmd_Argc() != 3)
5574 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5577 origin[2] = atof(Cmd_Argv(2));
5579 else if (!strcmp(Cmd_Argv(1), "move"))
5581 if (Cmd_Argc() != 5)
5583 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5586 origin[0] += atof(Cmd_Argv(2));
5587 origin[1] += atof(Cmd_Argv(3));
5588 origin[2] += atof(Cmd_Argv(4));
5590 else if (!strcmp(Cmd_Argv(1), "movex"))
5592 if (Cmd_Argc() != 3)
5594 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5597 origin[0] += atof(Cmd_Argv(2));
5599 else if (!strcmp(Cmd_Argv(1), "movey"))
5601 if (Cmd_Argc() != 3)
5603 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5606 origin[1] += atof(Cmd_Argv(2));
5608 else if (!strcmp(Cmd_Argv(1), "movez"))
5610 if (Cmd_Argc() != 3)
5612 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5615 origin[2] += atof(Cmd_Argv(2));
5617 else if (!strcmp(Cmd_Argv(1), "angles"))
5619 if (Cmd_Argc() != 5)
5621 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5624 angles[0] = atof(Cmd_Argv(2));
5625 angles[1] = atof(Cmd_Argv(3));
5626 angles[2] = atof(Cmd_Argv(4));
5628 else if (!strcmp(Cmd_Argv(1), "anglesx"))
5630 if (Cmd_Argc() != 3)
5632 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5635 angles[0] = atof(Cmd_Argv(2));
5637 else if (!strcmp(Cmd_Argv(1), "anglesy"))
5639 if (Cmd_Argc() != 3)
5641 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5644 angles[1] = atof(Cmd_Argv(2));
5646 else if (!strcmp(Cmd_Argv(1), "anglesz"))
5648 if (Cmd_Argc() != 3)
5650 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5653 angles[2] = atof(Cmd_Argv(2));
5655 else if (!strcmp(Cmd_Argv(1), "color"))
5657 if (Cmd_Argc() != 5)
5659 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
5662 color[0] = atof(Cmd_Argv(2));
5663 color[1] = atof(Cmd_Argv(3));
5664 color[2] = atof(Cmd_Argv(4));
5666 else if (!strcmp(Cmd_Argv(1), "radius"))
5668 if (Cmd_Argc() != 3)
5670 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5673 radius = atof(Cmd_Argv(2));
5675 else if (!strcmp(Cmd_Argv(1), "colorscale"))
5677 if (Cmd_Argc() == 3)
5679 double scale = atof(Cmd_Argv(2));
5686 if (Cmd_Argc() != 5)
5688 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
5691 color[0] *= atof(Cmd_Argv(2));
5692 color[1] *= atof(Cmd_Argv(3));
5693 color[2] *= atof(Cmd_Argv(4));
5696 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
5698 if (Cmd_Argc() != 3)
5700 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5703 radius *= atof(Cmd_Argv(2));
5705 else if (!strcmp(Cmd_Argv(1), "style"))
5707 if (Cmd_Argc() != 3)
5709 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5712 style = atoi(Cmd_Argv(2));
5714 else if (!strcmp(Cmd_Argv(1), "cubemap"))
5718 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5721 if (Cmd_Argc() == 3)
5722 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
5726 else if (!strcmp(Cmd_Argv(1), "shadows"))
5728 if (Cmd_Argc() != 3)
5730 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5733 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5735 else if (!strcmp(Cmd_Argv(1), "corona"))
5737 if (Cmd_Argc() != 3)
5739 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5742 corona = atof(Cmd_Argv(2));
5744 else if (!strcmp(Cmd_Argv(1), "coronasize"))
5746 if (Cmd_Argc() != 3)
5748 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5751 coronasizescale = atof(Cmd_Argv(2));
5753 else if (!strcmp(Cmd_Argv(1), "ambient"))
5755 if (Cmd_Argc() != 3)
5757 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5760 ambientscale = atof(Cmd_Argv(2));
5762 else if (!strcmp(Cmd_Argv(1), "diffuse"))
5764 if (Cmd_Argc() != 3)
5766 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5769 diffusescale = atof(Cmd_Argv(2));
5771 else if (!strcmp(Cmd_Argv(1), "specular"))
5773 if (Cmd_Argc() != 3)
5775 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5778 specularscale = atof(Cmd_Argv(2));
5780 else if (!strcmp(Cmd_Argv(1), "normalmode"))
5782 if (Cmd_Argc() != 3)
5784 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5787 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5789 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
5791 if (Cmd_Argc() != 3)
5793 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5796 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5800 Con_Print("usage: r_editlights_edit [property] [value]\n");
5801 Con_Print("Selected light's properties:\n");
5802 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5803 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5804 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5805 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
5806 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
5807 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
5808 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5809 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
5810 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
5811 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
5812 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
5813 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
5814 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5815 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5818 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5819 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5822 void R_Shadow_EditLights_EditAll_f(void)
5828 if (!r_editlights.integer)
5830 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5834 // EditLights doesn't seem to have a "remove" command or something so:
5835 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5836 for (lightindex = 0;lightindex < range;lightindex++)
5838 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5841 R_Shadow_SelectLight(light);
5842 R_Shadow_EditLights_Edit_f();
5846 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
5848 int lightnumber, lightcount;
5849 size_t lightindex, range;
5853 if (!r_editlights.integer)
5855 x = vid_conwidth.value - 240;
5857 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
5860 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5861 for (lightindex = 0;lightindex < range;lightindex++)
5863 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5866 if (light == r_shadow_selectedlight)
5867 lightnumber = lightindex;
5870 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;
5871 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;
5873 if (r_shadow_selectedlight == NULL)
5875 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;
5876 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;
5877 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;
5878 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;
5879 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;
5880 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;
5881 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;
5882 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;
5883 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;
5884 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;
5885 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;
5886 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;
5887 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;
5888 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;
5889 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;
5892 void R_Shadow_EditLights_ToggleShadow_f(void)
5894 if (!r_editlights.integer)
5896 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5899 if (!r_shadow_selectedlight)
5901 Con_Print("No selected light.\n");
5904 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);
5907 void R_Shadow_EditLights_ToggleCorona_f(void)
5909 if (!r_editlights.integer)
5911 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5914 if (!r_shadow_selectedlight)
5916 Con_Print("No selected light.\n");
5919 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);
5922 void R_Shadow_EditLights_Remove_f(void)
5924 if (!r_editlights.integer)
5926 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
5929 if (!r_shadow_selectedlight)
5931 Con_Print("No selected light.\n");
5934 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
5935 r_shadow_selectedlight = NULL;
5938 void R_Shadow_EditLights_Help_f(void)
5941 "Documentation on r_editlights system:\n"
5943 "r_editlights : enable/disable editing mode\n"
5944 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
5945 "r_editlights_cursorpushback : push back cursor this far from surface\n"
5946 "r_editlights_cursorpushoff : push cursor off surface this far\n"
5947 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
5948 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
5950 "r_editlights_help : this help\n"
5951 "r_editlights_clear : remove all lights\n"
5952 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
5953 "r_editlights_save : save to .rtlights file\n"
5954 "r_editlights_spawn : create a light with default settings\n"
5955 "r_editlights_edit command : edit selected light - more documentation below\n"
5956 "r_editlights_remove : remove selected light\n"
5957 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
5958 "r_editlights_importlightentitiesfrommap : reload light entities\n"
5959 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
5961 "origin x y z : set light location\n"
5962 "originx x: set x component of light location\n"
5963 "originy y: set y component of light location\n"
5964 "originz z: set z component of light location\n"
5965 "move x y z : adjust light location\n"
5966 "movex x: adjust x component of light location\n"
5967 "movey y: adjust y component of light location\n"
5968 "movez z: adjust z component of light location\n"
5969 "angles x y z : set light angles\n"
5970 "anglesx x: set x component of light angles\n"
5971 "anglesy y: set y component of light angles\n"
5972 "anglesz z: set z component of light angles\n"
5973 "color r g b : set color of light (can be brighter than 1 1 1)\n"
5974 "radius radius : set radius (size) of light\n"
5975 "colorscale grey : multiply color of light (1 does nothing)\n"
5976 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
5977 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
5978 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
5979 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
5980 "cubemap basename : set filter cubemap of light (not yet supported)\n"
5981 "shadows 1/0 : turn on/off shadows\n"
5982 "corona n : set corona intensity\n"
5983 "coronasize n : set corona size (0-1)\n"
5984 "ambient n : set ambient intensity (0-1)\n"
5985 "diffuse n : set diffuse intensity (0-1)\n"
5986 "specular n : set specular intensity (0-1)\n"
5987 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
5988 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
5989 "<nothing> : print light properties to console\n"
5993 void R_Shadow_EditLights_CopyInfo_f(void)
5995 if (!r_editlights.integer)
5997 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
6000 if (!r_shadow_selectedlight)
6002 Con_Print("No selected light.\n");
6005 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
6006 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
6007 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
6008 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
6009 if (r_shadow_selectedlight->cubemapname)
6010 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
6012 r_shadow_bufferlight.cubemapname[0] = 0;
6013 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
6014 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
6015 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
6016 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
6017 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
6018 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
6019 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
6022 void R_Shadow_EditLights_PasteInfo_f(void)
6024 if (!r_editlights.integer)
6026 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
6029 if (!r_shadow_selectedlight)
6031 Con_Print("No selected light.\n");
6034 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);
6037 void R_Shadow_EditLights_Init(void)
6039 Cvar_RegisterVariable(&r_editlights);
6040 Cvar_RegisterVariable(&r_editlights_cursordistance);
6041 Cvar_RegisterVariable(&r_editlights_cursorpushback);
6042 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
6043 Cvar_RegisterVariable(&r_editlights_cursorgrid);
6044 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
6045 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
6046 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
6047 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)");
6048 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
6049 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
6050 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
6051 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)");
6052 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
6053 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
6054 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
6055 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
6056 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
6057 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
6058 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)");
6064 =============================================================================
6068 =============================================================================
6071 void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, int dynamic)
6073 VectorClear(diffusecolor);
6074 VectorClear(diffusenormal);
6076 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
6078 ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_refdef.scene.ambient;
6079 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
6082 VectorSet(ambientcolor, 1, 1, 1);
6089 for (i = 0;i < r_refdef.scene.numlights;i++)
6091 light = r_refdef.scene.lights[i];
6092 Matrix4x4_Transform(&light->matrix_worldtolight, p, v);
6093 f = 1 - VectorLength2(v);
6094 if (f > 0 && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
6095 VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);