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;
445 // Cg has very little choice in depth texture sampling
448 r_shadow_shadowmapsampler = false;
449 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
453 case RENDERPATH_GL13:
455 case RENDERPATH_GL11:
460 qboolean R_Shadow_ShadowMappingEnabled(void)
462 switch (r_shadow_shadowmode)
464 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
465 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
466 case R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE:
473 void R_Shadow_FreeShadowMaps(void)
477 R_Shadow_SetShadowMode();
479 if (!vid.support.ext_framebuffer_object || !vid.support.arb_fragment_shader)
484 if (r_shadow_fborectangle)
485 qglDeleteFramebuffersEXT(1, &r_shadow_fborectangle);CHECKGLERROR
486 r_shadow_fborectangle = 0;
489 qglDeleteFramebuffersEXT(1, &r_shadow_fbo2d);CHECKGLERROR
491 for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
492 if (r_shadow_fbocubeside[i])
493 qglDeleteFramebuffersEXT(1, &r_shadow_fbocubeside[i]);CHECKGLERROR
494 memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
496 if (r_shadow_shadowmaprectangletexture)
497 R_FreeTexture(r_shadow_shadowmaprectangletexture);
498 r_shadow_shadowmaprectangletexture = NULL;
500 if (r_shadow_shadowmap2dtexture)
501 R_FreeTexture(r_shadow_shadowmap2dtexture);
502 r_shadow_shadowmap2dtexture = NULL;
504 for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
505 if (r_shadow_shadowmapcubetexture[i])
506 R_FreeTexture(r_shadow_shadowmapcubetexture[i]);
507 memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
509 if (r_shadow_shadowmapvsdcttexture)
510 R_FreeTexture(r_shadow_shadowmapvsdcttexture);
511 r_shadow_shadowmapvsdcttexture = NULL;
516 void r_shadow_start(void)
518 // allocate vertex processing arrays
519 r_shadow_attenuationgradienttexture = NULL;
520 r_shadow_attenuation2dtexture = NULL;
521 r_shadow_attenuation3dtexture = NULL;
522 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
523 r_shadow_shadowmaprectangletexture = NULL;
524 r_shadow_shadowmap2dtexture = NULL;
525 memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
526 r_shadow_shadowmapvsdcttexture = NULL;
527 r_shadow_shadowmapmaxsize = 0;
528 r_shadow_shadowmapsize = 0;
529 r_shadow_shadowmaplod = 0;
530 r_shadow_shadowmapfilterquality = -1;
531 r_shadow_shadowmaptexturetype = -1;
532 r_shadow_shadowmapdepthbits = 0;
533 r_shadow_shadowmapvsdct = false;
534 r_shadow_shadowmapsampler = false;
535 r_shadow_shadowmappcf = 0;
536 r_shadow_fborectangle = 0;
538 memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
540 R_Shadow_FreeShadowMaps();
542 r_shadow_texturepool = NULL;
543 r_shadow_filters_texturepool = NULL;
544 R_Shadow_ValidateCvars();
545 R_Shadow_MakeTextures();
546 maxshadowtriangles = 0;
547 shadowelements = NULL;
548 maxshadowvertices = 0;
549 shadowvertex3f = NULL;
557 shadowmarklist = NULL;
562 shadowsideslist = NULL;
563 r_shadow_buffer_numleafpvsbytes = 0;
564 r_shadow_buffer_visitingleafpvs = NULL;
565 r_shadow_buffer_leafpvs = NULL;
566 r_shadow_buffer_leaflist = NULL;
567 r_shadow_buffer_numsurfacepvsbytes = 0;
568 r_shadow_buffer_surfacepvs = NULL;
569 r_shadow_buffer_surfacelist = NULL;
570 r_shadow_buffer_surfacesides = NULL;
571 r_shadow_buffer_numshadowtrispvsbytes = 0;
572 r_shadow_buffer_shadowtrispvs = NULL;
573 r_shadow_buffer_numlighttrispvsbytes = 0;
574 r_shadow_buffer_lighttrispvs = NULL;
576 r_shadow_usingdeferredprepass = false;
577 r_shadow_prepass_width = r_shadow_prepass_height = 0;
580 static void R_Shadow_FreeDeferred(void);
581 void r_shadow_shutdown(void)
584 R_Shadow_UncompileWorldLights();
586 R_Shadow_FreeShadowMaps();
588 r_shadow_usingdeferredprepass = false;
589 if (r_shadow_prepass_width)
590 R_Shadow_FreeDeferred();
591 r_shadow_prepass_width = r_shadow_prepass_height = 0;
594 r_shadow_attenuationgradienttexture = NULL;
595 r_shadow_attenuation2dtexture = NULL;
596 r_shadow_attenuation3dtexture = NULL;
597 R_FreeTexturePool(&r_shadow_texturepool);
598 R_FreeTexturePool(&r_shadow_filters_texturepool);
599 maxshadowtriangles = 0;
601 Mem_Free(shadowelements);
602 shadowelements = NULL;
604 Mem_Free(shadowvertex3f);
605 shadowvertex3f = NULL;
608 Mem_Free(vertexupdate);
611 Mem_Free(vertexremap);
617 Mem_Free(shadowmark);
620 Mem_Free(shadowmarklist);
621 shadowmarklist = NULL;
626 Mem_Free(shadowsides);
629 Mem_Free(shadowsideslist);
630 shadowsideslist = NULL;
631 r_shadow_buffer_numleafpvsbytes = 0;
632 if (r_shadow_buffer_visitingleafpvs)
633 Mem_Free(r_shadow_buffer_visitingleafpvs);
634 r_shadow_buffer_visitingleafpvs = NULL;
635 if (r_shadow_buffer_leafpvs)
636 Mem_Free(r_shadow_buffer_leafpvs);
637 r_shadow_buffer_leafpvs = NULL;
638 if (r_shadow_buffer_leaflist)
639 Mem_Free(r_shadow_buffer_leaflist);
640 r_shadow_buffer_leaflist = NULL;
641 r_shadow_buffer_numsurfacepvsbytes = 0;
642 if (r_shadow_buffer_surfacepvs)
643 Mem_Free(r_shadow_buffer_surfacepvs);
644 r_shadow_buffer_surfacepvs = NULL;
645 if (r_shadow_buffer_surfacelist)
646 Mem_Free(r_shadow_buffer_surfacelist);
647 r_shadow_buffer_surfacelist = NULL;
648 if (r_shadow_buffer_surfacesides)
649 Mem_Free(r_shadow_buffer_surfacesides);
650 r_shadow_buffer_surfacesides = NULL;
651 r_shadow_buffer_numshadowtrispvsbytes = 0;
652 if (r_shadow_buffer_shadowtrispvs)
653 Mem_Free(r_shadow_buffer_shadowtrispvs);
654 r_shadow_buffer_numlighttrispvsbytes = 0;
655 if (r_shadow_buffer_lighttrispvs)
656 Mem_Free(r_shadow_buffer_lighttrispvs);
659 void r_shadow_newmap(void)
661 if (r_shadow_lightcorona) R_SkinFrame_MarkUsed(r_shadow_lightcorona);
662 if (r_editlights_sprcursor) R_SkinFrame_MarkUsed(r_editlights_sprcursor);
663 if (r_editlights_sprlight) R_SkinFrame_MarkUsed(r_editlights_sprlight);
664 if (r_editlights_sprnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprnoshadowlight);
665 if (r_editlights_sprcubemaplight) R_SkinFrame_MarkUsed(r_editlights_sprcubemaplight);
666 if (r_editlights_sprcubemapnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprcubemapnoshadowlight);
667 if (r_editlights_sprselection) R_SkinFrame_MarkUsed(r_editlights_sprselection);
668 if (cl.worldmodel && strncmp(cl.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
669 R_Shadow_EditLights_Reload_f();
672 void R_Shadow_Init(void)
674 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
675 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
676 Cvar_RegisterVariable(&r_shadow_usenormalmap);
677 Cvar_RegisterVariable(&r_shadow_debuglight);
678 Cvar_RegisterVariable(&r_shadow_deferred);
679 Cvar_RegisterVariable(&r_shadow_deferred_8bitrange);
680 // Cvar_RegisterVariable(&r_shadow_deferred_fp);
681 Cvar_RegisterVariable(&r_shadow_gloss);
682 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
683 Cvar_RegisterVariable(&r_shadow_glossintensity);
684 Cvar_RegisterVariable(&r_shadow_glossexponent);
685 Cvar_RegisterVariable(&r_shadow_gloss2exponent);
686 Cvar_RegisterVariable(&r_shadow_glossexact);
687 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
688 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
689 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
690 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
691 Cvar_RegisterVariable(&r_shadow_projectdistance);
692 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
693 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
694 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
695 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
696 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
697 Cvar_RegisterVariable(&r_shadow_realtime_world);
698 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
699 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
700 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
701 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
702 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
703 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
704 Cvar_RegisterVariable(&r_shadow_scissor);
705 Cvar_RegisterVariable(&r_shadow_shadowmapping);
706 Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
707 Cvar_RegisterVariable(&r_shadow_shadowmapping_texturetype);
708 Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
709 Cvar_RegisterVariable(&r_shadow_shadowmapping_depthbits);
710 Cvar_RegisterVariable(&r_shadow_shadowmapping_precision);
711 Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
712 Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
713 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
714 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
715 Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
716 Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
717 Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
718 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonfactor);
719 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonoffset);
720 Cvar_RegisterVariable(&r_shadow_polygonfactor);
721 Cvar_RegisterVariable(&r_shadow_polygonoffset);
722 Cvar_RegisterVariable(&r_shadow_texture3d);
723 Cvar_RegisterVariable(&r_coronas);
724 Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
725 Cvar_RegisterVariable(&r_coronas_occlusionquery);
726 Cvar_RegisterVariable(&gl_flashblend);
727 Cvar_RegisterVariable(&gl_ext_separatestencil);
728 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
729 if (gamemode == GAME_TENEBRAE)
731 Cvar_SetValue("r_shadow_gloss", 2);
732 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
734 R_Shadow_EditLights_Init();
735 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
736 maxshadowtriangles = 0;
737 shadowelements = NULL;
738 maxshadowvertices = 0;
739 shadowvertex3f = NULL;
747 shadowmarklist = NULL;
752 shadowsideslist = NULL;
753 r_shadow_buffer_numleafpvsbytes = 0;
754 r_shadow_buffer_visitingleafpvs = NULL;
755 r_shadow_buffer_leafpvs = NULL;
756 r_shadow_buffer_leaflist = NULL;
757 r_shadow_buffer_numsurfacepvsbytes = 0;
758 r_shadow_buffer_surfacepvs = NULL;
759 r_shadow_buffer_surfacelist = NULL;
760 r_shadow_buffer_surfacesides = NULL;
761 r_shadow_buffer_shadowtrispvs = NULL;
762 r_shadow_buffer_lighttrispvs = NULL;
763 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
766 matrix4x4_t matrix_attenuationxyz =
769 {0.5, 0.0, 0.0, 0.5},
770 {0.0, 0.5, 0.0, 0.5},
771 {0.0, 0.0, 0.5, 0.5},
776 matrix4x4_t matrix_attenuationz =
779 {0.0, 0.0, 0.5, 0.5},
780 {0.0, 0.0, 0.0, 0.5},
781 {0.0, 0.0, 0.0, 0.5},
786 void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles, int vertscale, int triscale)
788 numvertices = ((numvertices + 255) & ~255) * vertscale;
789 numtriangles = ((numtriangles + 255) & ~255) * triscale;
790 // make sure shadowelements is big enough for this volume
791 if (maxshadowtriangles < numtriangles)
793 maxshadowtriangles = numtriangles;
795 Mem_Free(shadowelements);
796 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[3]));
798 // make sure shadowvertex3f is big enough for this volume
799 if (maxshadowvertices < numvertices)
801 maxshadowvertices = numvertices;
803 Mem_Free(shadowvertex3f);
804 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[3]));
808 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
810 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
811 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
812 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
813 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
814 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
816 if (r_shadow_buffer_visitingleafpvs)
817 Mem_Free(r_shadow_buffer_visitingleafpvs);
818 if (r_shadow_buffer_leafpvs)
819 Mem_Free(r_shadow_buffer_leafpvs);
820 if (r_shadow_buffer_leaflist)
821 Mem_Free(r_shadow_buffer_leaflist);
822 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
823 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
824 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
825 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
827 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
829 if (r_shadow_buffer_surfacepvs)
830 Mem_Free(r_shadow_buffer_surfacepvs);
831 if (r_shadow_buffer_surfacelist)
832 Mem_Free(r_shadow_buffer_surfacelist);
833 if (r_shadow_buffer_surfacesides)
834 Mem_Free(r_shadow_buffer_surfacesides);
835 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
836 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
837 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
838 r_shadow_buffer_surfacesides = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
840 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
842 if (r_shadow_buffer_shadowtrispvs)
843 Mem_Free(r_shadow_buffer_shadowtrispvs);
844 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
845 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
847 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
849 if (r_shadow_buffer_lighttrispvs)
850 Mem_Free(r_shadow_buffer_lighttrispvs);
851 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
852 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
856 void R_Shadow_PrepareShadowMark(int numtris)
858 // make sure shadowmark is big enough for this volume
859 if (maxshadowmark < numtris)
861 maxshadowmark = numtris;
863 Mem_Free(shadowmark);
865 Mem_Free(shadowmarklist);
866 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
867 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
871 // if shadowmarkcount wrapped we clear the array and adjust accordingly
872 if (shadowmarkcount == 0)
875 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
880 void R_Shadow_PrepareShadowSides(int numtris)
882 if (maxshadowsides < numtris)
884 maxshadowsides = numtris;
886 Mem_Free(shadowsides);
888 Mem_Free(shadowsideslist);
889 shadowsides = (unsigned char *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsides));
890 shadowsideslist = (int *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsideslist));
895 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)
898 int outtriangles = 0, outvertices = 0;
901 float ratio, direction[3], projectvector[3];
903 if (projectdirection)
904 VectorScale(projectdirection, projectdistance, projectvector);
906 VectorClear(projectvector);
908 // create the vertices
909 if (projectdirection)
911 for (i = 0;i < numshadowmarktris;i++)
913 element = inelement3i + shadowmarktris[i] * 3;
914 for (j = 0;j < 3;j++)
916 if (vertexupdate[element[j]] != vertexupdatenum)
918 vertexupdate[element[j]] = vertexupdatenum;
919 vertexremap[element[j]] = outvertices;
920 vertex = invertex3f + element[j] * 3;
921 // project one copy of the vertex according to projectvector
922 VectorCopy(vertex, outvertex3f);
923 VectorAdd(vertex, projectvector, (outvertex3f + 3));
932 for (i = 0;i < numshadowmarktris;i++)
934 element = inelement3i + shadowmarktris[i] * 3;
935 for (j = 0;j < 3;j++)
937 if (vertexupdate[element[j]] != vertexupdatenum)
939 vertexupdate[element[j]] = vertexupdatenum;
940 vertexremap[element[j]] = outvertices;
941 vertex = invertex3f + element[j] * 3;
942 // project one copy of the vertex to the sphere radius of the light
943 // (FIXME: would projecting it to the light box be better?)
944 VectorSubtract(vertex, projectorigin, direction);
945 ratio = projectdistance / VectorLength(direction);
946 VectorCopy(vertex, outvertex3f);
947 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
955 if (r_shadow_frontsidecasting.integer)
957 for (i = 0;i < numshadowmarktris;i++)
959 int remappedelement[3];
961 const int *neighbortriangle;
963 markindex = shadowmarktris[i] * 3;
964 element = inelement3i + markindex;
965 neighbortriangle = inneighbor3i + markindex;
966 // output the front and back triangles
967 outelement3i[0] = vertexremap[element[0]];
968 outelement3i[1] = vertexremap[element[1]];
969 outelement3i[2] = vertexremap[element[2]];
970 outelement3i[3] = vertexremap[element[2]] + 1;
971 outelement3i[4] = vertexremap[element[1]] + 1;
972 outelement3i[5] = vertexremap[element[0]] + 1;
976 // output the sides (facing outward from this triangle)
977 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
979 remappedelement[0] = vertexremap[element[0]];
980 remappedelement[1] = vertexremap[element[1]];
981 outelement3i[0] = remappedelement[1];
982 outelement3i[1] = remappedelement[0];
983 outelement3i[2] = remappedelement[0] + 1;
984 outelement3i[3] = remappedelement[1];
985 outelement3i[4] = remappedelement[0] + 1;
986 outelement3i[5] = remappedelement[1] + 1;
991 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
993 remappedelement[1] = vertexremap[element[1]];
994 remappedelement[2] = vertexremap[element[2]];
995 outelement3i[0] = remappedelement[2];
996 outelement3i[1] = remappedelement[1];
997 outelement3i[2] = remappedelement[1] + 1;
998 outelement3i[3] = remappedelement[2];
999 outelement3i[4] = remappedelement[1] + 1;
1000 outelement3i[5] = remappedelement[2] + 1;
1005 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1007 remappedelement[0] = vertexremap[element[0]];
1008 remappedelement[2] = vertexremap[element[2]];
1009 outelement3i[0] = remappedelement[0];
1010 outelement3i[1] = remappedelement[2];
1011 outelement3i[2] = remappedelement[2] + 1;
1012 outelement3i[3] = remappedelement[0];
1013 outelement3i[4] = remappedelement[2] + 1;
1014 outelement3i[5] = remappedelement[0] + 1;
1023 for (i = 0;i < numshadowmarktris;i++)
1025 int remappedelement[3];
1027 const int *neighbortriangle;
1029 markindex = shadowmarktris[i] * 3;
1030 element = inelement3i + markindex;
1031 neighbortriangle = inneighbor3i + markindex;
1032 // output the front and back triangles
1033 outelement3i[0] = vertexremap[element[2]];
1034 outelement3i[1] = vertexremap[element[1]];
1035 outelement3i[2] = vertexremap[element[0]];
1036 outelement3i[3] = vertexremap[element[0]] + 1;
1037 outelement3i[4] = vertexremap[element[1]] + 1;
1038 outelement3i[5] = vertexremap[element[2]] + 1;
1042 // output the sides (facing outward from this triangle)
1043 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
1045 remappedelement[0] = vertexremap[element[0]];
1046 remappedelement[1] = vertexremap[element[1]];
1047 outelement3i[0] = remappedelement[0];
1048 outelement3i[1] = remappedelement[1];
1049 outelement3i[2] = remappedelement[1] + 1;
1050 outelement3i[3] = remappedelement[0];
1051 outelement3i[4] = remappedelement[1] + 1;
1052 outelement3i[5] = remappedelement[0] + 1;
1057 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1059 remappedelement[1] = vertexremap[element[1]];
1060 remappedelement[2] = vertexremap[element[2]];
1061 outelement3i[0] = remappedelement[1];
1062 outelement3i[1] = remappedelement[2];
1063 outelement3i[2] = remappedelement[2] + 1;
1064 outelement3i[3] = remappedelement[1];
1065 outelement3i[4] = remappedelement[2] + 1;
1066 outelement3i[5] = remappedelement[1] + 1;
1071 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1073 remappedelement[0] = vertexremap[element[0]];
1074 remappedelement[2] = vertexremap[element[2]];
1075 outelement3i[0] = remappedelement[2];
1076 outelement3i[1] = remappedelement[0];
1077 outelement3i[2] = remappedelement[0] + 1;
1078 outelement3i[3] = remappedelement[2];
1079 outelement3i[4] = remappedelement[0] + 1;
1080 outelement3i[5] = remappedelement[2] + 1;
1088 *outnumvertices = outvertices;
1089 return outtriangles;
1092 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)
1095 int outtriangles = 0, outvertices = 0;
1097 const float *vertex;
1098 float ratio, direction[3], projectvector[3];
1101 if (projectdirection)
1102 VectorScale(projectdirection, projectdistance, projectvector);
1104 VectorClear(projectvector);
1106 for (i = 0;i < numshadowmarktris;i++)
1108 int remappedelement[3];
1110 const int *neighbortriangle;
1112 markindex = shadowmarktris[i] * 3;
1113 neighbortriangle = inneighbor3i + markindex;
1114 side[0] = shadowmark[neighbortriangle[0]] == shadowmarkcount;
1115 side[1] = shadowmark[neighbortriangle[1]] == shadowmarkcount;
1116 side[2] = shadowmark[neighbortriangle[2]] == shadowmarkcount;
1117 if (side[0] + side[1] + side[2] == 0)
1121 element = inelement3i + markindex;
1123 // create the vertices
1124 for (j = 0;j < 3;j++)
1126 if (side[j] + side[j+1] == 0)
1129 if (vertexupdate[k] != vertexupdatenum)
1131 vertexupdate[k] = vertexupdatenum;
1132 vertexremap[k] = outvertices;
1133 vertex = invertex3f + k * 3;
1134 VectorCopy(vertex, outvertex3f);
1135 if (projectdirection)
1137 // project one copy of the vertex according to projectvector
1138 VectorAdd(vertex, projectvector, (outvertex3f + 3));
1142 // project one copy of the vertex to the sphere radius of the light
1143 // (FIXME: would projecting it to the light box be better?)
1144 VectorSubtract(vertex, projectorigin, direction);
1145 ratio = projectdistance / VectorLength(direction);
1146 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1153 // output the sides (facing outward from this triangle)
1156 remappedelement[0] = vertexremap[element[0]];
1157 remappedelement[1] = vertexremap[element[1]];
1158 outelement3i[0] = remappedelement[1];
1159 outelement3i[1] = remappedelement[0];
1160 outelement3i[2] = remappedelement[0] + 1;
1161 outelement3i[3] = remappedelement[1];
1162 outelement3i[4] = remappedelement[0] + 1;
1163 outelement3i[5] = remappedelement[1] + 1;
1170 remappedelement[1] = vertexremap[element[1]];
1171 remappedelement[2] = vertexremap[element[2]];
1172 outelement3i[0] = remappedelement[2];
1173 outelement3i[1] = remappedelement[1];
1174 outelement3i[2] = remappedelement[1] + 1;
1175 outelement3i[3] = remappedelement[2];
1176 outelement3i[4] = remappedelement[1] + 1;
1177 outelement3i[5] = remappedelement[2] + 1;
1184 remappedelement[0] = vertexremap[element[0]];
1185 remappedelement[2] = vertexremap[element[2]];
1186 outelement3i[0] = remappedelement[0];
1187 outelement3i[1] = remappedelement[2];
1188 outelement3i[2] = remappedelement[2] + 1;
1189 outelement3i[3] = remappedelement[0];
1190 outelement3i[4] = remappedelement[2] + 1;
1191 outelement3i[5] = remappedelement[0] + 1;
1198 *outnumvertices = outvertices;
1199 return outtriangles;
1202 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)
1208 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1210 tend = firsttriangle + numtris;
1211 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1213 // surface box entirely inside light box, no box cull
1214 if (projectdirection)
1216 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1218 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
1219 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1220 shadowmarklist[numshadowmark++] = t;
1225 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1226 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
1227 shadowmarklist[numshadowmark++] = t;
1232 // surface box not entirely inside light box, cull each triangle
1233 if (projectdirection)
1235 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1237 v[0] = invertex3f + e[0] * 3;
1238 v[1] = invertex3f + e[1] * 3;
1239 v[2] = invertex3f + e[2] * 3;
1240 TriangleNormal(v[0], v[1], v[2], normal);
1241 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1242 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1243 shadowmarklist[numshadowmark++] = t;
1248 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1250 v[0] = invertex3f + e[0] * 3;
1251 v[1] = invertex3f + e[1] * 3;
1252 v[2] = invertex3f + e[2] * 3;
1253 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1254 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1255 shadowmarklist[numshadowmark++] = t;
1261 qboolean R_Shadow_UseZPass(vec3_t mins, vec3_t maxs)
1266 if (r_shadow_compilingrtlight || !r_shadow_frontsidecasting.integer || !r_shadow_usezpassifpossible.integer)
1268 // check if the shadow volume intersects the near plane
1270 // a ray between the eye and light origin may intersect the caster,
1271 // indicating that the shadow may touch the eye location, however we must
1272 // test the near plane (a polygon), not merely the eye location, so it is
1273 // easiest to enlarge the caster bounding shape slightly for this.
1279 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)
1281 int i, tris, outverts;
1282 if (projectdistance < 0.1)
1284 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
1287 if (!numverts || !nummarktris)
1289 // make sure shadowelements is big enough for this volume
1290 if (maxshadowtriangles < nummarktris*8 || maxshadowvertices < numverts*2)
1291 R_Shadow_ResizeShadowArrays(numverts, nummarktris, 2, 8);
1293 if (maxvertexupdate < numverts)
1295 maxvertexupdate = numverts;
1297 Mem_Free(vertexupdate);
1299 Mem_Free(vertexremap);
1300 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1301 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1302 vertexupdatenum = 0;
1305 if (vertexupdatenum == 0)
1307 vertexupdatenum = 1;
1308 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
1309 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
1312 for (i = 0;i < nummarktris;i++)
1313 shadowmark[marktris[i]] = shadowmarkcount;
1315 if (r_shadow_compilingrtlight)
1317 // if we're compiling an rtlight, capture the mesh
1318 //tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1319 //Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zpass, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1320 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1321 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zfail, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1323 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
1325 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1326 R_Mesh_VertexPointer(shadowvertex3f, 0, 0);
1327 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1331 // decide which type of shadow to generate and set stencil mode
1332 R_Shadow_RenderMode_StencilShadowVolumes(R_Shadow_UseZPass(trismins, trismaxs));
1333 // generate the sides or a solid volume, depending on type
1334 if (r_shadow_rendermode >= R_SHADOW_RENDERMODE_ZPASS_STENCIL && r_shadow_rendermode <= R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE)
1335 tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1337 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1338 r_refdef.stats.lights_dynamicshadowtriangles += tris;
1339 r_refdef.stats.lights_shadowtriangles += tris;
1341 R_Mesh_VertexPointer(shadowvertex3f, 0, 0);
1342 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
1344 // increment stencil if frontface is infront of depthbuffer
1345 GL_CullFace(r_refdef.view.cullface_front);
1346 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1347 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1348 // decrement stencil if backface is infront of depthbuffer
1349 GL_CullFace(r_refdef.view.cullface_back);
1350 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1352 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
1354 // decrement stencil if backface is behind depthbuffer
1355 GL_CullFace(r_refdef.view.cullface_front);
1356 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1357 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1358 // increment stencil if frontface is behind depthbuffer
1359 GL_CullFace(r_refdef.view.cullface_back);
1360 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1362 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1367 int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias)
1369 // p1, p2, p3 are in the cubemap's local coordinate system
1370 // bias = border/(size - border)
1373 float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1374 dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2),
1375 dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3);
1376 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1378 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1379 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1380 | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1381 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1383 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1384 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1385 | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1387 dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1388 dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2),
1389 dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3);
1390 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1392 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1393 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1394 | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1395 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1397 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1398 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1399 | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1401 dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1402 dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2),
1403 dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3);
1404 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1406 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1407 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1408 | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1409 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1411 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1412 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1413 | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1418 int R_Shadow_CalcBBoxSideMask(const vec3_t mins, const vec3_t maxs, const matrix4x4_t *worldtolight, const matrix4x4_t *radiustolight, float bias)
1420 vec3_t center, radius, lightcenter, lightradius, pmin, pmax;
1421 float dp1, dn1, ap1, an1, dp2, dn2, ap2, an2;
1424 VectorSubtract(maxs, mins, radius);
1425 VectorScale(radius, 0.5f, radius);
1426 VectorAdd(mins, radius, center);
1427 Matrix4x4_Transform(worldtolight, center, lightcenter);
1428 Matrix4x4_Transform3x3(radiustolight, radius, lightradius);
1429 VectorSubtract(lightcenter, lightradius, pmin);
1430 VectorAdd(lightcenter, lightradius, pmax);
1432 dp1 = pmax[0] + pmax[1], dn1 = pmax[0] - pmin[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1433 dp2 = pmin[0] + pmin[1], dn2 = pmin[0] - pmax[1], ap2 = fabs(dp2), an2 = fabs(dn2);
1434 if(ap1 > bias*an1 && ap2 > bias*an2)
1436 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1437 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1438 if(an1 > bias*ap1 && an2 > bias*ap2)
1440 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1441 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1443 dp1 = pmax[1] + pmax[2], dn1 = pmax[1] - pmin[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1444 dp2 = pmin[1] + pmin[2], dn2 = pmin[1] - pmax[2], ap2 = fabs(dp2), an2 = fabs(dn2);
1445 if(ap1 > bias*an1 && ap2 > bias*an2)
1447 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1448 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1449 if(an1 > bias*ap1 && an2 > bias*ap2)
1451 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1452 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1454 dp1 = pmax[2] + pmax[0], dn1 = pmax[2] - pmin[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1455 dp2 = pmin[2] + pmin[0], dn2 = pmin[2] - pmax[0], ap2 = fabs(dp2), an2 = fabs(dn2);
1456 if(ap1 > bias*an1 && ap2 > bias*an2)
1458 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1459 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1460 if(an1 > bias*ap1 && an2 > bias*ap2)
1462 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1463 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1468 #define R_Shadow_CalcEntitySideMask(ent, worldtolight, radiustolight, bias) R_Shadow_CalcBBoxSideMask((ent)->mins, (ent)->maxs, worldtolight, radiustolight, bias)
1470 int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
1472 // p is in the cubemap's local coordinate system
1473 // bias = border/(size - border)
1474 float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn);
1475 float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn);
1476 float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn);
1478 if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
1479 if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
1480 if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
1481 if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
1482 if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
1483 if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
1487 int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
1491 int sides = 0x3F, masks[6] = { 3<<4, 3<<4, 3<<0, 3<<0, 3<<2, 3<<2 };
1492 float scale = (size - 2*border)/size, len;
1493 float bias = border / (float)(size - border), dp, dn, ap, an;
1494 // check if cone enclosing side would cross frustum plane
1495 scale = 2 / (scale*scale + 2);
1496 for (i = 0;i < 5;i++)
1498 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) > -0.03125)
1500 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[i].normal, n);
1501 len = scale*VectorLength2(n);
1502 if(n[0]*n[0] > len) sides &= n[0] < 0 ? ~(1<<0) : ~(2 << 0);
1503 if(n[1]*n[1] > len) sides &= n[1] < 0 ? ~(1<<2) : ~(2 << 2);
1504 if(n[2]*n[2] > len) sides &= n[2] < 0 ? ~(1<<4) : ~(2 << 4);
1506 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[4]) >= r_refdef.farclip - r_refdef.nearclip + 0.03125)
1508 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[4].normal, n);
1509 len = scale*VectorLength(n);
1510 if(n[0]*n[0] > len) sides &= n[0] >= 0 ? ~(1<<0) : ~(2 << 0);
1511 if(n[1]*n[1] > len) sides &= n[1] >= 0 ? ~(1<<2) : ~(2 << 2);
1512 if(n[2]*n[2] > len) sides &= n[2] >= 0 ? ~(1<<4) : ~(2 << 4);
1514 // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results
1515 // check if frustum corners/origin cross plane sides
1517 // infinite version, assumes frustum corners merely give direction and extend to infinite distance
1518 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.origin, p);
1519 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1520 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1521 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1522 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1523 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1524 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1525 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1526 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1527 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1528 for (i = 0;i < 4;i++)
1530 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.frustumcorner[i], n);
1531 VectorSubtract(n, p, n);
1532 dp = n[0] + n[1], dn = n[0] - n[1], ap = fabs(dp), an = fabs(dn);
1533 if(ap > 0) masks[0] |= dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2);
1534 if(an > 0) masks[1] |= dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2);
1535 dp = n[1] + n[2], dn = n[1] - n[2], ap = fabs(dp), an = fabs(dn);
1536 if(ap > 0) masks[2] |= dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4);
1537 if(an > 0) masks[3] |= dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4);
1538 dp = n[2] + n[0], dn = n[2] - n[0], ap = fabs(dp), an = fabs(dn);
1539 if(ap > 0) masks[4] |= dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0);
1540 if(an > 0) masks[5] |= dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0);
1543 // finite version, assumes corners are a finite distance from origin dependent on far plane
1544 for (i = 0;i < 5;i++)
1546 Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p);
1547 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1548 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1549 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1550 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1551 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1552 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1553 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1554 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1555 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1558 return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5];
1561 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)
1569 int mask, surfacemask = 0;
1570 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1572 bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
1573 tend = firsttriangle + numtris;
1574 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1576 // surface box entirely inside light box, no box cull
1577 if (projectdirection)
1579 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1581 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1582 TriangleNormal(v[0], v[1], v[2], normal);
1583 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1585 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1586 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1587 surfacemask |= mask;
1590 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;
1591 shadowsides[numshadowsides] = mask;
1592 shadowsideslist[numshadowsides++] = t;
1599 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1601 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1602 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]))
1604 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1605 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1606 surfacemask |= mask;
1609 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;
1610 shadowsides[numshadowsides] = mask;
1611 shadowsideslist[numshadowsides++] = t;
1619 // surface box not entirely inside light box, cull each triangle
1620 if (projectdirection)
1622 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1624 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1625 TriangleNormal(v[0], v[1], v[2], normal);
1626 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1627 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1629 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1630 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1631 surfacemask |= mask;
1634 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;
1635 shadowsides[numshadowsides] = mask;
1636 shadowsideslist[numshadowsides++] = t;
1643 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1645 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1646 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1647 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1649 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1650 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1651 surfacemask |= mask;
1654 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;
1655 shadowsides[numshadowsides] = mask;
1656 shadowsideslist[numshadowsides++] = t;
1665 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)
1667 int i, j, outtriangles = 0;
1668 int *outelement3i[6];
1669 if (!numverts || !numsidetris || !r_shadow_compilingrtlight)
1671 outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5];
1672 // make sure shadowelements is big enough for this mesh
1673 if (maxshadowtriangles < outtriangles)
1674 R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1);
1676 // compute the offset and size of the separate index lists for each cubemap side
1678 for (i = 0;i < 6;i++)
1680 outelement3i[i] = shadowelements + outtriangles * 3;
1681 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles;
1682 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i];
1683 outtriangles += sidetotals[i];
1686 // gather up the (sparse) triangles into separate index lists for each cubemap side
1687 for (i = 0;i < numsidetris;i++)
1689 const int *element = elements + sidetris[i] * 3;
1690 for (j = 0;j < 6;j++)
1692 if (sides[i] & (1 << j))
1694 outelement3i[j][0] = element[0];
1695 outelement3i[j][1] = element[1];
1696 outelement3i[j][2] = element[2];
1697 outelement3i[j] += 3;
1702 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, outtriangles, shadowelements);
1705 static void R_Shadow_MakeTextures_MakeCorona(void)
1709 unsigned char pixels[32][32][4];
1710 for (y = 0;y < 32;y++)
1712 dy = (y - 15.5f) * (1.0f / 16.0f);
1713 for (x = 0;x < 32;x++)
1715 dx = (x - 15.5f) * (1.0f / 16.0f);
1716 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1717 a = bound(0, a, 255);
1718 pixels[y][x][0] = a;
1719 pixels[y][x][1] = a;
1720 pixels[y][x][2] = a;
1721 pixels[y][x][3] = 255;
1724 r_shadow_lightcorona = R_SkinFrame_LoadInternalBGRA("lightcorona", TEXF_FORCELINEAR, &pixels[0][0][0], 32, 32);
1727 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1729 float dist = sqrt(x*x+y*y+z*z);
1730 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1731 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1732 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1735 static void R_Shadow_MakeTextures(void)
1738 float intensity, dist;
1740 R_Shadow_FreeShadowMaps();
1741 R_FreeTexturePool(&r_shadow_texturepool);
1742 r_shadow_texturepool = R_AllocTexturePool();
1743 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1744 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1745 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1746 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1747 for (x = 0;x <= ATTENTABLESIZE;x++)
1749 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1750 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1751 r_shadow_attentable[x] = bound(0, intensity, 1);
1753 // 1D gradient texture
1754 for (x = 0;x < ATTEN1DSIZE;x++)
1755 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1756 r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, NULL);
1757 // 2D circle texture
1758 for (y = 0;y < ATTEN2DSIZE;y++)
1759 for (x = 0;x < ATTEN2DSIZE;x++)
1760 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);
1761 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, NULL);
1762 // 3D sphere texture
1763 if (r_shadow_texture3d.integer && vid.support.ext_texture_3d)
1765 for (z = 0;z < ATTEN3DSIZE;z++)
1766 for (y = 0;y < ATTEN3DSIZE;y++)
1767 for (x = 0;x < ATTEN3DSIZE;x++)
1768 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));
1769 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, NULL);
1772 r_shadow_attenuation3dtexture = NULL;
1775 R_Shadow_MakeTextures_MakeCorona();
1777 // Editor light sprites
1778 r_editlights_sprcursor = R_SkinFrame_LoadInternal8bit("gfx/editlights/cursor", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1795 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1796 r_editlights_sprlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/light", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1813 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1814 r_editlights_sprnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/noshadow", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1831 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1832 r_editlights_sprcubemaplight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemaplight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1849 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1850 r_editlights_sprcubemapnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemapnoshadowlight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1867 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1868 r_editlights_sprselection = R_SkinFrame_LoadInternal8bit("gfx/editlights/selection", TEXF_ALPHA | TEXF_CLAMP, (unsigned char *)
1885 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1888 void R_Shadow_ValidateCvars(void)
1890 if (r_shadow_texture3d.integer && !vid.support.ext_texture_3d)
1891 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1892 if (gl_ext_separatestencil.integer && !vid.support.ati_separate_stencil)
1893 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
1894 if (gl_ext_stenciltwoside.integer && !vid.support.ext_stencil_two_side)
1895 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1898 void R_Shadow_RenderMode_Begin(void)
1904 R_Shadow_ValidateCvars();
1906 if (!r_shadow_attenuation2dtexture
1907 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1908 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1909 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1910 R_Shadow_MakeTextures();
1913 R_Mesh_ColorPointer(NULL, 0, 0);
1914 R_Mesh_ResetTextureState();
1915 GL_BlendFunc(GL_ONE, GL_ZERO);
1916 GL_DepthRange(0, 1);
1917 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1919 GL_DepthMask(false);
1920 GL_Color(0, 0, 0, 1);
1921 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1923 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1925 if (gl_ext_separatestencil.integer && vid.support.ati_separate_stencil)
1927 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
1928 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
1930 else if (gl_ext_stenciltwoside.integer && vid.support.ext_stencil_two_side)
1932 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
1933 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
1937 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
1938 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
1941 switch(vid.renderpath)
1943 case RENDERPATH_GL20:
1944 case RENDERPATH_CGGL:
1945 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1947 case RENDERPATH_GL13:
1948 case RENDERPATH_GL11:
1949 if (r_textureunits.integer >= 2 && vid.texunits >= 2 && r_shadow_texture3d.integer && r_shadow_attenuation3dtexture)
1950 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN;
1951 else if (r_textureunits.integer >= 3 && vid.texunits >= 3)
1952 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN;
1953 else if (r_textureunits.integer >= 2 && vid.texunits >= 2)
1954 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN;
1956 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1962 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
1963 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
1964 r_shadow_drawbuffer = drawbuffer;
1965 r_shadow_readbuffer = readbuffer;
1967 r_shadow_cullface_front = r_refdef.view.cullface_front;
1968 r_shadow_cullface_back = r_refdef.view.cullface_back;
1971 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
1973 rsurface.rtlight = rtlight;
1976 void R_Shadow_RenderMode_Reset(void)
1979 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE)
1981 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1983 if (vid.support.ext_framebuffer_object)
1985 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);CHECKGLERROR
1988 qglDrawBuffer(r_shadow_drawbuffer);CHECKGLERROR
1989 qglReadBuffer(r_shadow_readbuffer);CHECKGLERROR
1991 R_SetViewport(&r_refdef.view.viewport);
1992 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
1993 R_Mesh_ColorPointer(NULL, 0, 0);
1994 R_Mesh_ResetTextureState();
1995 GL_DepthRange(0, 1);
1997 GL_DepthMask(false);
1998 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1999 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
2000 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
2001 qglStencilMask(255);CHECKGLERROR
2002 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
2003 qglStencilFunc(GL_ALWAYS, 128, 255);CHECKGLERROR
2004 r_refdef.view.cullface_front = r_shadow_cullface_front;
2005 r_refdef.view.cullface_back = r_shadow_cullface_back;
2006 GL_CullFace(r_refdef.view.cullface_back);
2007 GL_Color(1, 1, 1, 1);
2008 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
2009 GL_BlendFunc(GL_ONE, GL_ZERO);
2010 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
2011 r_shadow_usingshadowmaprect = false;
2012 r_shadow_usingshadowmapcube = false;
2013 r_shadow_usingshadowmap2d = false;
2014 r_shadow_usingshadowmaportho = false;
2018 void R_Shadow_ClearStencil(void)
2021 GL_Clear(GL_STENCIL_BUFFER_BIT);
2022 r_refdef.stats.lights_clears++;
2025 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
2027 r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
2028 if (r_shadow_rendermode == mode)
2031 R_Shadow_RenderMode_Reset();
2032 GL_ColorMask(0, 0, 0, 0);
2033 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2034 R_SetupShader_DepthOrShadow();
2035 qglDepthFunc(GL_LESS);CHECKGLERROR
2036 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2037 r_shadow_rendermode = mode;
2042 case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
2043 GL_CullFace(GL_NONE);
2044 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
2045 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
2047 case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
2048 GL_CullFace(GL_NONE);
2049 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
2050 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
2052 case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
2053 GL_CullFace(GL_NONE);
2054 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
2055 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
2056 qglStencilMask(255);CHECKGLERROR
2057 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
2058 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
2059 qglStencilMask(255);CHECKGLERROR
2060 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
2062 case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
2063 GL_CullFace(GL_NONE);
2064 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
2065 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
2066 qglStencilMask(255);CHECKGLERROR
2067 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
2068 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
2069 qglStencilMask(255);CHECKGLERROR
2070 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
2075 static void R_Shadow_MakeVSDCT(void)
2077 // maps to a 2x3 texture rectangle with normalized coordinates
2082 // stores abs(dir.xy), offset.xy/2.5
2083 unsigned char data[4*6] =
2085 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
2086 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
2087 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
2088 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
2089 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
2090 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
2092 r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, NULL);
2095 static void R_Shadow_MakeShadowMap(int side, int size)
2098 switch (r_shadow_shadowmode)
2100 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2101 if (r_shadow_shadowmap2dtexture) return;
2102 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);
2103 qglGenFramebuffersEXT(1, &r_shadow_fbo2d);CHECKGLERROR
2104 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbo2d);CHECKGLERROR
2105 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_shadowmap2dtexture), 0);CHECKGLERROR
2107 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
2108 if (r_shadow_shadowmaprectangletexture) return;
2109 r_shadow_shadowmaprectangletexture = R_LoadTextureShadowMapRectangle(r_shadow_texturepool, "shadowmap", size*2, size*3, r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
2110 qglGenFramebuffersEXT(1, &r_shadow_fborectangle);CHECKGLERROR
2111 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fborectangle);CHECKGLERROR
2112 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, R_GetTexture(r_shadow_shadowmaprectangletexture), 0);CHECKGLERROR
2114 case R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE:
2115 if (r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]) return;
2116 r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod] = R_LoadTextureShadowMapCube(r_shadow_texturepool, "shadowmapcube", size, r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
2117 qglGenFramebuffersEXT(1, &r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR
2118 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR
2119 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
2124 // render depth into the fbo, do not render color at all
2125 qglDrawBuffer(GL_NONE);CHECKGLERROR
2126 qglReadBuffer(GL_NONE);CHECKGLERROR
2127 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2128 if (status != GL_FRAMEBUFFER_COMPLETE_EXT && (r_shadow_shadowmapping.integer || r_shadow_deferred.integer))
2130 Con_Printf("R_Shadow_MakeShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2131 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2132 Cvar_SetValueQuick(&r_shadow_deferred, 0);
2136 void R_Shadow_RenderMode_ShadowMap(int side, int clear, int size)
2138 float nearclip, farclip, bias;
2139 r_viewport_t viewport;
2143 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
2145 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
2146 r_shadow_shadowmap_parameters[1] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
2147 r_shadow_shadowmap_parameters[3] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
2148 r_shadow_shadowmapside = side;
2149 r_shadow_shadowmapsize = size;
2150 switch (r_shadow_shadowmode)
2152 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2153 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2154 r_shadow_shadowmap_parameters[2] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2155 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
2156 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D) goto init_done;
2158 // complex unrolled cube approach (more flexible)
2159 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2160 R_Shadow_MakeVSDCT();
2161 if (!r_shadow_shadowmap2dtexture)
2162 R_Shadow_MakeShadowMap(side, r_shadow_shadowmapmaxsize);
2164 if (r_shadow_shadowmap2dtexture) fbo = r_shadow_fbo2d;
2165 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
2166 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
2167 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
2169 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
2170 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2171 r_shadow_shadowmap_parameters[2] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2172 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
2173 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE) goto init_done;
2175 // complex unrolled cube approach (more flexible)
2176 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2177 R_Shadow_MakeVSDCT();
2178 if (!r_shadow_shadowmaprectangletexture)
2179 R_Shadow_MakeShadowMap(side, r_shadow_shadowmapmaxsize);
2181 if(r_shadow_shadowmaprectangletexture) fbo = r_shadow_fborectangle;
2182 r_shadow_shadowmap_texturescale[0] = 1.0f;
2183 r_shadow_shadowmap_texturescale[1] = 1.0f;
2184 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE;
2186 case R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE:
2187 r_shadow_shadowmap_parameters[0] = 1.0f;
2188 r_shadow_shadowmap_parameters[2] = 1.0f;
2189 R_Viewport_InitCubeSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, nearclip, farclip, NULL);
2190 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE) goto init_done;
2192 // simple cube approach
2193 if (!r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod])
2194 R_Shadow_MakeShadowMap(side, size);
2196 if (r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]) fbo = r_shadow_fbocubeside[r_shadow_shadowmaplod];
2197 r_shadow_shadowmap_texturescale[0] = 0.0f;
2198 r_shadow_shadowmap_texturescale[1] = 0.0f;
2199 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE;
2205 R_Shadow_RenderMode_Reset();
2208 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);CHECKGLERROR
2209 R_SetupShader_DepthOrShadow();
2213 R_SetupShader_ShowDepth();
2214 qglClearColor(1,1,1,1);CHECKGLERROR
2217 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
2224 R_SetViewport(&viewport);
2225 switch (r_shadow_rendermode)
2227 case R_SHADOW_RENDERMODE_SHADOWMAP2D:
2228 case R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE:
2229 flipped = (side & 1) ^ (side >> 2);
2230 r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
2231 r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
2232 GL_CullFace(r_refdef.view.cullface_back);
2233 if ((clear & ((2 << side) - 1)) == (1 << side)) // only clear if the side is the first in the mask
2235 // get tightest scissor rectangle that encloses all viewports in the clear mask
2236 int x1 = clear & 0x15 ? 0 : size;
2237 int x2 = clear & 0x2A ? 2 * size : size;
2238 int y1 = clear & 0x03 ? 0 : (clear & 0xC ? size : 2 * size);
2239 int y2 = clear & 0x30 ? 3 * size : (clear & 0xC ? 2 * size : size);
2240 GL_Scissor(x1, y1, x2 - x1, y2 - y1);
2241 GL_Clear(GL_DEPTH_BUFFER_BIT);
2243 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2245 case R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE:
2246 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
2247 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2249 GL_Clear(GL_DEPTH_BUFFER_BIT);
2257 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
2261 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2262 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2263 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2264 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2267 R_Shadow_RenderMode_Reset();
2268 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2271 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2275 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2276 // only draw light where this geometry was already rendered AND the
2277 // stencil is 128 (values other than this mean shadow)
2278 qglStencilFunc(GL_EQUAL, 128, 255);CHECKGLERROR
2280 r_shadow_rendermode = r_shadow_lightingrendermode;
2281 // do global setup needed for the chosen lighting mode
2282 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2284 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2289 switch (r_shadow_shadowmode)
2291 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2292 r_shadow_usingshadowmap2d = true;
2294 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
2295 r_shadow_usingshadowmaprect = true;
2297 case R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE:
2298 r_shadow_usingshadowmapcube = true;
2304 R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
2308 static const unsigned short bboxelements[36] =
2318 static const float bboxpoints[8][3] =
2330 void R_Shadow_RenderMode_DrawDeferredLight(qboolean stenciltest, qboolean shadowmapping)
2333 float vertex3f[8*3];
2334 const matrix4x4_t *matrix = &rsurface.rtlight->matrix_lighttoworld;
2336 R_Shadow_RenderMode_Reset();
2337 r_shadow_rendermode = r_shadow_lightingrendermode;
2338 // do global setup needed for the chosen lighting mode
2340 R_EntityMatrix(&identitymatrix);
2341 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2344 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2345 // only draw light where this geometry was already rendered AND the
2346 // stencil is 128 (values other than this mean shadow)
2347 qglStencilFunc(GL_EQUAL, 128, 255);CHECKGLERROR
2349 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepasslightingfbo);CHECKGLERROR
2352 switch (r_shadow_shadowmode)
2354 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2355 r_shadow_usingshadowmap2d = true;
2357 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
2358 r_shadow_usingshadowmaprect = true;
2360 case R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE:
2361 r_shadow_usingshadowmapcube = true;
2368 // render the lighting
2369 R_SetupShader_DeferredLight(rsurface.rtlight);
2370 for (i = 0;i < 8;i++)
2371 Matrix4x4_Transform(matrix, bboxpoints[i], vertex3f + i*3);
2373 R_Mesh_VertexPointer(vertex3f, 0, 0);
2374 R_Mesh_ColorPointer(NULL, 0, 0);
2375 GL_ColorMask(1,1,1,1);
2376 GL_DepthMask(false);
2377 GL_DepthRange(0, 1);
2378 GL_PolygonOffset(0, 0);
2380 qglDepthFunc(GL_GREATER);CHECKGLERROR
2381 GL_CullFace(r_refdef.view.cullface_back);
2382 R_Mesh_Draw(0, 8, 0, 12, NULL, bboxelements, 0, 0);
2386 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
2389 R_Shadow_RenderMode_Reset();
2390 GL_BlendFunc(GL_ONE, GL_ONE);
2391 GL_DepthRange(0, 1);
2392 GL_DepthTest(r_showshadowvolumes.integer < 2);
2393 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
2394 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2395 GL_CullFace(GL_NONE);
2396 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
2399 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
2402 R_Shadow_RenderMode_Reset();
2403 GL_BlendFunc(GL_ONE, GL_ONE);
2404 GL_DepthRange(0, 1);
2405 GL_DepthTest(r_showlighting.integer < 2);
2406 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2409 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2413 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2414 qglStencilFunc(GL_EQUAL, 128, 255);CHECKGLERROR
2416 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2419 void R_Shadow_RenderMode_End(void)
2422 R_Shadow_RenderMode_Reset();
2423 R_Shadow_RenderMode_ActiveLight(NULL);
2425 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2426 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2429 int bboxedges[12][2] =
2448 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2450 int i, ix1, iy1, ix2, iy2;
2451 float x1, y1, x2, y2;
2453 float vertex[20][3];
2462 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2463 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2464 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2465 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2467 if (!r_shadow_scissor.integer)
2470 // if view is inside the light box, just say yes it's visible
2471 if (BoxesOverlap(r_refdef.view.origin, r_refdef.view.origin, mins, maxs))
2474 x1 = y1 = x2 = y2 = 0;
2476 // transform all corners that are infront of the nearclip plane
2477 VectorNegate(r_refdef.view.frustum[4].normal, plane4f);
2478 plane4f[3] = r_refdef.view.frustum[4].dist;
2480 for (i = 0;i < 8;i++)
2482 Vector4Set(corner[i], (i & 1) ? maxs[0] : mins[0], (i & 2) ? maxs[1] : mins[1], (i & 4) ? maxs[2] : mins[2], 1);
2483 dist[i] = DotProduct4(corner[i], plane4f);
2484 sign[i] = dist[i] > 0;
2487 VectorCopy(corner[i], vertex[numvertices]);
2491 // if some points are behind the nearclip, add clipped edge points to make
2492 // sure that the scissor boundary is complete
2493 if (numvertices > 0 && numvertices < 8)
2495 // add clipped edge points
2496 for (i = 0;i < 12;i++)
2498 j = bboxedges[i][0];
2499 k = bboxedges[i][1];
2500 if (sign[j] != sign[k])
2502 f = dist[j] / (dist[j] - dist[k]);
2503 VectorLerp(corner[j], f, corner[k], vertex[numvertices]);
2509 // if we have no points to check, the light is behind the view plane
2513 // if we have some points to transform, check what screen area is covered
2514 x1 = y1 = x2 = y2 = 0;
2516 //Con_Printf("%i vertices to transform...\n", numvertices);
2517 for (i = 0;i < numvertices;i++)
2519 VectorCopy(vertex[i], v);
2520 R_Viewport_TransformToScreen(&r_refdef.view.viewport, v, v2);
2521 //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]);
2524 if (x1 > v2[0]) x1 = v2[0];
2525 if (x2 < v2[0]) x2 = v2[0];
2526 if (y1 > v2[1]) y1 = v2[1];
2527 if (y2 < v2[1]) y2 = v2[1];
2536 // now convert the scissor rectangle to integer screen coordinates
2537 ix1 = (int)(x1 - 1.0f);
2538 iy1 = vid.height - (int)(y2 - 1.0f);
2539 ix2 = (int)(x2 + 1.0f);
2540 iy2 = vid.height - (int)(y1 + 1.0f);
2541 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
2543 // clamp it to the screen
2544 if (ix1 < r_refdef.view.viewport.x) ix1 = r_refdef.view.viewport.x;
2545 if (iy1 < r_refdef.view.viewport.y) iy1 = r_refdef.view.viewport.y;
2546 if (ix2 > r_refdef.view.viewport.x + r_refdef.view.viewport.width) ix2 = r_refdef.view.viewport.x + r_refdef.view.viewport.width;
2547 if (iy2 > r_refdef.view.viewport.y + r_refdef.view.viewport.height) iy2 = r_refdef.view.viewport.y + r_refdef.view.viewport.height;
2549 // if it is inside out, it's not visible
2550 if (ix2 <= ix1 || iy2 <= iy1)
2553 // the light area is visible, set up the scissor rectangle
2554 r_shadow_lightscissor[0] = ix1;
2555 r_shadow_lightscissor[1] = iy1;
2556 r_shadow_lightscissor[2] = ix2 - ix1;
2557 r_shadow_lightscissor[3] = iy2 - iy1;
2559 r_refdef.stats.lights_scissored++;
2563 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, int numtriangles, const int *element3i, const float *diffusecolor, const float *ambientcolor)
2565 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
2566 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
2567 float *color4f = rsurface.array_color4f + 4 * firstvertex;
2568 float dist, dot, distintensity, shadeintensity, v[3], n[3];
2569 switch (r_shadow_rendermode)
2571 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2572 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2573 if (VectorLength2(diffusecolor) > 0)
2575 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2577 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2578 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2579 if ((dot = DotProduct(n, v)) < 0)
2581 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2582 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
2585 VectorCopy(ambientcolor, color4f);
2586 if (r_refdef.fogenabled)
2589 f = RSurf_FogVertex(vertex3f);
2590 VectorScale(color4f, f, color4f);
2597 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2599 VectorCopy(ambientcolor, color4f);
2600 if (r_refdef.fogenabled)
2603 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2604 f = RSurf_FogVertex(vertex3f);
2605 VectorScale(color4f, f, color4f);
2611 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2612 if (VectorLength2(diffusecolor) > 0)
2614 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2616 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2617 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2619 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2620 if ((dot = DotProduct(n, v)) < 0)
2622 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2623 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2624 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2625 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2629 color4f[0] = ambientcolor[0] * distintensity;
2630 color4f[1] = ambientcolor[1] * distintensity;
2631 color4f[2] = ambientcolor[2] * distintensity;
2633 if (r_refdef.fogenabled)
2636 f = RSurf_FogVertex(vertex3f);
2637 VectorScale(color4f, f, color4f);
2641 VectorClear(color4f);
2647 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2649 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2650 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2652 color4f[0] = ambientcolor[0] * distintensity;
2653 color4f[1] = ambientcolor[1] * distintensity;
2654 color4f[2] = ambientcolor[2] * distintensity;
2655 if (r_refdef.fogenabled)
2658 f = RSurf_FogVertex(vertex3f);
2659 VectorScale(color4f, f, color4f);
2663 VectorClear(color4f);
2668 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2669 if (VectorLength2(diffusecolor) > 0)
2671 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2673 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2674 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2676 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2677 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2678 if ((dot = DotProduct(n, v)) < 0)
2680 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2681 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2682 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2683 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2687 color4f[0] = ambientcolor[0] * distintensity;
2688 color4f[1] = ambientcolor[1] * distintensity;
2689 color4f[2] = ambientcolor[2] * distintensity;
2691 if (r_refdef.fogenabled)
2694 f = RSurf_FogVertex(vertex3f);
2695 VectorScale(color4f, f, color4f);
2699 VectorClear(color4f);
2705 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2707 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2708 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2710 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2711 color4f[0] = ambientcolor[0] * distintensity;
2712 color4f[1] = ambientcolor[1] * distintensity;
2713 color4f[2] = ambientcolor[2] * distintensity;
2714 if (r_refdef.fogenabled)
2717 f = RSurf_FogVertex(vertex3f);
2718 VectorScale(color4f, f, color4f);
2722 VectorClear(color4f);
2732 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)
2734 // used to display how many times a surface is lit for level design purposes
2735 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2738 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)
2740 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2741 R_SetupShader_Surface(lightcolor, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT);
2742 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2744 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2746 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2747 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2749 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
2753 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
2760 int newnumtriangles;
2764 int maxtriangles = 4096;
2765 static int newelements[4096*3];
2766 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, numtriangles, element3i, diffusecolor2, ambientcolor2);
2767 for (renders = 0;renders < 4;renders++)
2772 newnumtriangles = 0;
2774 // due to low fillrate on the cards this vertex lighting path is
2775 // designed for, we manually cull all triangles that do not
2776 // contain a lit vertex
2777 // this builds batches of triangles from multiple surfaces and
2778 // renders them at once
2779 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
2781 if (VectorLength2(rsurface.array_color4f + e[0] * 4) + VectorLength2(rsurface.array_color4f + e[1] * 4) + VectorLength2(rsurface.array_color4f + e[2] * 4) >= 0.01)
2783 if (newnumtriangles)
2785 newfirstvertex = min(newfirstvertex, e[0]);
2786 newlastvertex = max(newlastvertex, e[0]);
2790 newfirstvertex = e[0];
2791 newlastvertex = e[0];
2793 newfirstvertex = min(newfirstvertex, e[1]);
2794 newlastvertex = max(newlastvertex, e[1]);
2795 newfirstvertex = min(newfirstvertex, e[2]);
2796 newlastvertex = max(newlastvertex, e[2]);
2802 if (newnumtriangles >= maxtriangles)
2804 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
2805 newnumtriangles = 0;
2811 if (newnumtriangles >= 1)
2813 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
2816 // if we couldn't find any lit triangles, exit early
2819 // now reduce the intensity for the next overbright pass
2820 // we have to clamp to 0 here incase the drivers have improper
2821 // handling of negative colors
2822 // (some old drivers even have improper handling of >1 color)
2824 for (i = 0, c = rsurface.array_color4f + 4 * firstvertex;i < numvertices;i++, c += 4)
2826 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
2828 c[0] = max(0, c[0] - 1);
2829 c[1] = max(0, c[1] - 1);
2830 c[2] = max(0, c[2] - 1);
2842 static void R_Shadow_RenderLighting_Light_Vertex(int firstvertex, int numvertices, int numtriangles, const int *element3i, const vec3_t lightcolor, float ambientscale, float diffusescale)
2844 // OpenGL 1.1 path (anything)
2845 float ambientcolorbase[3], diffusecolorbase[3];
2846 float ambientcolorpants[3], diffusecolorpants[3];
2847 float ambientcolorshirt[3], diffusecolorshirt[3];
2848 const float *surfacecolor = rsurface.texture->dlightcolor;
2849 const float *surfacepants = rsurface.colormap_pantscolor;
2850 const float *surfaceshirt = rsurface.colormap_shirtcolor;
2851 rtexture_t *basetexture = rsurface.texture->basetexture;
2852 rtexture_t *pantstexture = rsurface.texture->pantstexture;
2853 rtexture_t *shirttexture = rsurface.texture->shirttexture;
2854 qboolean dopants = pantstexture && VectorLength2(surfacepants) >= (1.0f / 1048576.0f);
2855 qboolean doshirt = shirttexture && VectorLength2(surfaceshirt) >= (1.0f / 1048576.0f);
2856 ambientscale *= 2 * r_refdef.view.colorscale;
2857 diffusescale *= 2 * r_refdef.view.colorscale;
2858 ambientcolorbase[0] = lightcolor[0] * ambientscale * surfacecolor[0];ambientcolorbase[1] = lightcolor[1] * ambientscale * surfacecolor[1];ambientcolorbase[2] = lightcolor[2] * ambientscale * surfacecolor[2];
2859 diffusecolorbase[0] = lightcolor[0] * diffusescale * surfacecolor[0];diffusecolorbase[1] = lightcolor[1] * diffusescale * surfacecolor[1];diffusecolorbase[2] = lightcolor[2] * diffusescale * surfacecolor[2];
2860 ambientcolorpants[0] = ambientcolorbase[0] * surfacepants[0];ambientcolorpants[1] = ambientcolorbase[1] * surfacepants[1];ambientcolorpants[2] = ambientcolorbase[2] * surfacepants[2];
2861 diffusecolorpants[0] = diffusecolorbase[0] * surfacepants[0];diffusecolorpants[1] = diffusecolorbase[1] * surfacepants[1];diffusecolorpants[2] = diffusecolorbase[2] * surfacepants[2];
2862 ambientcolorshirt[0] = ambientcolorbase[0] * surfaceshirt[0];ambientcolorshirt[1] = ambientcolorbase[1] * surfaceshirt[1];ambientcolorshirt[2] = ambientcolorbase[2] * surfaceshirt[2];
2863 diffusecolorshirt[0] = diffusecolorbase[0] * surfaceshirt[0];diffusecolorshirt[1] = diffusecolorbase[1] * surfaceshirt[1];diffusecolorshirt[2] = diffusecolorbase[2] * surfaceshirt[2];
2864 R_Mesh_TexBind(0, basetexture);
2865 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
2866 R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
2867 R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
2868 switch(r_shadow_rendermode)
2870 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2871 R_Mesh_TexBind(1, r_shadow_attenuation3dtexture);
2872 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
2873 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
2874 R_Mesh_TexCoordPointer(1, 3, rsurface.vertex3f, rsurface.vertex3f_bufferobject, rsurface.vertex3f_bufferoffset);
2876 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2877 R_Mesh_TexBind(2, r_shadow_attenuation2dtexture);
2878 R_Mesh_TexMatrix(2, &rsurface.entitytoattenuationz);
2879 R_Mesh_TexCombine(2, GL_MODULATE, GL_MODULATE, 1, 1);
2880 R_Mesh_TexCoordPointer(2, 3, rsurface.vertex3f, rsurface.vertex3f_bufferobject, rsurface.vertex3f_bufferoffset);
2882 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2883 R_Mesh_TexBind(1, r_shadow_attenuation2dtexture);
2884 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
2885 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
2886 R_Mesh_TexCoordPointer(1, 3, rsurface.vertex3f, rsurface.vertex3f_bufferobject, rsurface.vertex3f_bufferoffset);
2888 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2893 //R_Mesh_TexBind(0, basetexture);
2894 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorbase, ambientcolorbase);
2897 R_Mesh_TexBind(0, pantstexture);
2898 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorpants, ambientcolorpants);
2902 R_Mesh_TexBind(0, shirttexture);
2903 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorshirt, ambientcolorshirt);
2907 extern cvar_t gl_lightmaps;
2908 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)
2910 float ambientscale, diffusescale, specularscale;
2912 float lightcolor[3];
2913 VectorCopy(rsurface.rtlight->currentcolor, lightcolor);
2914 ambientscale = rsurface.rtlight->ambientscale;
2915 diffusescale = rsurface.rtlight->diffusescale;
2916 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
2917 if (!r_shadow_usenormalmap.integer)
2919 ambientscale += 1.0f * diffusescale;
2923 if ((ambientscale + diffusescale) * VectorLength2(lightcolor) + specularscale * VectorLength2(lightcolor) < (1.0f / 1048576.0f))
2925 negated = (lightcolor[0] + lightcolor[1] + lightcolor[2] < 0) && vid.support.ext_blend_subtract;
2928 VectorNegate(lightcolor, lightcolor);
2929 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
2931 RSurf_SetupDepthAndCulling();
2932 switch (r_shadow_rendermode)
2934 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2935 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2936 R_Shadow_RenderLighting_VisibleLighting(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2938 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2939 R_Shadow_RenderLighting_Light_GLSL(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolor, ambientscale, diffusescale, specularscale);
2941 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2942 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2943 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2944 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2945 R_Shadow_RenderLighting_Light_Vertex(firstvertex, numvertices, numtriangles, element3i + firsttriangle * 3, lightcolor, ambientscale, diffusescale);
2948 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2952 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
2955 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)
2957 matrix4x4_t tempmatrix = *matrix;
2958 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
2960 // if this light has been compiled before, free the associated data
2961 R_RTLight_Uncompile(rtlight);
2963 // clear it completely to avoid any lingering data
2964 memset(rtlight, 0, sizeof(*rtlight));
2966 // copy the properties
2967 rtlight->matrix_lighttoworld = tempmatrix;
2968 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
2969 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
2970 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
2971 VectorCopy(color, rtlight->color);
2972 rtlight->cubemapname[0] = 0;
2973 if (cubemapname && cubemapname[0])
2974 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
2975 rtlight->shadow = shadow;
2976 rtlight->corona = corona;
2977 rtlight->style = style;
2978 rtlight->isstatic = isstatic;
2979 rtlight->coronasizescale = coronasizescale;
2980 rtlight->ambientscale = ambientscale;
2981 rtlight->diffusescale = diffusescale;
2982 rtlight->specularscale = specularscale;
2983 rtlight->flags = flags;
2985 // compute derived data
2986 //rtlight->cullradius = rtlight->radius;
2987 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2988 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2989 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2990 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2991 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2992 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2993 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2996 // compiles rtlight geometry
2997 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2998 void R_RTLight_Compile(rtlight_t *rtlight)
3001 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
3002 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
3003 entity_render_t *ent = r_refdef.scene.worldentity;
3004 dp_model_t *model = r_refdef.scene.worldmodel;
3005 unsigned char *data;
3008 // compile the light
3009 rtlight->compiled = true;
3010 rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
3011 rtlight->static_numleafs = 0;
3012 rtlight->static_numleafpvsbytes = 0;
3013 rtlight->static_leaflist = NULL;
3014 rtlight->static_leafpvs = NULL;
3015 rtlight->static_numsurfaces = 0;
3016 rtlight->static_surfacelist = NULL;
3017 rtlight->static_shadowmap_receivers = 0x3F;
3018 rtlight->static_shadowmap_casters = 0x3F;
3019 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3020 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3021 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3022 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3023 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3024 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3026 if (model && model->GetLightInfo)
3028 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
3029 r_shadow_compilingrtlight = rtlight;
3030 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);
3031 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
3032 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
3033 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3034 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
3035 rtlight->static_numsurfaces = numsurfaces;
3036 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
3037 rtlight->static_numleafs = numleafs;
3038 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
3039 rtlight->static_numleafpvsbytes = numleafpvsbytes;
3040 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
3041 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
3042 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
3043 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
3044 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3045 if (rtlight->static_numsurfaces)
3046 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3047 if (rtlight->static_numleafs)
3048 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3049 if (rtlight->static_numleafpvsbytes)
3050 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3051 if (rtlight->static_numshadowtrispvsbytes)
3052 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3053 if (rtlight->static_numlighttrispvsbytes)
3054 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3055 switch (rtlight->shadowmode)
3057 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
3058 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
3059 case R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE:
3060 if (model->CompileShadowMap && rtlight->shadow)
3061 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3064 if (model->CompileShadowVolume && rtlight->shadow)
3065 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3068 // now we're done compiling the rtlight
3069 r_shadow_compilingrtlight = NULL;
3073 // use smallest available cullradius - box radius or light radius
3074 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3075 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3077 shadowzpasstris = 0;
3078 if (rtlight->static_meshchain_shadow_zpass)
3079 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
3080 shadowzpasstris += mesh->numtriangles;
3082 shadowzfailtris = 0;
3083 if (rtlight->static_meshchain_shadow_zfail)
3084 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
3085 shadowzfailtris += mesh->numtriangles;
3088 if (rtlight->static_numlighttrispvsbytes)
3089 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3090 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3094 if (rtlight->static_numlighttrispvsbytes)
3095 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3096 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3099 if (developer_extra.integer)
3100 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);
3103 void R_RTLight_Uncompile(rtlight_t *rtlight)
3105 if (rtlight->compiled)
3107 if (rtlight->static_meshchain_shadow_zpass)
3108 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
3109 rtlight->static_meshchain_shadow_zpass = NULL;
3110 if (rtlight->static_meshchain_shadow_zfail)
3111 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
3112 rtlight->static_meshchain_shadow_zfail = NULL;
3113 if (rtlight->static_meshchain_shadow_shadowmap)
3114 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
3115 rtlight->static_meshchain_shadow_shadowmap = NULL;
3116 // these allocations are grouped
3117 if (rtlight->static_surfacelist)
3118 Mem_Free(rtlight->static_surfacelist);
3119 rtlight->static_numleafs = 0;
3120 rtlight->static_numleafpvsbytes = 0;
3121 rtlight->static_leaflist = NULL;
3122 rtlight->static_leafpvs = NULL;
3123 rtlight->static_numsurfaces = 0;
3124 rtlight->static_surfacelist = NULL;
3125 rtlight->static_numshadowtrispvsbytes = 0;
3126 rtlight->static_shadowtrispvs = NULL;
3127 rtlight->static_numlighttrispvsbytes = 0;
3128 rtlight->static_lighttrispvs = NULL;
3129 rtlight->compiled = false;
3133 void R_Shadow_UncompileWorldLights(void)
3137 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3138 for (lightindex = 0;lightindex < range;lightindex++)
3140 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3143 R_RTLight_Uncompile(&light->rtlight);
3147 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3151 // reset the count of frustum planes
3152 // see rtlight->cached_frustumplanes definition for how much this array
3154 rtlight->cached_numfrustumplanes = 0;
3156 // haven't implemented a culling path for ortho rendering
3157 if (!r_refdef.view.useperspective)
3159 // check if the light is on screen and copy the 4 planes if it is
3160 for (i = 0;i < 4;i++)
3161 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3164 for (i = 0;i < 4;i++)
3165 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3170 // generate a deformed frustum that includes the light origin, this is
3171 // used to cull shadow casting surfaces that can not possibly cast a
3172 // shadow onto the visible light-receiving surfaces, which can be a
3175 // if the light origin is onscreen the result will be 4 planes exactly
3176 // if the light origin is offscreen on only one axis the result will
3177 // be exactly 5 planes (split-side case)
3178 // if the light origin is offscreen on two axes the result will be
3179 // exactly 4 planes (stretched corner case)
3180 for (i = 0;i < 4;i++)
3182 // quickly reject standard frustum planes that put the light
3183 // origin outside the frustum
3184 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3187 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3189 // if all the standard frustum planes were accepted, the light is onscreen
3190 // otherwise we need to generate some more planes below...
3191 if (rtlight->cached_numfrustumplanes < 4)
3193 // at least one of the stock frustum planes failed, so we need to
3194 // create one or two custom planes to enclose the light origin
3195 for (i = 0;i < 4;i++)
3197 // create a plane using the view origin and light origin, and a
3198 // single point from the frustum corner set
3199 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3200 VectorNormalize(plane.normal);
3201 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3202 // see if this plane is backwards and flip it if so
3203 for (j = 0;j < 4;j++)
3204 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3208 VectorNegate(plane.normal, plane.normal);
3210 // flipped plane, test again to see if it is now valid
3211 for (j = 0;j < 4;j++)
3212 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3214 // if the plane is still not valid, then it is dividing the
3215 // frustum and has to be rejected
3219 // we have created a valid plane, compute extra info
3220 PlaneClassify(&plane);
3222 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3224 // if we've found 5 frustum planes then we have constructed a
3225 // proper split-side case and do not need to keep searching for
3226 // planes to enclose the light origin
3227 if (rtlight->cached_numfrustumplanes == 5)
3235 for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
3237 plane = rtlight->cached_frustumplanes[i];
3238 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));
3243 // now add the light-space box planes if the light box is rotated, as any
3244 // caster outside the oriented light box is irrelevant (even if it passed
3245 // the worldspace light box, which is axial)
3246 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3248 for (i = 0;i < 6;i++)
3252 v[i >> 1] = (i & 1) ? -1 : 1;
3253 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3254 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3255 plane.dist = VectorNormalizeLength(plane.normal);
3256 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3257 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3263 // add the world-space reduced box planes
3264 for (i = 0;i < 6;i++)
3266 VectorClear(plane.normal);
3267 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3268 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
3269 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3278 // reduce all plane distances to tightly fit the rtlight cull box, which
3280 VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3281 VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3282 VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3283 VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3284 VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3285 VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3286 VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3287 VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3288 oldnum = rtlight->cached_numfrustumplanes;
3289 rtlight->cached_numfrustumplanes = 0;
3290 for (j = 0;j < oldnum;j++)
3292 // find the nearest point on the box to this plane
3293 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
3294 for (i = 1;i < 8;i++)
3296 dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
3297 if (bestdist > dist)
3300 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);
3301 // if the nearest point is near or behind the plane, we want this
3302 // plane, otherwise the plane is useless as it won't cull anything
3303 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
3305 PlaneClassify(&rtlight->cached_frustumplanes[j]);
3306 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
3313 void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
3317 RSurf_ActiveWorldEntity();
3319 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3322 GL_CullFace(GL_NONE);
3323 mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3324 for (;mesh;mesh = mesh->next)
3326 if (!mesh->sidetotals[r_shadow_shadowmapside])
3328 r_refdef.stats.lights_shadowtriangles += mesh->sidetotals[r_shadow_shadowmapside];
3329 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
3330 R_Mesh_Draw(0, mesh->numverts, mesh->sideoffsets[r_shadow_shadowmapside], mesh->sidetotals[r_shadow_shadowmapside], mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3334 else if (r_refdef.scene.worldentity->model)
3335 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);
3337 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3340 void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3342 qboolean zpass = false;
3345 int surfacelistindex;
3346 msurface_t *surface;
3348 RSurf_ActiveWorldEntity();
3350 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3353 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
3355 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
3356 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
3358 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
3359 for (;mesh;mesh = mesh->next)
3361 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
3362 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
3363 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
3365 // increment stencil if frontface is infront of depthbuffer
3366 GL_CullFace(r_refdef.view.cullface_back);
3367 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
3368 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3369 // decrement stencil if backface is infront of depthbuffer
3370 GL_CullFace(r_refdef.view.cullface_front);
3371 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
3373 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
3375 // decrement stencil if backface is behind depthbuffer
3376 GL_CullFace(r_refdef.view.cullface_front);
3377 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
3378 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3379 // increment stencil if frontface is behind depthbuffer
3380 GL_CullFace(r_refdef.view.cullface_back);
3381 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
3383 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3387 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh)
3389 // use the shadow trispvs calculated earlier by GetLightInfo to cull world triangles on this dynamic light
3390 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
3391 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
3393 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
3394 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
3395 if (CHECKPVSBIT(trispvs, t))
3396 shadowmarklist[numshadowmark++] = t;
3398 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);
3400 else if (numsurfaces)
3401 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);
3403 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3406 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3408 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3409 vec_t relativeshadowradius;
3410 RSurf_ActiveModelEntity(ent, false, false, false);
3411 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3412 // we need to re-init the shader for each entity because the matrix changed
3413 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3414 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3415 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3416 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3417 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3418 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3419 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3420 switch (r_shadow_rendermode)
3422 case R_SHADOW_RENDERMODE_SHADOWMAP2D:
3423 case R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE:
3424 case R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE:
3425 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
3428 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3431 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3434 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3436 // set up properties for rendering light onto this entity
3437 RSurf_ActiveModelEntity(ent, true, true, false);
3438 GL_AlphaTest(false);
3439 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3440 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3441 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3442 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3445 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
3447 if (!r_refdef.scene.worldmodel->DrawLight)
3450 // set up properties for rendering light onto this entity
3451 RSurf_ActiveWorldEntity();
3452 GL_AlphaTest(false);
3453 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3454 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3455 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3456 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3458 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
3460 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3463 void R_Shadow_DrawEntityLight(entity_render_t *ent)
3465 dp_model_t *model = ent->model;
3466 if (!model->DrawLight)
3469 R_Shadow_SetupEntityLight(ent);
3471 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3473 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3476 void R_Shadow_PrepareLight(rtlight_t *rtlight)
3480 int numleafs, numsurfaces;
3481 int *leaflist, *surfacelist;
3482 unsigned char *leafpvs;
3483 unsigned char *shadowtrispvs;
3484 unsigned char *lighttrispvs;
3485 //unsigned char *surfacesides;
3486 int numlightentities;
3487 int numlightentities_noselfshadow;
3488 int numshadowentities;
3489 int numshadowentities_noselfshadow;
3490 static entity_render_t *lightentities[MAX_EDICTS];
3491 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3492 static entity_render_t *shadowentities[MAX_EDICTS];
3493 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3496 rtlight->draw = false;
3498 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3499 // skip lights that are basically invisible (color 0 0 0)
3500 nolight = VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f);
3502 // loading is done before visibility checks because loading should happen
3503 // all at once at the start of a level, not when it stalls gameplay.
3504 // (especially important to benchmarks)
3506 if (rtlight->isstatic && !nolight && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
3508 if (rtlight->compiled)
3509 R_RTLight_Uncompile(rtlight);
3510 R_RTLight_Compile(rtlight);
3514 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
3516 // look up the light style value at this time
3517 f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3518 VectorScale(rtlight->color, f, rtlight->currentcolor);
3520 if (rtlight->selected)
3522 f = 2 + sin(realtime * M_PI * 4.0);
3523 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3527 // if lightstyle is currently off, don't draw the light
3528 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3531 // skip processing on corona-only lights
3535 // if the light box is offscreen, skip it
3536 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3539 VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
3540 VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
3542 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3544 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3546 // compiled light, world available and can receive realtime lighting
3547 // retrieve leaf information
3548 numleafs = rtlight->static_numleafs;
3549 leaflist = rtlight->static_leaflist;
3550 leafpvs = rtlight->static_leafpvs;
3551 numsurfaces = rtlight->static_numsurfaces;
3552 surfacelist = rtlight->static_surfacelist;
3553 //surfacesides = NULL;
3554 shadowtrispvs = rtlight->static_shadowtrispvs;
3555 lighttrispvs = rtlight->static_lighttrispvs;
3557 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3559 // dynamic light, world available and can receive realtime lighting
3560 // calculate lit surfaces and leafs
3561 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);
3562 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3563 leaflist = r_shadow_buffer_leaflist;
3564 leafpvs = r_shadow_buffer_leafpvs;
3565 surfacelist = r_shadow_buffer_surfacelist;
3566 //surfacesides = r_shadow_buffer_surfacesides;
3567 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3568 lighttrispvs = r_shadow_buffer_lighttrispvs;
3569 // if the reduced leaf bounds are offscreen, skip it
3570 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3581 //surfacesides = NULL;
3582 shadowtrispvs = NULL;
3583 lighttrispvs = NULL;
3585 // check if light is illuminating any visible leafs
3588 for (i = 0;i < numleafs;i++)
3589 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3595 // make a list of lit entities and shadow casting entities
3596 numlightentities = 0;
3597 numlightentities_noselfshadow = 0;
3598 numshadowentities = 0;
3599 numshadowentities_noselfshadow = 0;
3601 // add dynamic entities that are lit by the light
3602 for (i = 0;i < r_refdef.scene.numentities;i++)
3605 entity_render_t *ent = r_refdef.scene.entities[i];
3607 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3609 // skip the object entirely if it is not within the valid
3610 // shadow-casting region (which includes the lit region)
3611 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
3613 if (!(model = ent->model))
3615 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
3617 // this entity wants to receive light, is visible, and is
3618 // inside the light box
3619 // TODO: check if the surfaces in the model can receive light
3620 // so now check if it's in a leaf seen by the light
3621 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))
3623 if (ent->flags & RENDER_NOSELFSHADOW)
3624 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
3626 lightentities[numlightentities++] = ent;
3627 // since it is lit, it probably also casts a shadow...
3628 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3629 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3630 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3632 // note: exterior models without the RENDER_NOSELFSHADOW
3633 // flag still create a RENDER_NOSELFSHADOW shadow but
3634 // are lit normally, this means that they are
3635 // self-shadowing but do not shadow other
3636 // RENDER_NOSELFSHADOW entities such as the gun
3637 // (very weird, but keeps the player shadow off the gun)
3638 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3639 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3641 shadowentities[numshadowentities++] = ent;
3644 else if (ent->flags & RENDER_SHADOW)
3646 // this entity is not receiving light, but may still need to
3648 // TODO: check if the surfaces in the model can cast shadow
3649 // now check if it is in a leaf seen by the light
3650 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))
3652 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3653 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3654 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3656 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3657 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3659 shadowentities[numshadowentities++] = ent;
3664 // return if there's nothing at all to light
3665 if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
3668 // count this light in the r_speeds
3669 r_refdef.stats.lights++;
3671 // flag it as worth drawing later
3672 rtlight->draw = true;
3674 // cache all the animated entities that cast a shadow but are not visible
3675 for (i = 0;i < numshadowentities;i++)
3676 if (!shadowentities[i]->animcache_vertex3f)
3677 R_AnimCache_GetEntity(shadowentities[i], false, false);
3678 for (i = 0;i < numshadowentities_noselfshadow;i++)
3679 if (!shadowentities_noselfshadow[i]->animcache_vertex3f)
3680 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
3682 // allocate some temporary memory for rendering this light later in the frame
3683 // reusable buffers need to be copied, static data can be used as-is
3684 rtlight->cached_numlightentities = numlightentities;
3685 rtlight->cached_numlightentities_noselfshadow = numlightentities_noselfshadow;
3686 rtlight->cached_numshadowentities = numshadowentities;
3687 rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
3688 rtlight->cached_numsurfaces = numsurfaces;
3689 rtlight->cached_lightentities = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
3690 rtlight->cached_lightentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
3691 rtlight->cached_shadowentities = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
3692 rtlight->cached_shadowentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
3693 if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
3695 int numshadowtrispvsbytes = (((r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles) + 7) >> 3);
3696 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
3697 rtlight->cached_shadowtrispvs = (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
3698 rtlight->cached_lighttrispvs = (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
3699 rtlight->cached_surfacelist = (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
3703 // compiled light data
3704 rtlight->cached_shadowtrispvs = shadowtrispvs;
3705 rtlight->cached_lighttrispvs = lighttrispvs;
3706 rtlight->cached_surfacelist = surfacelist;
3710 void R_Shadow_DrawLight(rtlight_t *rtlight)
3714 unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
3715 int numlightentities;
3716 int numlightentities_noselfshadow;
3717 int numshadowentities;
3718 int numshadowentities_noselfshadow;
3719 entity_render_t **lightentities;
3720 entity_render_t **lightentities_noselfshadow;
3721 entity_render_t **shadowentities;
3722 entity_render_t **shadowentities_noselfshadow;
3724 static unsigned char entitysides[MAX_EDICTS];
3725 static unsigned char entitysides_noselfshadow[MAX_EDICTS];
3726 vec3_t nearestpoint;
3728 qboolean castshadows;
3731 // check if we cached this light this frame (meaning it is worth drawing)
3735 // if R_FrameData_Store ran out of space we skip anything dependent on it
3736 if (r_framedata_failed)
3739 numlightentities = rtlight->cached_numlightentities;
3740 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
3741 numshadowentities = rtlight->cached_numshadowentities;
3742 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
3743 numsurfaces = rtlight->cached_numsurfaces;
3744 lightentities = rtlight->cached_lightentities;
3745 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
3746 shadowentities = rtlight->cached_shadowentities;
3747 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
3748 shadowtrispvs = rtlight->cached_shadowtrispvs;
3749 lighttrispvs = rtlight->cached_lighttrispvs;
3750 surfacelist = rtlight->cached_surfacelist;
3752 // set up a scissor rectangle for this light
3753 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3756 // don't let sound skip if going slow
3757 if (r_refdef.scene.extraupdate)
3760 // make this the active rtlight for rendering purposes
3761 R_Shadow_RenderMode_ActiveLight(rtlight);
3763 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
3765 // optionally draw visible shape of the shadow volumes
3766 // for performance analysis by level designers
3767 R_Shadow_RenderMode_VisibleShadowVolumes();
3769 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
3770 for (i = 0;i < numshadowentities;i++)
3771 R_Shadow_DrawEntityShadow(shadowentities[i]);
3772 for (i = 0;i < numshadowentities_noselfshadow;i++)
3773 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3774 R_Shadow_RenderMode_VisibleLighting(false, false);
3777 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
3779 // optionally draw the illuminated areas
3780 // for performance analysis by level designers
3781 R_Shadow_RenderMode_VisibleLighting(false, false);
3783 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3784 for (i = 0;i < numlightentities;i++)
3785 R_Shadow_DrawEntityLight(lightentities[i]);
3786 for (i = 0;i < numlightentities_noselfshadow;i++)
3787 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3790 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
3792 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
3793 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
3794 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
3795 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
3797 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance/rtlight->radius));
3798 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
3799 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
3801 if (castshadows && (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE))
3807 int receivermask = 0;
3808 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
3809 Matrix4x4_Abs(&radiustolight);
3811 r_shadow_shadowmaplod = 0;
3812 for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
3813 if ((r_shadow_shadowmapmaxsize >> i) > lodlinear)
3814 r_shadow_shadowmaplod = i;
3816 if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
3817 size = max(1, r_shadow_shadowmapmaxsize >> r_shadow_shadowmaplod);
3819 size = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
3821 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
3823 surfacesides = NULL;
3826 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3828 castermask = rtlight->static_shadowmap_casters;
3829 receivermask = rtlight->static_shadowmap_receivers;
3833 surfacesides = r_shadow_buffer_surfacesides;
3834 for(i = 0;i < numsurfaces;i++)
3836 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
3837 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3838 castermask |= surfacesides[i];
3839 receivermask |= surfacesides[i];
3843 if (receivermask < 0x3F)
3845 for (i = 0;i < numlightentities;i++)
3846 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3847 if (receivermask < 0x3F)
3848 for(i = 0; i < numlightentities_noselfshadow;i++)
3849 receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3852 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
3856 for (i = 0;i < numshadowentities;i++)
3857 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3858 for (i = 0;i < numshadowentities_noselfshadow;i++)
3859 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3862 //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
3864 // render shadow casters into 6 sided depth texture
3865 for (side = 0;side < 6;side++) if (receivermask & (1 << side))
3867 R_Shadow_RenderMode_ShadowMap(side, receivermask, size);
3868 if (! (castermask & (1 << side))) continue;
3870 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
3871 for (i = 0;i < numshadowentities;i++) if (entitysides[i] & (1 << side))
3872 R_Shadow_DrawEntityShadow(shadowentities[i]);
3875 if (numlightentities_noselfshadow)
3877 // render lighting using the depth texture as shadowmap
3878 // draw lighting in the unmasked areas
3879 R_Shadow_RenderMode_Lighting(false, false, true);
3880 for (i = 0;i < numlightentities_noselfshadow;i++)
3881 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3884 // render shadow casters into 6 sided depth texture
3885 if (numshadowentities_noselfshadow)
3887 for (side = 0;side < 6;side++) if ((receivermask & castermask) & (1 << side))
3889 R_Shadow_RenderMode_ShadowMap(side, 0, size);
3890 for (i = 0;i < numshadowentities_noselfshadow;i++) if (entitysides_noselfshadow[i] & (1 << side))
3891 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3895 // render lighting using the depth texture as shadowmap
3896 // draw lighting in the unmasked areas
3897 R_Shadow_RenderMode_Lighting(false, false, true);
3898 // draw lighting in the unmasked areas
3900 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3901 for (i = 0;i < numlightentities;i++)
3902 R_Shadow_DrawEntityLight(lightentities[i]);
3904 else if (castshadows && vid.stencil)
3906 // draw stencil shadow volumes to mask off pixels that are in shadow
3907 // so that they won't receive lighting
3908 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
3909 R_Shadow_ClearStencil();
3912 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
3913 for (i = 0;i < numshadowentities;i++)
3914 R_Shadow_DrawEntityShadow(shadowentities[i]);
3916 // draw lighting in the unmasked areas
3917 R_Shadow_RenderMode_Lighting(true, false, false);
3918 for (i = 0;i < numlightentities_noselfshadow;i++)
3919 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3921 for (i = 0;i < numshadowentities_noselfshadow;i++)
3922 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3924 // draw lighting in the unmasked areas
3925 R_Shadow_RenderMode_Lighting(true, false, false);
3927 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3928 for (i = 0;i < numlightentities;i++)
3929 R_Shadow_DrawEntityLight(lightentities[i]);
3933 // draw lighting in the unmasked areas
3934 R_Shadow_RenderMode_Lighting(false, false, false);
3936 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3937 for (i = 0;i < numlightentities;i++)
3938 R_Shadow_DrawEntityLight(lightentities[i]);
3939 for (i = 0;i < numlightentities_noselfshadow;i++)
3940 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3943 if (r_shadow_usingdeferredprepass)
3945 // when rendering deferred lighting, we simply rasterize the box
3946 if (castshadows && (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE))
3947 R_Shadow_RenderMode_DrawDeferredLight(false, true);
3948 else if (castshadows && vid.stencil)
3949 R_Shadow_RenderMode_DrawDeferredLight(true, false);
3951 R_Shadow_RenderMode_DrawDeferredLight(false, false);
3955 static void R_Shadow_FreeDeferred(void)
3957 if (r_shadow_prepassgeometryfbo)
3958 qglDeleteFramebuffersEXT(1, &r_shadow_prepassgeometryfbo);CHECKGLERROR
3959 r_shadow_prepassgeometryfbo = 0;
3961 if (r_shadow_prepasslightingfbo)
3962 qglDeleteFramebuffersEXT(1, &r_shadow_prepasslightingfbo);CHECKGLERROR
3963 r_shadow_prepasslightingfbo = 0;
3965 if (r_shadow_prepassgeometrydepthtexture)
3966 R_FreeTexture(r_shadow_prepassgeometrydepthtexture);
3967 r_shadow_prepassgeometrydepthtexture = NULL;
3969 if (r_shadow_prepassgeometrynormalmaptexture)
3970 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
3971 r_shadow_prepassgeometrynormalmaptexture = NULL;
3973 if (r_shadow_prepasslightingdiffusetexture)
3974 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
3975 r_shadow_prepasslightingdiffusetexture = NULL;
3977 if (r_shadow_prepasslightingspeculartexture)
3978 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
3979 r_shadow_prepasslightingspeculartexture = NULL;
3982 void R_Shadow_DrawPrepass(void)
3990 entity_render_t *ent;
3992 GL_AlphaTest(false);
3993 R_Mesh_ColorPointer(NULL, 0, 0);
3994 R_Mesh_ResetTextureState();
3996 GL_ColorMask(1,1,1,1);
3997 GL_BlendFunc(GL_ONE, GL_ZERO);
4000 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepassgeometryfbo);CHECKGLERROR
4001 qglClearColor(0.5f,0.5f,0.5f,1.0f);CHECKGLERROR
4002 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);CHECKGLERROR
4004 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
4005 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
4006 if (r_timereport_active)
4007 R_TimeReport("prepassworld");
4009 for (i = 0;i < r_refdef.scene.numentities;i++)
4011 if (!r_refdef.viewcache.entityvisible[i])
4013 ent = r_refdef.scene.entities[i];
4014 if (ent->model && ent->model->DrawPrepass != NULL)
4015 ent->model->DrawPrepass(ent);
4018 if (r_timereport_active)
4019 R_TimeReport("prepassmodels");
4021 GL_DepthMask(false);
4022 GL_ColorMask(1,1,1,1);
4025 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepasslightingfbo);CHECKGLERROR
4026 qglClearColor(0.0f,0.0f,0.0f,0.0f);CHECKGLERROR
4027 GL_Clear(GL_COLOR_BUFFER_BIT);CHECKGLERROR
4028 if (r_refdef.fogenabled)
4029 qglClearColor(r_refdef.fogcolor[0],r_refdef.fogcolor[1],r_refdef.fogcolor[2],0);CHECKGLERROR
4031 R_Shadow_RenderMode_Begin();
4033 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4034 if (r_shadow_debuglight.integer >= 0)
4036 lightindex = r_shadow_debuglight.integer;
4037 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4038 if (light && (light->flags & flag))
4039 R_Shadow_DrawLight(&light->rtlight);
4043 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4044 for (lightindex = 0;lightindex < range;lightindex++)
4046 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4047 if (light && (light->flags & flag))
4048 R_Shadow_DrawLight(&light->rtlight);
4051 if (r_refdef.scene.rtdlight)
4052 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4053 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4055 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);CHECKGLERROR
4056 if (r_refdef.fogenabled)
4057 qglClearColor(r_refdef.fogcolor[0],r_refdef.fogcolor[1],r_refdef.fogcolor[2],0);CHECKGLERROR
4059 R_Shadow_RenderMode_End();
4061 if (r_timereport_active)
4062 R_TimeReport("prepasslights");
4065 void R_Shadow_DrawLightSprites(void);
4066 void R_Shadow_PrepareLights(void)
4076 if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4) ||
4077 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
4078 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0) ||
4079 r_shadow_shadowmaptexturetype != r_shadow_shadowmapping_texturetype.integer ||
4080 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
4081 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
4082 r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
4083 R_Shadow_FreeShadowMaps();
4085 r_shadow_usingshadowmaportho = false;
4087 switch (vid.renderpath)
4089 case RENDERPATH_GL20:
4090 case RENDERPATH_CGGL:
4091 if (!r_shadow_deferred.integer || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_STENCIL || !vid.support.ext_framebuffer_object || vid.maxdrawbuffers < 2)
4093 r_shadow_usingdeferredprepass = false;
4094 if (r_shadow_prepass_width)
4095 R_Shadow_FreeDeferred();
4096 r_shadow_prepass_width = r_shadow_prepass_height = 0;
4100 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
4102 R_Shadow_FreeDeferred();
4104 r_shadow_usingdeferredprepass = true;
4105 r_shadow_prepass_width = vid.width;
4106 r_shadow_prepass_height = vid.height;
4107 r_shadow_prepassgeometrydepthtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "prepassgeometrydepthmap", vid.width, vid.height, 24, false);
4108 r_shadow_prepassgeometrynormalmaptexture = R_LoadTexture2D(r_shadow_texturepool, "prepassgeometrynormalmap", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, NULL);
4109 r_shadow_prepasslightingdiffusetexture = R_LoadTexture2D(r_shadow_texturepool, "prepasslightingdiffuse", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, NULL);
4110 r_shadow_prepasslightingspeculartexture = R_LoadTexture2D(r_shadow_texturepool, "prepasslightingspecular", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, NULL);
4112 // set up the geometry pass fbo (depth + normalmap)
4113 qglGenFramebuffersEXT(1, &r_shadow_prepassgeometryfbo);CHECKGLERROR
4114 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepassgeometryfbo);CHECKGLERROR
4115 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_prepassgeometrydepthtexture), 0);CHECKGLERROR
4116 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_prepassgeometrynormalmaptexture), 0);CHECKGLERROR
4117 // render depth into one texture and normalmap into the other
4118 if (qglDrawBuffersARB)
4120 qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);CHECKGLERROR
4121 qglReadBuffer(GL_NONE);CHECKGLERROR
4123 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4124 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4126 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4127 Cvar_SetValueQuick(&r_shadow_deferred, 0);
4128 r_shadow_usingdeferredprepass = false;
4131 // set up the lighting pass fbo (diffuse + specular)
4132 qglGenFramebuffersEXT(1, &r_shadow_prepasslightingfbo);CHECKGLERROR
4133 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepasslightingfbo);CHECKGLERROR
4134 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_prepassgeometrydepthtexture), 0);CHECKGLERROR
4135 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_prepasslightingdiffusetexture), 0);CHECKGLERROR
4136 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_prepasslightingspeculartexture), 0);CHECKGLERROR
4137 // render diffuse into one texture and specular into another,
4138 // with depth and normalmap bound as textures,
4139 // with depth bound as attachment as well
4140 if (qglDrawBuffersARB)
4142 qglDrawBuffersARB(2, r_shadow_prepasslightingdrawbuffers);CHECKGLERROR
4143 qglReadBuffer(GL_NONE);CHECKGLERROR
4145 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4146 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4148 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4149 Cvar_SetValueQuick(&r_shadow_deferred, 0);
4150 r_shadow_usingdeferredprepass = false;
4154 case RENDERPATH_GL13:
4155 case RENDERPATH_GL11:
4156 r_shadow_usingdeferredprepass = false;
4160 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);
4162 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4163 if (r_shadow_debuglight.integer >= 0)
4165 lightindex = r_shadow_debuglight.integer;
4166 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4167 if (light && (light->flags & flag))
4168 R_Shadow_PrepareLight(&light->rtlight);
4172 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4173 for (lightindex = 0;lightindex < range;lightindex++)
4175 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4176 if (light && (light->flags & flag))
4177 R_Shadow_PrepareLight(&light->rtlight);
4180 if (r_refdef.scene.rtdlight)
4182 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4183 R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
4185 else if(gl_flashblend.integer)
4187 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4189 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
4190 f = (rtlight->style >= 0 ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4191 VectorScale(rtlight->color, f, rtlight->currentcolor);
4195 if (r_editlights.integer)
4196 R_Shadow_DrawLightSprites();
4199 void R_Shadow_DrawLights(void)
4207 R_Shadow_RenderMode_Begin();
4209 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4210 if (r_shadow_debuglight.integer >= 0)
4212 lightindex = r_shadow_debuglight.integer;
4213 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4214 if (light && (light->flags & flag))
4215 R_Shadow_DrawLight(&light->rtlight);
4219 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4220 for (lightindex = 0;lightindex < range;lightindex++)
4222 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4223 if (light && (light->flags & flag))
4224 R_Shadow_DrawLight(&light->rtlight);
4227 if (r_refdef.scene.rtdlight)
4228 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4229 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4231 R_Shadow_RenderMode_End();
4234 extern const float r_screenvertex3f[12];
4235 extern void R_SetupView(qboolean allowwaterclippingplane);
4236 extern void R_ResetViewRendering3D(void);
4237 extern void R_ResetViewRendering2D(void);
4238 extern cvar_t r_shadows;
4239 extern cvar_t r_shadows_darken;
4240 extern cvar_t r_shadows_drawafterrtlighting;
4241 extern cvar_t r_shadows_castfrombmodels;
4242 extern cvar_t r_shadows_throwdistance;
4243 extern cvar_t r_shadows_throwdirection;
4244 extern cvar_t r_shadows_focus;
4245 extern cvar_t r_shadows_shadowmapscale;
4247 void R_Shadow_PrepareModelShadows(void)
4250 float scale, size, radius, dot1, dot2;
4251 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
4252 entity_render_t *ent;
4254 if (!r_refdef.scene.numentities)
4257 switch (r_shadow_shadowmode)
4259 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4260 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
4261 if (r_shadows.integer >= 2)
4264 case R_SHADOW_SHADOWMODE_STENCIL:
4265 for (i = 0;i < r_refdef.scene.numentities;i++)
4267 ent = r_refdef.scene.entities[i];
4268 if (!ent->animcache_vertex3f && ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4269 R_AnimCache_GetEntity(ent, false, false);
4276 size = 2*r_shadow_shadowmapmaxsize;
4277 scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
4278 radius = 0.5f * size / scale;
4280 Math_atov(r_shadows_throwdirection.string, shadowdir);
4281 VectorNormalize(shadowdir);
4282 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4283 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4284 if (fabs(dot1) <= fabs(dot2))
4285 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4287 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4288 VectorNormalize(shadowforward);
4289 CrossProduct(shadowdir, shadowforward, shadowright);
4290 Math_atov(r_shadows_focus.string, shadowfocus);
4291 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4292 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4293 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4294 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4295 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4297 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4299 shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4300 shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4301 shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4302 shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4303 shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4304 shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4306 for (i = 0;i < r_refdef.scene.numentities;i++)
4308 ent = r_refdef.scene.entities[i];
4309 if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
4311 // cast shadows from anything of the map (submodels are optional)
4312 if (!ent->animcache_vertex3f && ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4313 R_AnimCache_GetEntity(ent, false, false);
4317 void R_DrawModelShadowMaps(void)
4320 float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
4321 entity_render_t *ent;
4322 vec3_t relativelightorigin;
4323 vec3_t relativelightdirection, relativeforward, relativeright;
4324 vec3_t relativeshadowmins, relativeshadowmaxs;
4325 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
4327 matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
4328 r_viewport_t viewport;
4331 if (!r_refdef.scene.numentities)
4334 switch (r_shadow_shadowmode)
4336 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4337 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
4344 R_ResetViewRendering3D();
4345 R_Shadow_RenderMode_Begin();
4346 R_Shadow_RenderMode_ActiveLight(NULL);
4348 switch (r_shadow_shadowmode)
4350 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4351 if (!r_shadow_shadowmap2dtexture)
4352 R_Shadow_MakeShadowMap(0, r_shadow_shadowmapmaxsize);
4353 fbo = r_shadow_fbo2d;
4354 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
4355 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
4356 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
4358 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
4359 if (!r_shadow_shadowmaprectangletexture)
4360 R_Shadow_MakeShadowMap(0, r_shadow_shadowmapmaxsize);
4361 fbo = r_shadow_fborectangle;
4362 r_shadow_shadowmap_texturescale[0] = 1.0f;
4363 r_shadow_shadowmap_texturescale[1] = 1.0f;
4364 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE;
4370 size = 2*r_shadow_shadowmapmaxsize;
4371 scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
4372 radius = 0.5f / scale;
4373 nearclip = -r_shadows_throwdistance.value;
4374 farclip = r_shadows_throwdistance.value;
4375 bias = r_shadow_shadowmapping_bias.value * r_shadow_shadowmapping_nearclip.value / (2 * r_shadows_throwdistance.value) * (1024.0f / size);
4377 r_shadow_shadowmap_parameters[0] = size;
4378 r_shadow_shadowmap_parameters[1] = size;
4379 r_shadow_shadowmap_parameters[2] = 1.0;
4380 r_shadow_shadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
4382 Math_atov(r_shadows_throwdirection.string, shadowdir);
4383 VectorNormalize(shadowdir);
4384 Math_atov(r_shadows_focus.string, shadowfocus);
4385 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4386 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4387 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4388 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4389 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4390 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4391 if (fabs(dot1) <= fabs(dot2))
4392 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4394 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4395 VectorNormalize(shadowforward);
4396 VectorM(scale, shadowforward, &m[0]);
4397 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4399 m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
4400 CrossProduct(shadowdir, shadowforward, shadowright);
4401 VectorM(scale, shadowright, &m[4]);
4402 m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
4403 VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
4404 m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
4405 Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
4406 Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
4407 R_Viewport_InitOrtho(&viewport, &cameramatrix, 0, 0, size, size, 0, 0, 1, 1, 0, -1, NULL);
4409 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4412 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);CHECKGLERROR
4413 R_SetupShader_ShowDepth();
4415 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);CHECKGLERROR
4416 R_SetupShader_DepthOrShadow();
4419 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
4422 R_SetViewport(&viewport);
4423 GL_Scissor(viewport.x, viewport.y, min(viewport.width + r_shadow_shadowmapborder, 2*r_shadow_shadowmapmaxsize), viewport.height + r_shadow_shadowmapborder);
4426 qglClearColor(1,1,1,1);
4427 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
4429 GL_Clear(GL_DEPTH_BUFFER_BIT);
4431 GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
4434 for (i = 0;i < r_refdef.scene.numentities;i++)
4436 ent = r_refdef.scene.entities[i];
4438 // cast shadows from anything of the map (submodels are optional)
4439 if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4441 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4442 Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
4443 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4444 Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
4445 Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
4446 relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4447 relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4448 relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4449 relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4450 relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4451 relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4452 RSurf_ActiveModelEntity(ent, false, false, false);
4453 ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
4454 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4458 R_Shadow_RenderMode_End();
4460 Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
4461 Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
4462 Matrix4x4_CreateScale3(&scalematrix, size, -size, 1);
4463 Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
4464 Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
4465 Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
4467 r_shadow_usingshadowmaportho = true;
4468 switch (r_shadow_shadowmode)
4470 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4471 r_shadow_usingshadowmap2d = true;
4473 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
4474 r_shadow_usingshadowmaprect = true;
4481 void R_DrawModelShadows(void)
4484 float relativethrowdistance;
4485 entity_render_t *ent;
4486 vec3_t relativelightorigin;
4487 vec3_t relativelightdirection;
4488 vec3_t relativeshadowmins, relativeshadowmaxs;
4489 vec3_t tmp, shadowdir;
4491 if (!r_refdef.scene.numentities || !vid.stencil || (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL && r_shadows.integer != 1))
4495 R_ResetViewRendering3D();
4496 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4497 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4498 R_Shadow_RenderMode_Begin();
4499 R_Shadow_RenderMode_ActiveLight(NULL);
4500 r_shadow_lightscissor[0] = r_refdef.view.x;
4501 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
4502 r_shadow_lightscissor[2] = r_refdef.view.width;
4503 r_shadow_lightscissor[3] = r_refdef.view.height;
4504 R_Shadow_RenderMode_StencilShadowVolumes(false);
4507 if (r_shadows.integer == 2)
4509 Math_atov(r_shadows_throwdirection.string, shadowdir);
4510 VectorNormalize(shadowdir);
4513 R_Shadow_ClearStencil();
4515 for (i = 0;i < r_refdef.scene.numentities;i++)
4517 ent = r_refdef.scene.entities[i];
4519 // cast shadows from anything of the map (submodels are optional)
4520 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4522 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4523 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
4524 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
4525 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
4526 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4529 if(ent->entitynumber != 0)
4531 if(ent->entitynumber >= MAX_EDICTS) // csqc entity
4533 // FIXME handle this
4534 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4538 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
4539 int entnum, entnum2, recursion;
4540 entnum = entnum2 = ent->entitynumber;
4541 for(recursion = 32; recursion > 0; --recursion)
4543 entnum2 = cl.entities[entnum].state_current.tagentity;
4544 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
4549 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
4551 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
4552 // transform into modelspace of OUR entity
4553 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
4554 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
4557 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4561 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4564 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
4565 RSurf_ActiveModelEntity(ent, false, false, false);
4566 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4567 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4571 // not really the right mode, but this will disable any silly stencil features
4572 R_Shadow_RenderMode_End();
4574 // set up ortho view for rendering this pass
4575 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4576 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4577 //GL_ScissorTest(true);
4578 //R_EntityMatrix(&identitymatrix);
4579 //R_Mesh_ResetTextureState();
4580 R_ResetViewRendering2D();
4581 R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
4582 R_Mesh_ColorPointer(NULL, 0, 0);
4583 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
4585 // set up a darkening blend on shadowed areas
4586 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4587 //GL_DepthRange(0, 1);
4588 //GL_DepthTest(false);
4589 //GL_DepthMask(false);
4590 //GL_PolygonOffset(0, 0);CHECKGLERROR
4591 GL_Color(0, 0, 0, r_shadows_darken.value);
4592 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4593 //qglDepthFunc(GL_ALWAYS);CHECKGLERROR
4594 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
4595 qglStencilMask(255);CHECKGLERROR
4596 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
4597 qglStencilFunc(GL_NOTEQUAL, 128, 255);CHECKGLERROR
4599 // apply the blend to the shadowed areas
4600 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
4602 // restore the viewport
4603 R_SetViewport(&r_refdef.view.viewport);
4605 // restore other state to normal
4606 //R_Shadow_RenderMode_End();
4609 void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4612 vec3_t centerorigin;
4614 // if it's too close, skip it
4615 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
4617 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4620 if (usequery && r_numqueries + 2 <= r_maxqueries)
4622 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4623 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4624 // 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
4625 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4628 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use qglDepthFunc instead
4629 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
4630 qglDepthFunc(GL_ALWAYS);
4631 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4632 R_Mesh_VertexPointer(vertex3f, 0, 0);
4633 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
4634 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4635 qglDepthFunc(GL_LEQUAL);
4636 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
4637 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4638 R_Mesh_VertexPointer(vertex3f, 0, 0);
4639 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
4640 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4643 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4646 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
4648 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4651 GLint allpixels = 0, visiblepixels = 0;
4652 // now we have to check the query result
4653 if (rtlight->corona_queryindex_visiblepixels)
4656 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
4657 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
4659 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
4660 if (visiblepixels < 1 || allpixels < 1)
4662 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
4663 cscale *= rtlight->corona_visibility;
4667 // FIXME: these traces should scan all render entities instead of cl.world
4668 if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
4671 VectorScale(rtlight->currentcolor, cscale, color);
4672 if (VectorLength(color) > (1.0f / 256.0f))
4675 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
4678 VectorNegate(color, color);
4679 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
4681 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4682 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);
4683 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4685 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
4689 void R_Shadow_DrawCoronas(void)
4697 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4699 if (r_waterstate.renderingscene)
4701 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4702 R_EntityMatrix(&identitymatrix);
4704 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4706 // check occlusion of coronas
4707 // use GL_ARB_occlusion_query if available
4708 // otherwise use raytraces
4710 usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
4713 GL_ColorMask(0,0,0,0);
4714 if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
4715 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
4718 r_maxqueries = (range + r_refdef.scene.numlights) * 4;
4719 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
4721 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
4724 RSurf_ActiveWorldEntity();
4725 GL_BlendFunc(GL_ONE, GL_ZERO);
4726 GL_CullFace(GL_NONE);
4727 GL_DepthMask(false);
4728 GL_DepthRange(0, 1);
4729 GL_PolygonOffset(0, 0);
4731 R_Mesh_ColorPointer(NULL, 0, 0);
4732 R_Mesh_ResetTextureState();
4733 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
4735 for (lightindex = 0;lightindex < range;lightindex++)
4737 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4740 rtlight = &light->rtlight;
4741 rtlight->corona_visibility = 0;
4742 rtlight->corona_queryindex_visiblepixels = 0;
4743 rtlight->corona_queryindex_allpixels = 0;
4744 if (!(rtlight->flags & flag))
4746 if (rtlight->corona <= 0)
4748 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4750 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4752 for (i = 0;i < r_refdef.scene.numlights;i++)
4754 rtlight = r_refdef.scene.lights[i];
4755 rtlight->corona_visibility = 0;
4756 rtlight->corona_queryindex_visiblepixels = 0;
4757 rtlight->corona_queryindex_allpixels = 0;
4758 if (!(rtlight->flags & flag))
4760 if (rtlight->corona <= 0)
4762 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4765 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4767 // now draw the coronas using the query data for intensity info
4768 for (lightindex = 0;lightindex < range;lightindex++)
4770 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4773 rtlight = &light->rtlight;
4774 if (rtlight->corona_visibility <= 0)
4776 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4778 for (i = 0;i < r_refdef.scene.numlights;i++)
4780 rtlight = r_refdef.scene.lights[i];
4781 if (rtlight->corona_visibility <= 0)
4783 if (gl_flashblend.integer)
4784 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4786 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4792 dlight_t *R_Shadow_NewWorldLight(void)
4794 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4797 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)
4800 // validate parameters
4801 if (style < 0 || style >= MAX_LIGHTSTYLES)
4803 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
4809 // copy to light properties
4810 VectorCopy(origin, light->origin);
4811 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4812 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4813 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4815 light->color[0] = max(color[0], 0);
4816 light->color[1] = max(color[1], 0);
4817 light->color[2] = max(color[2], 0);
4819 light->color[0] = color[0];
4820 light->color[1] = color[1];
4821 light->color[2] = color[2];
4822 light->radius = max(radius, 0);
4823 light->style = style;
4824 light->shadow = shadowenable;
4825 light->corona = corona;
4826 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4827 light->coronasizescale = coronasizescale;
4828 light->ambientscale = ambientscale;
4829 light->diffusescale = diffusescale;
4830 light->specularscale = specularscale;
4831 light->flags = flags;
4833 // update renderable light data
4834 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4835 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);
4838 void R_Shadow_FreeWorldLight(dlight_t *light)
4840 if (r_shadow_selectedlight == light)
4841 r_shadow_selectedlight = NULL;
4842 R_RTLight_Uncompile(&light->rtlight);
4843 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4846 void R_Shadow_ClearWorldLights(void)
4850 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4851 for (lightindex = 0;lightindex < range;lightindex++)
4853 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4855 R_Shadow_FreeWorldLight(light);
4857 r_shadow_selectedlight = NULL;
4860 void R_Shadow_SelectLight(dlight_t *light)
4862 if (r_shadow_selectedlight)
4863 r_shadow_selectedlight->selected = false;
4864 r_shadow_selectedlight = light;
4865 if (r_shadow_selectedlight)
4866 r_shadow_selectedlight->selected = true;
4869 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4871 // this is never batched (there can be only one)
4873 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
4874 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4875 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4878 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4883 skinframe_t *skinframe;
4886 // this is never batched (due to the ent parameter changing every time)
4887 // so numsurfaces == 1 and surfacelist[0] == lightnumber
4888 const dlight_t *light = (dlight_t *)ent;
4891 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
4894 VectorScale(light->color, intensity, spritecolor);
4895 if (VectorLength(spritecolor) < 0.1732f)
4896 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
4897 if (VectorLength(spritecolor) > 1.0f)
4898 VectorNormalize(spritecolor);
4900 // draw light sprite
4901 if (light->cubemapname[0] && !light->shadow)
4902 skinframe = r_editlights_sprcubemapnoshadowlight;
4903 else if (light->cubemapname[0])
4904 skinframe = r_editlights_sprcubemaplight;
4905 else if (!light->shadow)
4906 skinframe = r_editlights_sprnoshadowlight;
4908 skinframe = r_editlights_sprlight;
4910 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);
4911 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4913 // draw selection sprite if light is selected
4914 if (light->selected)
4916 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4917 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4918 // VorteX todo: add normalmode/realtime mode light overlay sprites?
4922 void R_Shadow_DrawLightSprites(void)
4926 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4927 for (lightindex = 0;lightindex < range;lightindex++)
4929 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4931 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
4933 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
4936 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
4941 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
4942 if (lightindex >= range)
4944 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4947 rtlight = &light->rtlight;
4948 //if (!(rtlight->flags & flag))
4950 VectorCopy(rtlight->shadoworigin, origin);
4951 *radius = rtlight->radius;
4952 VectorCopy(rtlight->color, color);
4956 void R_Shadow_SelectLightInView(void)
4958 float bestrating, rating, temp[3];
4962 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4965 for (lightindex = 0;lightindex < range;lightindex++)
4967 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4970 VectorSubtract(light->origin, r_refdef.view.origin, temp);
4971 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
4974 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
4975 if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1.0f)
4977 bestrating = rating;
4982 R_Shadow_SelectLight(best);
4985 void R_Shadow_LoadWorldLights(void)
4987 int n, a, style, shadow, flags;
4988 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
4989 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
4990 if (cl.worldmodel == NULL)
4992 Con_Print("No map loaded.\n");
4995 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4996 strlcat (name, ".rtlights", sizeof (name));
4997 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5007 for (;COM_Parse(t, true) && strcmp(
5008 if (COM_Parse(t, true))
5010 if (com_token[0] == '!')
5013 origin[0] = atof(com_token+1);
5016 origin[0] = atof(com_token);
5021 while (*s && *s != '\n' && *s != '\r')
5027 // check for modifier flags
5034 #if _MSC_VER >= 1400
5035 #define sscanf sscanf_s
5037 cubemapname[sizeof(cubemapname)-1] = 0;
5038 #if MAX_QPATH != 128
5039 #error update this code if MAX_QPATH changes
5041 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
5042 #if _MSC_VER >= 1400
5043 , sizeof(cubemapname)
5045 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
5048 flags = LIGHTFLAG_REALTIMEMODE;
5056 coronasizescale = 0.25f;
5058 VectorClear(angles);
5061 if (a < 9 || !strcmp(cubemapname, "\"\""))
5063 // remove quotes on cubemapname
5064 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
5067 namelen = strlen(cubemapname) - 2;
5068 memmove(cubemapname, cubemapname + 1, namelen);
5069 cubemapname[namelen] = '\0';
5073 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);
5076 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5084 Con_Printf("invalid rtlights file \"%s\"\n", name);
5085 Mem_Free(lightsstring);
5089 void R_Shadow_SaveWorldLights(void)
5093 size_t bufchars, bufmaxchars;
5095 char name[MAX_QPATH];
5096 char line[MAX_INPUTLINE];
5097 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
5098 // I hate lines which are 3 times my screen size :( --blub
5101 if (cl.worldmodel == NULL)
5103 Con_Print("No map loaded.\n");
5106 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
5107 strlcat (name, ".rtlights", sizeof (name));
5108 bufchars = bufmaxchars = 0;
5110 for (lightindex = 0;lightindex < range;lightindex++)
5112 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5115 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
5116 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);
5117 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
5118 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]);
5120 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);
5121 if (bufchars + strlen(line) > bufmaxchars)
5123 bufmaxchars = bufchars + strlen(line) + 2048;
5125 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
5129 memcpy(buf, oldbuf, bufchars);
5135 memcpy(buf + bufchars, line, strlen(line));
5136 bufchars += strlen(line);
5140 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
5145 void R_Shadow_LoadLightsFile(void)
5148 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
5149 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
5150 if (cl.worldmodel == NULL)
5152 Con_Print("No map loaded.\n");
5155 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
5156 strlcat (name, ".lights", sizeof (name));
5157 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5165 while (*s && *s != '\n' && *s != '\r')
5171 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);
5175 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);
5178 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
5179 radius = bound(15, radius, 4096);
5180 VectorScale(color, (2.0f / (8388608.0f)), color);
5181 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5189 Con_Printf("invalid lights file \"%s\"\n", name);
5190 Mem_Free(lightsstring);
5194 // tyrlite/hmap2 light types in the delay field
5195 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
5197 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
5209 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
5210 char key[256], value[MAX_INPUTLINE];
5212 if (cl.worldmodel == NULL)
5214 Con_Print("No map loaded.\n");
5217 // try to load a .ent file first
5218 FS_StripExtension (cl.worldmodel->name, key, sizeof (key));
5219 strlcat (key, ".ent", sizeof (key));
5220 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
5221 // and if that is not found, fall back to the bsp file entity string
5223 data = cl.worldmodel->brush.entities;
5226 for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
5228 type = LIGHTTYPE_MINUSX;
5229 origin[0] = origin[1] = origin[2] = 0;
5230 originhack[0] = originhack[1] = originhack[2] = 0;
5231 angles[0] = angles[1] = angles[2] = 0;
5232 color[0] = color[1] = color[2] = 1;
5233 light[0] = light[1] = light[2] = 1;light[3] = 300;
5234 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
5244 if (!COM_ParseToken_Simple(&data, false, false))
5246 if (com_token[0] == '}')
5247 break; // end of entity
5248 if (com_token[0] == '_')
5249 strlcpy(key, com_token + 1, sizeof(key));
5251 strlcpy(key, com_token, sizeof(key));
5252 while (key[strlen(key)-1] == ' ') // remove trailing spaces
5253 key[strlen(key)-1] = 0;
5254 if (!COM_ParseToken_Simple(&data, false, false))
5256 strlcpy(value, com_token, sizeof(value));
5258 // now that we have the key pair worked out...
5259 if (!strcmp("light", key))
5261 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5265 light[0] = vec[0] * (1.0f / 256.0f);
5266 light[1] = vec[0] * (1.0f / 256.0f);
5267 light[2] = vec[0] * (1.0f / 256.0f);
5273 light[0] = vec[0] * (1.0f / 255.0f);
5274 light[1] = vec[1] * (1.0f / 255.0f);
5275 light[2] = vec[2] * (1.0f / 255.0f);
5279 else if (!strcmp("delay", key))
5281 else if (!strcmp("origin", key))
5282 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5283 else if (!strcmp("angle", key))
5284 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5285 else if (!strcmp("angles", key))
5286 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5287 else if (!strcmp("color", key))
5288 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5289 else if (!strcmp("wait", key))
5290 fadescale = atof(value);
5291 else if (!strcmp("classname", key))
5293 if (!strncmp(value, "light", 5))
5296 if (!strcmp(value, "light_fluoro"))
5301 overridecolor[0] = 1;
5302 overridecolor[1] = 1;
5303 overridecolor[2] = 1;
5305 if (!strcmp(value, "light_fluorospark"))
5310 overridecolor[0] = 1;
5311 overridecolor[1] = 1;
5312 overridecolor[2] = 1;
5314 if (!strcmp(value, "light_globe"))
5319 overridecolor[0] = 1;
5320 overridecolor[1] = 0.8;
5321 overridecolor[2] = 0.4;
5323 if (!strcmp(value, "light_flame_large_yellow"))
5328 overridecolor[0] = 1;
5329 overridecolor[1] = 0.5;
5330 overridecolor[2] = 0.1;
5332 if (!strcmp(value, "light_flame_small_yellow"))
5337 overridecolor[0] = 1;
5338 overridecolor[1] = 0.5;
5339 overridecolor[2] = 0.1;
5341 if (!strcmp(value, "light_torch_small_white"))
5346 overridecolor[0] = 1;
5347 overridecolor[1] = 0.5;
5348 overridecolor[2] = 0.1;
5350 if (!strcmp(value, "light_torch_small_walltorch"))
5355 overridecolor[0] = 1;
5356 overridecolor[1] = 0.5;
5357 overridecolor[2] = 0.1;
5361 else if (!strcmp("style", key))
5362 style = atoi(value);
5363 else if (!strcmp("skin", key))
5364 skin = (int)atof(value);
5365 else if (!strcmp("pflags", key))
5366 pflags = (int)atof(value);
5367 //else if (!strcmp("effects", key))
5368 // effects = (int)atof(value);
5369 else if (cl.worldmodel->type == mod_brushq3)
5371 if (!strcmp("scale", key))
5372 lightscale = atof(value);
5373 if (!strcmp("fade", key))
5374 fadescale = atof(value);
5379 if (lightscale <= 0)
5383 if (color[0] == color[1] && color[0] == color[2])
5385 color[0] *= overridecolor[0];
5386 color[1] *= overridecolor[1];
5387 color[2] *= overridecolor[2];
5389 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5390 color[0] = color[0] * light[0];
5391 color[1] = color[1] * light[1];
5392 color[2] = color[2] * light[2];
5395 case LIGHTTYPE_MINUSX:
5397 case LIGHTTYPE_RECIPX:
5399 VectorScale(color, (1.0f / 16.0f), color);
5401 case LIGHTTYPE_RECIPXX:
5403 VectorScale(color, (1.0f / 16.0f), color);
5406 case LIGHTTYPE_NONE:
5410 case LIGHTTYPE_MINUSXX:
5413 VectorAdd(origin, originhack, origin);
5415 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);
5418 Mem_Free(entfiledata);
5422 void R_Shadow_SetCursorLocationForView(void)
5425 vec3_t dest, endpos;
5427 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5428 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
5429 if (trace.fraction < 1)
5431 dist = trace.fraction * r_editlights_cursordistance.value;
5432 push = r_editlights_cursorpushback.value;
5436 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5437 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5441 VectorClear( endpos );
5443 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5444 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5445 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5448 void R_Shadow_UpdateWorldLightSelection(void)
5450 if (r_editlights.integer)
5452 R_Shadow_SetCursorLocationForView();
5453 R_Shadow_SelectLightInView();
5456 R_Shadow_SelectLight(NULL);
5459 void R_Shadow_EditLights_Clear_f(void)
5461 R_Shadow_ClearWorldLights();
5464 void R_Shadow_EditLights_Reload_f(void)
5468 strlcpy(r_shadow_mapname, cl.worldmodel->name, sizeof(r_shadow_mapname));
5469 R_Shadow_ClearWorldLights();
5470 R_Shadow_LoadWorldLights();
5471 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5473 R_Shadow_LoadLightsFile();
5474 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5475 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5479 void R_Shadow_EditLights_Save_f(void)
5483 R_Shadow_SaveWorldLights();
5486 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
5488 R_Shadow_ClearWorldLights();
5489 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5492 void R_Shadow_EditLights_ImportLightsFile_f(void)
5494 R_Shadow_ClearWorldLights();
5495 R_Shadow_LoadLightsFile();
5498 void R_Shadow_EditLights_Spawn_f(void)
5501 if (!r_editlights.integer)
5503 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5506 if (Cmd_Argc() != 1)
5508 Con_Print("r_editlights_spawn does not take parameters\n");
5511 color[0] = color[1] = color[2] = 1;
5512 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5515 void R_Shadow_EditLights_Edit_f(void)
5517 vec3_t origin, angles, color;
5518 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5519 int style, shadows, flags, normalmode, realtimemode;
5520 char cubemapname[MAX_INPUTLINE];
5521 if (!r_editlights.integer)
5523 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5526 if (!r_shadow_selectedlight)
5528 Con_Print("No selected light.\n");
5531 VectorCopy(r_shadow_selectedlight->origin, origin);
5532 VectorCopy(r_shadow_selectedlight->angles, angles);
5533 VectorCopy(r_shadow_selectedlight->color, color);
5534 radius = r_shadow_selectedlight->radius;
5535 style = r_shadow_selectedlight->style;
5536 if (r_shadow_selectedlight->cubemapname)
5537 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5540 shadows = r_shadow_selectedlight->shadow;
5541 corona = r_shadow_selectedlight->corona;
5542 coronasizescale = r_shadow_selectedlight->coronasizescale;
5543 ambientscale = r_shadow_selectedlight->ambientscale;
5544 diffusescale = r_shadow_selectedlight->diffusescale;
5545 specularscale = r_shadow_selectedlight->specularscale;
5546 flags = r_shadow_selectedlight->flags;
5547 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5548 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5549 if (!strcmp(Cmd_Argv(1), "origin"))
5551 if (Cmd_Argc() != 5)
5553 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5556 origin[0] = atof(Cmd_Argv(2));
5557 origin[1] = atof(Cmd_Argv(3));
5558 origin[2] = atof(Cmd_Argv(4));
5560 else if (!strcmp(Cmd_Argv(1), "originx"))
5562 if (Cmd_Argc() != 3)
5564 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5567 origin[0] = atof(Cmd_Argv(2));
5569 else if (!strcmp(Cmd_Argv(1), "originy"))
5571 if (Cmd_Argc() != 3)
5573 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5576 origin[1] = atof(Cmd_Argv(2));
5578 else if (!strcmp(Cmd_Argv(1), "originz"))
5580 if (Cmd_Argc() != 3)
5582 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5585 origin[2] = atof(Cmd_Argv(2));
5587 else if (!strcmp(Cmd_Argv(1), "move"))
5589 if (Cmd_Argc() != 5)
5591 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5594 origin[0] += atof(Cmd_Argv(2));
5595 origin[1] += atof(Cmd_Argv(3));
5596 origin[2] += atof(Cmd_Argv(4));
5598 else if (!strcmp(Cmd_Argv(1), "movex"))
5600 if (Cmd_Argc() != 3)
5602 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5605 origin[0] += atof(Cmd_Argv(2));
5607 else if (!strcmp(Cmd_Argv(1), "movey"))
5609 if (Cmd_Argc() != 3)
5611 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5614 origin[1] += atof(Cmd_Argv(2));
5616 else if (!strcmp(Cmd_Argv(1), "movez"))
5618 if (Cmd_Argc() != 3)
5620 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5623 origin[2] += atof(Cmd_Argv(2));
5625 else if (!strcmp(Cmd_Argv(1), "angles"))
5627 if (Cmd_Argc() != 5)
5629 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5632 angles[0] = atof(Cmd_Argv(2));
5633 angles[1] = atof(Cmd_Argv(3));
5634 angles[2] = atof(Cmd_Argv(4));
5636 else if (!strcmp(Cmd_Argv(1), "anglesx"))
5638 if (Cmd_Argc() != 3)
5640 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5643 angles[0] = atof(Cmd_Argv(2));
5645 else if (!strcmp(Cmd_Argv(1), "anglesy"))
5647 if (Cmd_Argc() != 3)
5649 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5652 angles[1] = atof(Cmd_Argv(2));
5654 else if (!strcmp(Cmd_Argv(1), "anglesz"))
5656 if (Cmd_Argc() != 3)
5658 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5661 angles[2] = atof(Cmd_Argv(2));
5663 else if (!strcmp(Cmd_Argv(1), "color"))
5665 if (Cmd_Argc() != 5)
5667 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
5670 color[0] = atof(Cmd_Argv(2));
5671 color[1] = atof(Cmd_Argv(3));
5672 color[2] = atof(Cmd_Argv(4));
5674 else if (!strcmp(Cmd_Argv(1), "radius"))
5676 if (Cmd_Argc() != 3)
5678 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5681 radius = atof(Cmd_Argv(2));
5683 else if (!strcmp(Cmd_Argv(1), "colorscale"))
5685 if (Cmd_Argc() == 3)
5687 double scale = atof(Cmd_Argv(2));
5694 if (Cmd_Argc() != 5)
5696 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
5699 color[0] *= atof(Cmd_Argv(2));
5700 color[1] *= atof(Cmd_Argv(3));
5701 color[2] *= atof(Cmd_Argv(4));
5704 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
5706 if (Cmd_Argc() != 3)
5708 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5711 radius *= atof(Cmd_Argv(2));
5713 else if (!strcmp(Cmd_Argv(1), "style"))
5715 if (Cmd_Argc() != 3)
5717 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5720 style = atoi(Cmd_Argv(2));
5722 else if (!strcmp(Cmd_Argv(1), "cubemap"))
5726 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5729 if (Cmd_Argc() == 3)
5730 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
5734 else if (!strcmp(Cmd_Argv(1), "shadows"))
5736 if (Cmd_Argc() != 3)
5738 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5741 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5743 else if (!strcmp(Cmd_Argv(1), "corona"))
5745 if (Cmd_Argc() != 3)
5747 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5750 corona = atof(Cmd_Argv(2));
5752 else if (!strcmp(Cmd_Argv(1), "coronasize"))
5754 if (Cmd_Argc() != 3)
5756 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5759 coronasizescale = atof(Cmd_Argv(2));
5761 else if (!strcmp(Cmd_Argv(1), "ambient"))
5763 if (Cmd_Argc() != 3)
5765 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5768 ambientscale = atof(Cmd_Argv(2));
5770 else if (!strcmp(Cmd_Argv(1), "diffuse"))
5772 if (Cmd_Argc() != 3)
5774 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5777 diffusescale = atof(Cmd_Argv(2));
5779 else if (!strcmp(Cmd_Argv(1), "specular"))
5781 if (Cmd_Argc() != 3)
5783 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5786 specularscale = atof(Cmd_Argv(2));
5788 else if (!strcmp(Cmd_Argv(1), "normalmode"))
5790 if (Cmd_Argc() != 3)
5792 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5795 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5797 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
5799 if (Cmd_Argc() != 3)
5801 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5804 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5808 Con_Print("usage: r_editlights_edit [property] [value]\n");
5809 Con_Print("Selected light's properties:\n");
5810 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5811 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5812 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5813 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
5814 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
5815 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
5816 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5817 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
5818 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
5819 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
5820 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
5821 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
5822 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5823 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5826 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5827 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5830 void R_Shadow_EditLights_EditAll_f(void)
5836 if (!r_editlights.integer)
5838 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5842 // EditLights doesn't seem to have a "remove" command or something so:
5843 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5844 for (lightindex = 0;lightindex < range;lightindex++)
5846 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5849 R_Shadow_SelectLight(light);
5850 R_Shadow_EditLights_Edit_f();
5854 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
5856 int lightnumber, lightcount;
5857 size_t lightindex, range;
5861 if (!r_editlights.integer)
5863 x = vid_conwidth.value - 240;
5865 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
5868 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5869 for (lightindex = 0;lightindex < range;lightindex++)
5871 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5874 if (light == r_shadow_selectedlight)
5875 lightnumber = lightindex;
5878 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;
5879 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;
5881 if (r_shadow_selectedlight == NULL)
5883 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;
5884 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;
5885 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;
5886 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;
5887 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;
5888 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;
5889 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;
5890 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;
5891 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;
5892 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;
5893 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;
5894 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;
5895 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;
5896 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;
5897 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;
5900 void R_Shadow_EditLights_ToggleShadow_f(void)
5902 if (!r_editlights.integer)
5904 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5907 if (!r_shadow_selectedlight)
5909 Con_Print("No selected light.\n");
5912 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);
5915 void R_Shadow_EditLights_ToggleCorona_f(void)
5917 if (!r_editlights.integer)
5919 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5922 if (!r_shadow_selectedlight)
5924 Con_Print("No selected light.\n");
5927 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);
5930 void R_Shadow_EditLights_Remove_f(void)
5932 if (!r_editlights.integer)
5934 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
5937 if (!r_shadow_selectedlight)
5939 Con_Print("No selected light.\n");
5942 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
5943 r_shadow_selectedlight = NULL;
5946 void R_Shadow_EditLights_Help_f(void)
5949 "Documentation on r_editlights system:\n"
5951 "r_editlights : enable/disable editing mode\n"
5952 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
5953 "r_editlights_cursorpushback : push back cursor this far from surface\n"
5954 "r_editlights_cursorpushoff : push cursor off surface this far\n"
5955 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
5956 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
5958 "r_editlights_help : this help\n"
5959 "r_editlights_clear : remove all lights\n"
5960 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
5961 "r_editlights_save : save to .rtlights file\n"
5962 "r_editlights_spawn : create a light with default settings\n"
5963 "r_editlights_edit command : edit selected light - more documentation below\n"
5964 "r_editlights_remove : remove selected light\n"
5965 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
5966 "r_editlights_importlightentitiesfrommap : reload light entities\n"
5967 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
5969 "origin x y z : set light location\n"
5970 "originx x: set x component of light location\n"
5971 "originy y: set y component of light location\n"
5972 "originz z: set z component of light location\n"
5973 "move x y z : adjust light location\n"
5974 "movex x: adjust x component of light location\n"
5975 "movey y: adjust y component of light location\n"
5976 "movez z: adjust z component of light location\n"
5977 "angles x y z : set light angles\n"
5978 "anglesx x: set x component of light angles\n"
5979 "anglesy y: set y component of light angles\n"
5980 "anglesz z: set z component of light angles\n"
5981 "color r g b : set color of light (can be brighter than 1 1 1)\n"
5982 "radius radius : set radius (size) of light\n"
5983 "colorscale grey : multiply color of light (1 does nothing)\n"
5984 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
5985 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
5986 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
5987 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
5988 "cubemap basename : set filter cubemap of light (not yet supported)\n"
5989 "shadows 1/0 : turn on/off shadows\n"
5990 "corona n : set corona intensity\n"
5991 "coronasize n : set corona size (0-1)\n"
5992 "ambient n : set ambient intensity (0-1)\n"
5993 "diffuse n : set diffuse intensity (0-1)\n"
5994 "specular n : set specular intensity (0-1)\n"
5995 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
5996 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
5997 "<nothing> : print light properties to console\n"
6001 void R_Shadow_EditLights_CopyInfo_f(void)
6003 if (!r_editlights.integer)
6005 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
6008 if (!r_shadow_selectedlight)
6010 Con_Print("No selected light.\n");
6013 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
6014 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
6015 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
6016 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
6017 if (r_shadow_selectedlight->cubemapname)
6018 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
6020 r_shadow_bufferlight.cubemapname[0] = 0;
6021 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
6022 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
6023 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
6024 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
6025 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
6026 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
6027 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
6030 void R_Shadow_EditLights_PasteInfo_f(void)
6032 if (!r_editlights.integer)
6034 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
6037 if (!r_shadow_selectedlight)
6039 Con_Print("No selected light.\n");
6042 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);
6045 void R_Shadow_EditLights_Init(void)
6047 Cvar_RegisterVariable(&r_editlights);
6048 Cvar_RegisterVariable(&r_editlights_cursordistance);
6049 Cvar_RegisterVariable(&r_editlights_cursorpushback);
6050 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
6051 Cvar_RegisterVariable(&r_editlights_cursorgrid);
6052 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
6053 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
6054 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
6055 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)");
6056 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
6057 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
6058 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
6059 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)");
6060 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
6061 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
6062 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
6063 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
6064 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
6065 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
6066 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)");
6072 =============================================================================
6076 =============================================================================
6079 void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, int dynamic)
6081 VectorClear(diffusecolor);
6082 VectorClear(diffusenormal);
6084 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
6086 ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_refdef.scene.ambient;
6087 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
6090 VectorSet(ambientcolor, 1, 1, 1);
6097 for (i = 0;i < r_refdef.scene.numlights;i++)
6099 light = r_refdef.scene.lights[i];
6100 Matrix4x4_Transform(&light->matrix_worldtolight, p, v);
6101 f = 1 - VectorLength2(v);
6102 if (f > 0 && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
6103 VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);