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_PrepareVertices_Position_Arrays(outverts, shadowvertex3f);
1327 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 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 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
1343 // increment stencil if frontface is infront of depthbuffer
1344 GL_CullFace(r_refdef.view.cullface_front);
1345 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1346 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1347 // decrement stencil if backface is infront of depthbuffer
1348 GL_CullFace(r_refdef.view.cullface_back);
1349 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1351 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
1353 // decrement stencil if backface is behind depthbuffer
1354 GL_CullFace(r_refdef.view.cullface_front);
1355 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1356 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1357 // increment stencil if frontface is behind depthbuffer
1358 GL_CullFace(r_refdef.view.cullface_back);
1359 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1361 R_Mesh_PrepareVertices_Position_Arrays(outverts, shadowvertex3f);
1362 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 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 static const r_vertexposition_t resetvertexposition[3];
1900 void R_Shadow_RenderMode_Begin(void)
1906 R_Shadow_ValidateCvars();
1908 if (!r_shadow_attenuation2dtexture
1909 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1910 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1911 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1912 R_Shadow_MakeTextures();
1915 R_Mesh_ResetTextureState();
1916 R_Mesh_PrepareVertices_Position(0, resetvertexposition, NULL);
1917 GL_BlendFunc(GL_ONE, GL_ZERO);
1918 GL_DepthRange(0, 1);
1919 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1921 GL_DepthMask(false);
1922 GL_Color(0, 0, 0, 1);
1923 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1925 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1927 if (gl_ext_separatestencil.integer && vid.support.ati_separate_stencil)
1929 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
1930 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
1932 else if (gl_ext_stenciltwoside.integer && vid.support.ext_stencil_two_side)
1934 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
1935 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
1939 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
1940 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
1943 switch(vid.renderpath)
1945 case RENDERPATH_GL20:
1946 case RENDERPATH_CGGL:
1947 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1949 case RENDERPATH_GL13:
1950 case RENDERPATH_GL11:
1951 if (r_textureunits.integer >= 2 && vid.texunits >= 2 && r_shadow_texture3d.integer && r_shadow_attenuation3dtexture)
1952 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN;
1953 else if (r_textureunits.integer >= 3 && vid.texunits >= 3)
1954 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN;
1955 else if (r_textureunits.integer >= 2 && vid.texunits >= 2)
1956 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN;
1958 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1964 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
1965 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
1966 r_shadow_drawbuffer = drawbuffer;
1967 r_shadow_readbuffer = readbuffer;
1969 r_shadow_cullface_front = r_refdef.view.cullface_front;
1970 r_shadow_cullface_back = r_refdef.view.cullface_back;
1973 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
1975 rsurface.rtlight = rtlight;
1978 void R_Shadow_RenderMode_Reset(void)
1981 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE)
1983 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1985 if (vid.support.ext_framebuffer_object)
1987 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);CHECKGLERROR
1990 qglDrawBuffer(r_shadow_drawbuffer);CHECKGLERROR
1991 qglReadBuffer(r_shadow_readbuffer);CHECKGLERROR
1993 R_SetViewport(&r_refdef.view.viewport);
1994 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
1995 R_Mesh_ResetTextureState();
1996 R_Mesh_PrepareVertices_Position(0, resetvertexposition, NULL);
1997 GL_DepthRange(0, 1);
1999 GL_DepthMask(false);
2000 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
2001 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
2002 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
2003 qglStencilMask(255);CHECKGLERROR
2004 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
2005 qglStencilFunc(GL_ALWAYS, 128, 255);CHECKGLERROR
2006 r_refdef.view.cullface_front = r_shadow_cullface_front;
2007 r_refdef.view.cullface_back = r_shadow_cullface_back;
2008 GL_CullFace(r_refdef.view.cullface_back);
2009 GL_Color(1, 1, 1, 1);
2010 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
2011 GL_BlendFunc(GL_ONE, GL_ZERO);
2012 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
2013 r_shadow_usingshadowmaprect = false;
2014 r_shadow_usingshadowmapcube = false;
2015 r_shadow_usingshadowmap2d = false;
2016 r_shadow_usingshadowmaportho = false;
2020 void R_Shadow_ClearStencil(void)
2023 GL_Clear(GL_STENCIL_BUFFER_BIT);
2024 r_refdef.stats.lights_clears++;
2027 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
2029 r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
2030 if (r_shadow_rendermode == mode)
2033 R_Shadow_RenderMode_Reset();
2034 GL_ColorMask(0, 0, 0, 0);
2035 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2036 R_SetupShader_DepthOrShadow();
2037 qglDepthFunc(GL_LESS);CHECKGLERROR
2038 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2039 r_shadow_rendermode = mode;
2044 case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
2045 GL_CullFace(GL_NONE);
2046 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
2047 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
2049 case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
2050 GL_CullFace(GL_NONE);
2051 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
2052 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
2054 case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
2055 GL_CullFace(GL_NONE);
2056 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
2057 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
2058 qglStencilMask(255);CHECKGLERROR
2059 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
2060 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
2061 qglStencilMask(255);CHECKGLERROR
2062 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
2064 case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
2065 GL_CullFace(GL_NONE);
2066 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
2067 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
2068 qglStencilMask(255);CHECKGLERROR
2069 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
2070 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
2071 qglStencilMask(255);CHECKGLERROR
2072 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
2077 static void R_Shadow_MakeVSDCT(void)
2079 // maps to a 2x3 texture rectangle with normalized coordinates
2084 // stores abs(dir.xy), offset.xy/2.5
2085 unsigned char data[4*6] =
2087 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
2088 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
2089 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
2090 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
2091 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
2092 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
2094 r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, NULL);
2097 static void R_Shadow_MakeShadowMap(int side, int size)
2100 switch (r_shadow_shadowmode)
2102 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2103 if (r_shadow_shadowmap2dtexture) return;
2104 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);
2105 qglGenFramebuffersEXT(1, &r_shadow_fbo2d);CHECKGLERROR
2106 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbo2d);CHECKGLERROR
2107 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_shadowmap2dtexture), 0);CHECKGLERROR
2109 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
2110 if (r_shadow_shadowmaprectangletexture) return;
2111 r_shadow_shadowmaprectangletexture = R_LoadTextureShadowMapRectangle(r_shadow_texturepool, "shadowmap", size*2, size*3, r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
2112 qglGenFramebuffersEXT(1, &r_shadow_fborectangle);CHECKGLERROR
2113 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fborectangle);CHECKGLERROR
2114 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, R_GetTexture(r_shadow_shadowmaprectangletexture), 0);CHECKGLERROR
2116 case R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE:
2117 if (r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]) return;
2118 r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod] = R_LoadTextureShadowMapCube(r_shadow_texturepool, "shadowmapcube", size, r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
2119 qglGenFramebuffersEXT(1, &r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR
2120 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR
2121 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
2126 // render depth into the fbo, do not render color at all
2127 qglDrawBuffer(GL_NONE);CHECKGLERROR
2128 qglReadBuffer(GL_NONE);CHECKGLERROR
2129 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2130 if (status != GL_FRAMEBUFFER_COMPLETE_EXT && (r_shadow_shadowmapping.integer || r_shadow_deferred.integer))
2132 Con_Printf("R_Shadow_MakeShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2133 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2134 Cvar_SetValueQuick(&r_shadow_deferred, 0);
2138 void R_Shadow_RenderMode_ShadowMap(int side, int clear, int size)
2140 float nearclip, farclip, bias;
2141 r_viewport_t viewport;
2145 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
2147 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
2148 r_shadow_shadowmap_parameters[1] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
2149 r_shadow_shadowmap_parameters[3] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
2150 r_shadow_shadowmapside = side;
2151 r_shadow_shadowmapsize = size;
2152 switch (r_shadow_shadowmode)
2154 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2155 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2156 r_shadow_shadowmap_parameters[2] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2157 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
2158 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D) goto init_done;
2160 // complex unrolled cube approach (more flexible)
2161 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2162 R_Shadow_MakeVSDCT();
2163 if (!r_shadow_shadowmap2dtexture)
2164 R_Shadow_MakeShadowMap(side, r_shadow_shadowmapmaxsize);
2166 if (r_shadow_shadowmap2dtexture) fbo = r_shadow_fbo2d;
2167 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
2168 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
2169 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
2171 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
2172 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2173 r_shadow_shadowmap_parameters[2] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2174 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
2175 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE) goto init_done;
2177 // complex unrolled cube approach (more flexible)
2178 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2179 R_Shadow_MakeVSDCT();
2180 if (!r_shadow_shadowmaprectangletexture)
2181 R_Shadow_MakeShadowMap(side, r_shadow_shadowmapmaxsize);
2183 if(r_shadow_shadowmaprectangletexture) fbo = r_shadow_fborectangle;
2184 r_shadow_shadowmap_texturescale[0] = 1.0f;
2185 r_shadow_shadowmap_texturescale[1] = 1.0f;
2186 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE;
2188 case R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE:
2189 r_shadow_shadowmap_parameters[0] = 1.0f;
2190 r_shadow_shadowmap_parameters[2] = 1.0f;
2191 R_Viewport_InitCubeSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, nearclip, farclip, NULL);
2192 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE) goto init_done;
2194 // simple cube approach
2195 if (!r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod])
2196 R_Shadow_MakeShadowMap(side, size);
2198 if (r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]) fbo = r_shadow_fbocubeside[r_shadow_shadowmaplod];
2199 r_shadow_shadowmap_texturescale[0] = 0.0f;
2200 r_shadow_shadowmap_texturescale[1] = 0.0f;
2201 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE;
2207 R_Shadow_RenderMode_Reset();
2210 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);CHECKGLERROR
2211 R_SetupShader_DepthOrShadow();
2215 R_SetupShader_ShowDepth();
2216 qglClearColor(1,1,1,1);CHECKGLERROR
2219 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
2226 R_SetViewport(&viewport);
2227 switch (r_shadow_rendermode)
2229 case R_SHADOW_RENDERMODE_SHADOWMAP2D:
2230 case R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE:
2231 flipped = (side & 1) ^ (side >> 2);
2232 r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
2233 r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
2234 GL_CullFace(r_refdef.view.cullface_back);
2235 if ((clear & ((2 << side) - 1)) == (1 << side)) // only clear if the side is the first in the mask
2237 // get tightest scissor rectangle that encloses all viewports in the clear mask
2238 int x1 = clear & 0x15 ? 0 : size;
2239 int x2 = clear & 0x2A ? 2 * size : size;
2240 int y1 = clear & 0x03 ? 0 : (clear & 0xC ? size : 2 * size);
2241 int y2 = clear & 0x30 ? 3 * size : (clear & 0xC ? 2 * size : size);
2242 GL_Scissor(x1, y1, x2 - x1, y2 - y1);
2243 GL_Clear(GL_DEPTH_BUFFER_BIT);
2245 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2247 case R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE:
2248 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
2249 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2251 GL_Clear(GL_DEPTH_BUFFER_BIT);
2259 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
2263 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2264 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2265 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2266 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2269 R_Shadow_RenderMode_Reset();
2270 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2273 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2277 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2278 // only draw light where this geometry was already rendered AND the
2279 // stencil is 128 (values other than this mean shadow)
2280 qglStencilFunc(GL_EQUAL, 128, 255);CHECKGLERROR
2282 r_shadow_rendermode = r_shadow_lightingrendermode;
2283 // do global setup needed for the chosen lighting mode
2284 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2286 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2291 switch (r_shadow_shadowmode)
2293 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2294 r_shadow_usingshadowmap2d = true;
2296 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
2297 r_shadow_usingshadowmaprect = true;
2299 case R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE:
2300 r_shadow_usingshadowmapcube = true;
2306 //R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.array_passcolor4f, 0, 0);
2310 static const unsigned short bboxelements[36] =
2320 static const float bboxpoints[8][3] =
2332 void R_Shadow_RenderMode_DrawDeferredLight(qboolean stenciltest, qboolean shadowmapping)
2335 float vertex3f[8*3];
2336 const matrix4x4_t *matrix = &rsurface.rtlight->matrix_lighttoworld;
2338 R_Shadow_RenderMode_Reset();
2339 r_shadow_rendermode = r_shadow_lightingrendermode;
2340 // do global setup needed for the chosen lighting mode
2342 R_EntityMatrix(&identitymatrix);
2343 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2346 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2347 // only draw light where this geometry was already rendered AND the
2348 // stencil is 128 (values other than this mean shadow)
2349 qglStencilFunc(GL_EQUAL, 128, 255);CHECKGLERROR
2351 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepasslightingfbo);CHECKGLERROR
2354 switch (r_shadow_shadowmode)
2356 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2357 r_shadow_usingshadowmap2d = true;
2359 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
2360 r_shadow_usingshadowmaprect = true;
2362 case R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE:
2363 r_shadow_usingshadowmapcube = true;
2370 // render the lighting
2371 R_SetupShader_DeferredLight(rsurface.rtlight);
2372 for (i = 0;i < 8;i++)
2373 Matrix4x4_Transform(matrix, bboxpoints[i], vertex3f + i*3);
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_PrepareVertices_Position_Arrays(8, vertex3f);
2383 R_Mesh_Draw(0, 8, 0, 12, NULL, NULL, 0, bboxelements, NULL, 0);
2387 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
2390 R_Shadow_RenderMode_Reset();
2391 GL_BlendFunc(GL_ONE, GL_ONE);
2392 GL_DepthRange(0, 1);
2393 GL_DepthTest(r_showshadowvolumes.integer < 2);
2394 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
2395 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2396 GL_CullFace(GL_NONE);
2397 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
2400 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
2403 R_Shadow_RenderMode_Reset();
2404 GL_BlendFunc(GL_ONE, GL_ONE);
2405 GL_DepthRange(0, 1);
2406 GL_DepthTest(r_showlighting.integer < 2);
2407 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2410 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2414 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2415 qglStencilFunc(GL_EQUAL, 128, 255);CHECKGLERROR
2417 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2420 void R_Shadow_RenderMode_End(void)
2423 R_Shadow_RenderMode_Reset();
2424 R_Shadow_RenderMode_ActiveLight(NULL);
2426 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2427 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2430 int bboxedges[12][2] =
2449 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2451 int i, ix1, iy1, ix2, iy2;
2452 float x1, y1, x2, y2;
2454 float vertex[20][3];
2463 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2464 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2465 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2466 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2468 if (!r_shadow_scissor.integer)
2471 // if view is inside the light box, just say yes it's visible
2472 if (BoxesOverlap(r_refdef.view.origin, r_refdef.view.origin, mins, maxs))
2475 x1 = y1 = x2 = y2 = 0;
2477 // transform all corners that are infront of the nearclip plane
2478 VectorNegate(r_refdef.view.frustum[4].normal, plane4f);
2479 plane4f[3] = r_refdef.view.frustum[4].dist;
2481 for (i = 0;i < 8;i++)
2483 Vector4Set(corner[i], (i & 1) ? maxs[0] : mins[0], (i & 2) ? maxs[1] : mins[1], (i & 4) ? maxs[2] : mins[2], 1);
2484 dist[i] = DotProduct4(corner[i], plane4f);
2485 sign[i] = dist[i] > 0;
2488 VectorCopy(corner[i], vertex[numvertices]);
2492 // if some points are behind the nearclip, add clipped edge points to make
2493 // sure that the scissor boundary is complete
2494 if (numvertices > 0 && numvertices < 8)
2496 // add clipped edge points
2497 for (i = 0;i < 12;i++)
2499 j = bboxedges[i][0];
2500 k = bboxedges[i][1];
2501 if (sign[j] != sign[k])
2503 f = dist[j] / (dist[j] - dist[k]);
2504 VectorLerp(corner[j], f, corner[k], vertex[numvertices]);
2510 // if we have no points to check, the light is behind the view plane
2514 // if we have some points to transform, check what screen area is covered
2515 x1 = y1 = x2 = y2 = 0;
2517 //Con_Printf("%i vertices to transform...\n", numvertices);
2518 for (i = 0;i < numvertices;i++)
2520 VectorCopy(vertex[i], v);
2521 R_Viewport_TransformToScreen(&r_refdef.view.viewport, v, v2);
2522 //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]);
2525 if (x1 > v2[0]) x1 = v2[0];
2526 if (x2 < v2[0]) x2 = v2[0];
2527 if (y1 > v2[1]) y1 = v2[1];
2528 if (y2 < v2[1]) y2 = v2[1];
2537 // now convert the scissor rectangle to integer screen coordinates
2538 ix1 = (int)(x1 - 1.0f);
2539 iy1 = vid.height - (int)(y2 - 1.0f);
2540 ix2 = (int)(x2 + 1.0f);
2541 iy2 = vid.height - (int)(y1 + 1.0f);
2542 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
2544 // clamp it to the screen
2545 if (ix1 < r_refdef.view.viewport.x) ix1 = r_refdef.view.viewport.x;
2546 if (iy1 < r_refdef.view.viewport.y) iy1 = r_refdef.view.viewport.y;
2547 if (ix2 > r_refdef.view.viewport.x + r_refdef.view.viewport.width) ix2 = r_refdef.view.viewport.x + r_refdef.view.viewport.width;
2548 if (iy2 > r_refdef.view.viewport.y + r_refdef.view.viewport.height) iy2 = r_refdef.view.viewport.y + r_refdef.view.viewport.height;
2550 // if it is inside out, it's not visible
2551 if (ix2 <= ix1 || iy2 <= iy1)
2554 // the light area is visible, set up the scissor rectangle
2555 r_shadow_lightscissor[0] = ix1;
2556 r_shadow_lightscissor[1] = iy1;
2557 r_shadow_lightscissor[2] = ix2 - ix1;
2558 r_shadow_lightscissor[3] = iy2 - iy1;
2560 r_refdef.stats.lights_scissored++;
2564 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, const float *diffusecolor, const float *ambientcolor)
2567 const float *vertex3f;
2568 const float *normal3f;
2570 float dist, dot, distintensity, shadeintensity, v[3], n[3];
2571 switch (r_shadow_rendermode)
2573 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2574 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2575 if (VectorLength2(diffusecolor) > 0)
2577 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, normal3f = rsurface.batchnormal3f + 3*firstvertex, color4f = rsurface.array_passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, normal3f += 3, color4f += 4)
2579 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2580 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2581 if ((dot = DotProduct(n, v)) < 0)
2583 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2584 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
2587 VectorCopy(ambientcolor, color4f);
2588 if (r_refdef.fogenabled)
2591 f = RSurf_FogVertex(vertex3f);
2592 VectorScale(color4f, f, color4f);
2599 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.array_passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
2601 VectorCopy(ambientcolor, color4f);
2602 if (r_refdef.fogenabled)
2605 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2606 f = RSurf_FogVertex(vertex3f);
2607 VectorScale(color4f + 4*i, f, color4f);
2613 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2614 if (VectorLength2(diffusecolor) > 0)
2616 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, normal3f = rsurface.batchnormal3f + 3*firstvertex, color4f = rsurface.array_passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, normal3f += 3, color4f += 4)
2618 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2619 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2621 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2622 if ((dot = DotProduct(n, v)) < 0)
2624 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2625 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2626 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2627 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2631 color4f[0] = ambientcolor[0] * distintensity;
2632 color4f[1] = ambientcolor[1] * distintensity;
2633 color4f[2] = ambientcolor[2] * distintensity;
2635 if (r_refdef.fogenabled)
2638 f = RSurf_FogVertex(vertex3f);
2639 VectorScale(color4f, f, color4f);
2643 VectorClear(color4f);
2649 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.array_passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
2651 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2652 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2654 color4f[0] = ambientcolor[0] * distintensity;
2655 color4f[1] = ambientcolor[1] * distintensity;
2656 color4f[2] = ambientcolor[2] * distintensity;
2657 if (r_refdef.fogenabled)
2660 f = RSurf_FogVertex(vertex3f);
2661 VectorScale(color4f, f, color4f);
2665 VectorClear(color4f);
2670 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2671 if (VectorLength2(diffusecolor) > 0)
2673 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, normal3f = rsurface.batchnormal3f + 3*firstvertex, color4f = rsurface.array_passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, normal3f += 3, color4f += 4)
2675 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2676 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2678 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2679 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2680 if ((dot = DotProduct(n, v)) < 0)
2682 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2683 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2684 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2685 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2689 color4f[0] = ambientcolor[0] * distintensity;
2690 color4f[1] = ambientcolor[1] * distintensity;
2691 color4f[2] = ambientcolor[2] * distintensity;
2693 if (r_refdef.fogenabled)
2696 f = RSurf_FogVertex(vertex3f);
2697 VectorScale(color4f, f, color4f);
2701 VectorClear(color4f);
2707 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.array_passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
2709 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2710 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2712 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2713 color4f[0] = ambientcolor[0] * distintensity;
2714 color4f[1] = ambientcolor[1] * distintensity;
2715 color4f[2] = ambientcolor[2] * distintensity;
2716 if (r_refdef.fogenabled)
2719 f = RSurf_FogVertex(vertex3f);
2720 VectorScale(color4f, f, color4f);
2724 VectorClear(color4f);
2734 static void R_Shadow_RenderLighting_VisibleLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
2736 // used to display how many times a surface is lit for level design purposes
2737 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
2738 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
2742 static void R_Shadow_RenderLighting_Light_GLSL(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale, float specularscale)
2744 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2745 R_SetupShader_Surface(lightcolor, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT, texturenumsurfaces, texturesurfacelist);
2746 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2748 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2751 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2753 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
2757 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
2764 int newnumtriangles;
2768 int maxtriangles = 4096;
2769 static int newelements[4096*3];
2770 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, diffusecolor2, ambientcolor2);
2771 for (renders = 0;renders < 4;renders++)
2776 newnumtriangles = 0;
2778 // due to low fillrate on the cards this vertex lighting path is
2779 // designed for, we manually cull all triangles that do not
2780 // contain a lit vertex
2781 // this builds batches of triangles from multiple surfaces and
2782 // renders them at once
2783 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
2785 if (VectorLength2(rsurface.array_passcolor4f + e[0] * 4) + VectorLength2(rsurface.array_passcolor4f + e[1] * 4) + VectorLength2(rsurface.array_passcolor4f + e[2] * 4) >= 0.01)
2787 if (newnumtriangles)
2789 newfirstvertex = min(newfirstvertex, e[0]);
2790 newlastvertex = max(newlastvertex, e[0]);
2794 newfirstvertex = e[0];
2795 newlastvertex = e[0];
2797 newfirstvertex = min(newfirstvertex, e[1]);
2798 newlastvertex = max(newlastvertex, e[1]);
2799 newfirstvertex = min(newfirstvertex, e[2]);
2800 newlastvertex = max(newlastvertex, e[2]);
2806 if (newnumtriangles >= maxtriangles)
2808 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
2809 newnumtriangles = 0;
2815 if (newnumtriangles >= 1)
2817 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
2820 // if we couldn't find any lit triangles, exit early
2823 // now reduce the intensity for the next overbright pass
2824 // we have to clamp to 0 here incase the drivers have improper
2825 // handling of negative colors
2826 // (some old drivers even have improper handling of >1 color)
2828 for (i = 0, c = rsurface.array_passcolor4f + 4 * firstvertex;i < numvertices;i++, c += 4)
2830 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
2832 c[0] = max(0, c[0] - 1);
2833 c[1] = max(0, c[1] - 1);
2834 c[2] = max(0, c[2] - 1);
2846 static void R_Shadow_RenderLighting_Light_Vertex(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale)
2848 // OpenGL 1.1 path (anything)
2849 float ambientcolorbase[3], diffusecolorbase[3];
2850 float ambientcolorpants[3], diffusecolorpants[3];
2851 float ambientcolorshirt[3], diffusecolorshirt[3];
2852 const float *surfacecolor = rsurface.texture->dlightcolor;
2853 const float *surfacepants = rsurface.colormap_pantscolor;
2854 const float *surfaceshirt = rsurface.colormap_shirtcolor;
2855 rtexture_t *basetexture = rsurface.texture->basetexture;
2856 rtexture_t *pantstexture = rsurface.texture->pantstexture;
2857 rtexture_t *shirttexture = rsurface.texture->shirttexture;
2858 qboolean dopants = pantstexture && VectorLength2(surfacepants) >= (1.0f / 1048576.0f);
2859 qboolean doshirt = shirttexture && VectorLength2(surfaceshirt) >= (1.0f / 1048576.0f);
2860 ambientscale *= 2 * r_refdef.view.colorscale;
2861 diffusescale *= 2 * r_refdef.view.colorscale;
2862 ambientcolorbase[0] = lightcolor[0] * ambientscale * surfacecolor[0];ambientcolorbase[1] = lightcolor[1] * ambientscale * surfacecolor[1];ambientcolorbase[2] = lightcolor[2] * ambientscale * surfacecolor[2];
2863 diffusecolorbase[0] = lightcolor[0] * diffusescale * surfacecolor[0];diffusecolorbase[1] = lightcolor[1] * diffusescale * surfacecolor[1];diffusecolorbase[2] = lightcolor[2] * diffusescale * surfacecolor[2];
2864 ambientcolorpants[0] = ambientcolorbase[0] * surfacepants[0];ambientcolorpants[1] = ambientcolorbase[1] * surfacepants[1];ambientcolorpants[2] = ambientcolorbase[2] * surfacepants[2];
2865 diffusecolorpants[0] = diffusecolorbase[0] * surfacepants[0];diffusecolorpants[1] = diffusecolorbase[1] * surfacepants[1];diffusecolorpants[2] = diffusecolorbase[2] * surfacepants[2];
2866 ambientcolorshirt[0] = ambientcolorbase[0] * surfaceshirt[0];ambientcolorshirt[1] = ambientcolorbase[1] * surfaceshirt[1];ambientcolorshirt[2] = ambientcolorbase[2] * surfaceshirt[2];
2867 diffusecolorshirt[0] = diffusecolorbase[0] * surfaceshirt[0];diffusecolorshirt[1] = diffusecolorbase[1] * surfaceshirt[1];diffusecolorshirt[2] = diffusecolorbase[2] * surfaceshirt[2];
2868 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | (diffusescale > 0 ? BATCHNEED_ARRAY_NORMAL : 0) | BATCHNEED_ARRAY_TEXCOORD, texturenumsurfaces, texturesurfacelist);
2869 R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
2870 R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.array_passcolor4f, 0, 0);
2871 R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
2872 R_Mesh_TexBind(0, basetexture);
2873 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
2874 R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
2875 switch(r_shadow_rendermode)
2877 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2878 R_Mesh_TexBind(1, r_shadow_attenuation3dtexture);
2879 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
2880 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
2881 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
2883 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2884 R_Mesh_TexBind(2, r_shadow_attenuation2dtexture);
2885 R_Mesh_TexMatrix(2, &rsurface.entitytoattenuationz);
2886 R_Mesh_TexCombine(2, GL_MODULATE, GL_MODULATE, 1, 1);
2887 R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
2889 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2890 R_Mesh_TexBind(1, r_shadow_attenuation2dtexture);
2891 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
2892 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
2893 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
2895 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2900 //R_Mesh_TexBind(0, basetexture);
2901 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorbase, ambientcolorbase);
2904 R_Mesh_TexBind(0, pantstexture);
2905 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorpants, ambientcolorpants);
2909 R_Mesh_TexBind(0, shirttexture);
2910 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorshirt, ambientcolorshirt);
2914 extern cvar_t gl_lightmaps;
2915 void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
2917 float ambientscale, diffusescale, specularscale;
2919 float lightcolor[3];
2920 VectorCopy(rsurface.rtlight->currentcolor, lightcolor);
2921 ambientscale = rsurface.rtlight->ambientscale;
2922 diffusescale = rsurface.rtlight->diffusescale;
2923 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
2924 if (!r_shadow_usenormalmap.integer)
2926 ambientscale += 1.0f * diffusescale;
2930 if ((ambientscale + diffusescale) * VectorLength2(lightcolor) + specularscale * VectorLength2(lightcolor) < (1.0f / 1048576.0f))
2932 negated = (lightcolor[0] + lightcolor[1] + lightcolor[2] < 0) && vid.support.ext_blend_subtract;
2935 VectorNegate(lightcolor, lightcolor);
2936 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
2938 RSurf_SetupDepthAndCulling();
2939 switch (r_shadow_rendermode)
2941 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2942 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2943 R_Shadow_RenderLighting_VisibleLighting(texturenumsurfaces, texturesurfacelist);
2945 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2946 R_Shadow_RenderLighting_Light_GLSL(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale, specularscale);
2948 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2949 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2950 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2951 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2952 R_Shadow_RenderLighting_Light_Vertex(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale);
2955 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2959 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
2962 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)
2964 matrix4x4_t tempmatrix = *matrix;
2965 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
2967 // if this light has been compiled before, free the associated data
2968 R_RTLight_Uncompile(rtlight);
2970 // clear it completely to avoid any lingering data
2971 memset(rtlight, 0, sizeof(*rtlight));
2973 // copy the properties
2974 rtlight->matrix_lighttoworld = tempmatrix;
2975 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
2976 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
2977 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
2978 VectorCopy(color, rtlight->color);
2979 rtlight->cubemapname[0] = 0;
2980 if (cubemapname && cubemapname[0])
2981 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
2982 rtlight->shadow = shadow;
2983 rtlight->corona = corona;
2984 rtlight->style = style;
2985 rtlight->isstatic = isstatic;
2986 rtlight->coronasizescale = coronasizescale;
2987 rtlight->ambientscale = ambientscale;
2988 rtlight->diffusescale = diffusescale;
2989 rtlight->specularscale = specularscale;
2990 rtlight->flags = flags;
2992 // compute derived data
2993 //rtlight->cullradius = rtlight->radius;
2994 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2995 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2996 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2997 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2998 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2999 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3000 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3003 // compiles rtlight geometry
3004 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
3005 void R_RTLight_Compile(rtlight_t *rtlight)
3008 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
3009 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
3010 entity_render_t *ent = r_refdef.scene.worldentity;
3011 dp_model_t *model = r_refdef.scene.worldmodel;
3012 unsigned char *data;
3015 // compile the light
3016 rtlight->compiled = true;
3017 rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
3018 rtlight->static_numleafs = 0;
3019 rtlight->static_numleafpvsbytes = 0;
3020 rtlight->static_leaflist = NULL;
3021 rtlight->static_leafpvs = NULL;
3022 rtlight->static_numsurfaces = 0;
3023 rtlight->static_surfacelist = NULL;
3024 rtlight->static_shadowmap_receivers = 0x3F;
3025 rtlight->static_shadowmap_casters = 0x3F;
3026 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3027 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3028 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3029 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3030 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3031 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3033 if (model && model->GetLightInfo)
3035 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
3036 r_shadow_compilingrtlight = rtlight;
3037 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);
3038 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
3039 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
3040 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3041 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
3042 rtlight->static_numsurfaces = numsurfaces;
3043 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
3044 rtlight->static_numleafs = numleafs;
3045 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
3046 rtlight->static_numleafpvsbytes = numleafpvsbytes;
3047 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
3048 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
3049 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
3050 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
3051 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3052 if (rtlight->static_numsurfaces)
3053 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3054 if (rtlight->static_numleafs)
3055 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3056 if (rtlight->static_numleafpvsbytes)
3057 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3058 if (rtlight->static_numshadowtrispvsbytes)
3059 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3060 if (rtlight->static_numlighttrispvsbytes)
3061 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3062 switch (rtlight->shadowmode)
3064 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
3065 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
3066 case R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE:
3067 if (model->CompileShadowMap && rtlight->shadow)
3068 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3071 if (model->CompileShadowVolume && rtlight->shadow)
3072 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3075 // now we're done compiling the rtlight
3076 r_shadow_compilingrtlight = NULL;
3080 // use smallest available cullradius - box radius or light radius
3081 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3082 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3084 shadowzpasstris = 0;
3085 if (rtlight->static_meshchain_shadow_zpass)
3086 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
3087 shadowzpasstris += mesh->numtriangles;
3089 shadowzfailtris = 0;
3090 if (rtlight->static_meshchain_shadow_zfail)
3091 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
3092 shadowzfailtris += mesh->numtriangles;
3095 if (rtlight->static_numlighttrispvsbytes)
3096 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3097 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3101 if (rtlight->static_numlighttrispvsbytes)
3102 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3103 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3106 if (developer_extra.integer)
3107 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);
3110 void R_RTLight_Uncompile(rtlight_t *rtlight)
3112 if (rtlight->compiled)
3114 if (rtlight->static_meshchain_shadow_zpass)
3115 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
3116 rtlight->static_meshchain_shadow_zpass = NULL;
3117 if (rtlight->static_meshchain_shadow_zfail)
3118 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
3119 rtlight->static_meshchain_shadow_zfail = NULL;
3120 if (rtlight->static_meshchain_shadow_shadowmap)
3121 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
3122 rtlight->static_meshchain_shadow_shadowmap = NULL;
3123 // these allocations are grouped
3124 if (rtlight->static_surfacelist)
3125 Mem_Free(rtlight->static_surfacelist);
3126 rtlight->static_numleafs = 0;
3127 rtlight->static_numleafpvsbytes = 0;
3128 rtlight->static_leaflist = NULL;
3129 rtlight->static_leafpvs = NULL;
3130 rtlight->static_numsurfaces = 0;
3131 rtlight->static_surfacelist = NULL;
3132 rtlight->static_numshadowtrispvsbytes = 0;
3133 rtlight->static_shadowtrispvs = NULL;
3134 rtlight->static_numlighttrispvsbytes = 0;
3135 rtlight->static_lighttrispvs = NULL;
3136 rtlight->compiled = false;
3140 void R_Shadow_UncompileWorldLights(void)
3144 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3145 for (lightindex = 0;lightindex < range;lightindex++)
3147 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3150 R_RTLight_Uncompile(&light->rtlight);
3154 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3158 // reset the count of frustum planes
3159 // see rtlight->cached_frustumplanes definition for how much this array
3161 rtlight->cached_numfrustumplanes = 0;
3163 // haven't implemented a culling path for ortho rendering
3164 if (!r_refdef.view.useperspective)
3166 // check if the light is on screen and copy the 4 planes if it is
3167 for (i = 0;i < 4;i++)
3168 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3171 for (i = 0;i < 4;i++)
3172 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3177 // generate a deformed frustum that includes the light origin, this is
3178 // used to cull shadow casting surfaces that can not possibly cast a
3179 // shadow onto the visible light-receiving surfaces, which can be a
3182 // if the light origin is onscreen the result will be 4 planes exactly
3183 // if the light origin is offscreen on only one axis the result will
3184 // be exactly 5 planes (split-side case)
3185 // if the light origin is offscreen on two axes the result will be
3186 // exactly 4 planes (stretched corner case)
3187 for (i = 0;i < 4;i++)
3189 // quickly reject standard frustum planes that put the light
3190 // origin outside the frustum
3191 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3194 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3196 // if all the standard frustum planes were accepted, the light is onscreen
3197 // otherwise we need to generate some more planes below...
3198 if (rtlight->cached_numfrustumplanes < 4)
3200 // at least one of the stock frustum planes failed, so we need to
3201 // create one or two custom planes to enclose the light origin
3202 for (i = 0;i < 4;i++)
3204 // create a plane using the view origin and light origin, and a
3205 // single point from the frustum corner set
3206 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3207 VectorNormalize(plane.normal);
3208 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3209 // see if this plane is backwards and flip it if so
3210 for (j = 0;j < 4;j++)
3211 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3215 VectorNegate(plane.normal, plane.normal);
3217 // flipped plane, test again to see if it is now valid
3218 for (j = 0;j < 4;j++)
3219 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3221 // if the plane is still not valid, then it is dividing the
3222 // frustum and has to be rejected
3226 // we have created a valid plane, compute extra info
3227 PlaneClassify(&plane);
3229 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3231 // if we've found 5 frustum planes then we have constructed a
3232 // proper split-side case and do not need to keep searching for
3233 // planes to enclose the light origin
3234 if (rtlight->cached_numfrustumplanes == 5)
3242 for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
3244 plane = rtlight->cached_frustumplanes[i];
3245 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));
3250 // now add the light-space box planes if the light box is rotated, as any
3251 // caster outside the oriented light box is irrelevant (even if it passed
3252 // the worldspace light box, which is axial)
3253 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3255 for (i = 0;i < 6;i++)
3259 v[i >> 1] = (i & 1) ? -1 : 1;
3260 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3261 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3262 plane.dist = VectorNormalizeLength(plane.normal);
3263 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3264 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3270 // add the world-space reduced box planes
3271 for (i = 0;i < 6;i++)
3273 VectorClear(plane.normal);
3274 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3275 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
3276 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3285 // reduce all plane distances to tightly fit the rtlight cull box, which
3287 VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3288 VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3289 VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3290 VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3291 VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3292 VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3293 VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3294 VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3295 oldnum = rtlight->cached_numfrustumplanes;
3296 rtlight->cached_numfrustumplanes = 0;
3297 for (j = 0;j < oldnum;j++)
3299 // find the nearest point on the box to this plane
3300 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
3301 for (i = 1;i < 8;i++)
3303 dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
3304 if (bestdist > dist)
3307 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);
3308 // if the nearest point is near or behind the plane, we want this
3309 // plane, otherwise the plane is useless as it won't cull anything
3310 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
3312 PlaneClassify(&rtlight->cached_frustumplanes[j]);
3313 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
3320 void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
3324 RSurf_ActiveWorldEntity();
3326 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3329 GL_CullFace(GL_NONE);
3330 mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3331 for (;mesh;mesh = mesh->next)
3333 if (!mesh->sidetotals[r_shadow_shadowmapside])
3335 r_refdef.stats.lights_shadowtriangles += mesh->sidetotals[r_shadow_shadowmapside];
3336 R_Mesh_PrepareVertices_Position(mesh->numverts, mesh->vertexposition, mesh->vertexpositionbuffer);
3337 R_Mesh_Draw(0, mesh->numverts, mesh->sideoffsets[r_shadow_shadowmapside], mesh->sidetotals[r_shadow_shadowmapside], mesh->element3i, mesh->element3i_indexbuffer, mesh->element3i_bufferoffset, mesh->element3s, mesh->element3s_indexbuffer, mesh->element3s_bufferoffset);
3341 else if (r_refdef.scene.worldentity->model)
3342 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);
3344 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3347 void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3349 qboolean zpass = false;
3352 int surfacelistindex;
3353 msurface_t *surface;
3355 RSurf_ActiveWorldEntity();
3357 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3360 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
3362 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
3363 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
3365 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
3366 for (;mesh;mesh = mesh->next)
3368 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
3369 R_Mesh_PrepareVertices_Position(mesh->numverts, mesh->vertexposition, mesh->vertexpositionbuffer);
3370 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
3372 // increment stencil if frontface is infront of depthbuffer
3373 GL_CullFace(r_refdef.view.cullface_back);
3374 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
3375 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3i_indexbuffer, mesh->element3i_bufferoffset, mesh->element3s, mesh->element3s_indexbuffer, mesh->element3s_bufferoffset);
3376 // decrement stencil if backface is infront of depthbuffer
3377 GL_CullFace(r_refdef.view.cullface_front);
3378 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
3380 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
3382 // decrement stencil if backface is behind depthbuffer
3383 GL_CullFace(r_refdef.view.cullface_front);
3384 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
3385 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3i_indexbuffer, mesh->element3i_bufferoffset, mesh->element3s, mesh->element3s_indexbuffer, mesh->element3s_bufferoffset);
3386 // increment stencil if frontface is behind depthbuffer
3387 GL_CullFace(r_refdef.view.cullface_back);
3388 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
3390 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3i_indexbuffer, mesh->element3i_bufferoffset, mesh->element3s, mesh->element3s_indexbuffer, mesh->element3s_bufferoffset);
3394 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh)
3396 // use the shadow trispvs calculated earlier by GetLightInfo to cull world triangles on this dynamic light
3397 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
3398 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
3400 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
3401 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
3402 if (CHECKPVSBIT(trispvs, t))
3403 shadowmarklist[numshadowmark++] = t;
3405 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);
3407 else if (numsurfaces)
3408 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);
3410 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3413 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3415 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3416 vec_t relativeshadowradius;
3417 RSurf_ActiveModelEntity(ent, false, false, false);
3418 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3419 // we need to re-init the shader for each entity because the matrix changed
3420 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3421 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3422 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3423 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3424 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3425 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3426 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3427 switch (r_shadow_rendermode)
3429 case R_SHADOW_RENDERMODE_SHADOWMAP2D:
3430 case R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE:
3431 case R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE:
3432 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
3435 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3438 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3441 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3443 // set up properties for rendering light onto this entity
3444 RSurf_ActiveModelEntity(ent, true, true, false);
3445 GL_AlphaTest(false);
3446 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3447 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3448 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3449 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3452 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
3454 if (!r_refdef.scene.worldmodel->DrawLight)
3457 // set up properties for rendering light onto this entity
3458 RSurf_ActiveWorldEntity();
3459 GL_AlphaTest(false);
3460 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3461 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3462 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3463 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3465 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
3467 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3470 void R_Shadow_DrawEntityLight(entity_render_t *ent)
3472 dp_model_t *model = ent->model;
3473 if (!model->DrawLight)
3476 R_Shadow_SetupEntityLight(ent);
3478 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3480 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3483 void R_Shadow_PrepareLight(rtlight_t *rtlight)
3487 int numleafs, numsurfaces;
3488 int *leaflist, *surfacelist;
3489 unsigned char *leafpvs;
3490 unsigned char *shadowtrispvs;
3491 unsigned char *lighttrispvs;
3492 //unsigned char *surfacesides;
3493 int numlightentities;
3494 int numlightentities_noselfshadow;
3495 int numshadowentities;
3496 int numshadowentities_noselfshadow;
3497 static entity_render_t *lightentities[MAX_EDICTS];
3498 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3499 static entity_render_t *shadowentities[MAX_EDICTS];
3500 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3503 rtlight->draw = false;
3505 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3506 // skip lights that are basically invisible (color 0 0 0)
3507 nolight = VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f);
3509 // loading is done before visibility checks because loading should happen
3510 // all at once at the start of a level, not when it stalls gameplay.
3511 // (especially important to benchmarks)
3513 if (rtlight->isstatic && !nolight && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
3515 if (rtlight->compiled)
3516 R_RTLight_Uncompile(rtlight);
3517 R_RTLight_Compile(rtlight);
3521 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
3523 // look up the light style value at this time
3524 f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3525 VectorScale(rtlight->color, f, rtlight->currentcolor);
3527 if (rtlight->selected)
3529 f = 2 + sin(realtime * M_PI * 4.0);
3530 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3534 // if lightstyle is currently off, don't draw the light
3535 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3538 // skip processing on corona-only lights
3542 // if the light box is offscreen, skip it
3543 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3546 VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
3547 VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
3549 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3551 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3553 // compiled light, world available and can receive realtime lighting
3554 // retrieve leaf information
3555 numleafs = rtlight->static_numleafs;
3556 leaflist = rtlight->static_leaflist;
3557 leafpvs = rtlight->static_leafpvs;
3558 numsurfaces = rtlight->static_numsurfaces;
3559 surfacelist = rtlight->static_surfacelist;
3560 //surfacesides = NULL;
3561 shadowtrispvs = rtlight->static_shadowtrispvs;
3562 lighttrispvs = rtlight->static_lighttrispvs;
3564 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3566 // dynamic light, world available and can receive realtime lighting
3567 // calculate lit surfaces and leafs
3568 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);
3569 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3570 leaflist = r_shadow_buffer_leaflist;
3571 leafpvs = r_shadow_buffer_leafpvs;
3572 surfacelist = r_shadow_buffer_surfacelist;
3573 //surfacesides = r_shadow_buffer_surfacesides;
3574 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3575 lighttrispvs = r_shadow_buffer_lighttrispvs;
3576 // if the reduced leaf bounds are offscreen, skip it
3577 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3588 //surfacesides = NULL;
3589 shadowtrispvs = NULL;
3590 lighttrispvs = NULL;
3592 // check if light is illuminating any visible leafs
3595 for (i = 0;i < numleafs;i++)
3596 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3602 // make a list of lit entities and shadow casting entities
3603 numlightentities = 0;
3604 numlightentities_noselfshadow = 0;
3605 numshadowentities = 0;
3606 numshadowentities_noselfshadow = 0;
3608 // add dynamic entities that are lit by the light
3609 for (i = 0;i < r_refdef.scene.numentities;i++)
3612 entity_render_t *ent = r_refdef.scene.entities[i];
3614 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3616 // skip the object entirely if it is not within the valid
3617 // shadow-casting region (which includes the lit region)
3618 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
3620 if (!(model = ent->model))
3622 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
3624 // this entity wants to receive light, is visible, and is
3625 // inside the light box
3626 // TODO: check if the surfaces in the model can receive light
3627 // so now check if it's in a leaf seen by the light
3628 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))
3630 if (ent->flags & RENDER_NOSELFSHADOW)
3631 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
3633 lightentities[numlightentities++] = ent;
3634 // since it is lit, it probably also casts a shadow...
3635 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3636 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3637 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3639 // note: exterior models without the RENDER_NOSELFSHADOW
3640 // flag still create a RENDER_NOSELFSHADOW shadow but
3641 // are lit normally, this means that they are
3642 // self-shadowing but do not shadow other
3643 // RENDER_NOSELFSHADOW entities such as the gun
3644 // (very weird, but keeps the player shadow off the gun)
3645 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3646 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3648 shadowentities[numshadowentities++] = ent;
3651 else if (ent->flags & RENDER_SHADOW)
3653 // this entity is not receiving light, but may still need to
3655 // TODO: check if the surfaces in the model can cast shadow
3656 // now check if it is in a leaf seen by the light
3657 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))
3659 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3660 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3661 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3663 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3664 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3666 shadowentities[numshadowentities++] = ent;
3671 // return if there's nothing at all to light
3672 if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
3675 // count this light in the r_speeds
3676 r_refdef.stats.lights++;
3678 // flag it as worth drawing later
3679 rtlight->draw = true;
3681 // cache all the animated entities that cast a shadow but are not visible
3682 for (i = 0;i < numshadowentities;i++)
3683 if (!shadowentities[i]->animcache_vertex3f)
3684 R_AnimCache_GetEntity(shadowentities[i], false, false);
3685 for (i = 0;i < numshadowentities_noselfshadow;i++)
3686 if (!shadowentities_noselfshadow[i]->animcache_vertex3f)
3687 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
3689 // allocate some temporary memory for rendering this light later in the frame
3690 // reusable buffers need to be copied, static data can be used as-is
3691 rtlight->cached_numlightentities = numlightentities;
3692 rtlight->cached_numlightentities_noselfshadow = numlightentities_noselfshadow;
3693 rtlight->cached_numshadowentities = numshadowentities;
3694 rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
3695 rtlight->cached_numsurfaces = numsurfaces;
3696 rtlight->cached_lightentities = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
3697 rtlight->cached_lightentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
3698 rtlight->cached_shadowentities = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
3699 rtlight->cached_shadowentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
3700 if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
3702 int numshadowtrispvsbytes = (((r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles) + 7) >> 3);
3703 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
3704 rtlight->cached_shadowtrispvs = (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
3705 rtlight->cached_lighttrispvs = (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
3706 rtlight->cached_surfacelist = (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
3710 // compiled light data
3711 rtlight->cached_shadowtrispvs = shadowtrispvs;
3712 rtlight->cached_lighttrispvs = lighttrispvs;
3713 rtlight->cached_surfacelist = surfacelist;
3717 void R_Shadow_DrawLight(rtlight_t *rtlight)
3721 unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
3722 int numlightentities;
3723 int numlightentities_noselfshadow;
3724 int numshadowentities;
3725 int numshadowentities_noselfshadow;
3726 entity_render_t **lightentities;
3727 entity_render_t **lightentities_noselfshadow;
3728 entity_render_t **shadowentities;
3729 entity_render_t **shadowentities_noselfshadow;
3731 static unsigned char entitysides[MAX_EDICTS];
3732 static unsigned char entitysides_noselfshadow[MAX_EDICTS];
3733 vec3_t nearestpoint;
3735 qboolean castshadows;
3738 // check if we cached this light this frame (meaning it is worth drawing)
3742 // if R_FrameData_Store ran out of space we skip anything dependent on it
3743 if (r_framedata_failed)
3746 numlightentities = rtlight->cached_numlightentities;
3747 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
3748 numshadowentities = rtlight->cached_numshadowentities;
3749 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
3750 numsurfaces = rtlight->cached_numsurfaces;
3751 lightentities = rtlight->cached_lightentities;
3752 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
3753 shadowentities = rtlight->cached_shadowentities;
3754 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
3755 shadowtrispvs = rtlight->cached_shadowtrispvs;
3756 lighttrispvs = rtlight->cached_lighttrispvs;
3757 surfacelist = rtlight->cached_surfacelist;
3759 // set up a scissor rectangle for this light
3760 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3763 // don't let sound skip if going slow
3764 if (r_refdef.scene.extraupdate)
3767 // make this the active rtlight for rendering purposes
3768 R_Shadow_RenderMode_ActiveLight(rtlight);
3770 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
3772 // optionally draw visible shape of the shadow volumes
3773 // for performance analysis by level designers
3774 R_Shadow_RenderMode_VisibleShadowVolumes();
3776 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
3777 for (i = 0;i < numshadowentities;i++)
3778 R_Shadow_DrawEntityShadow(shadowentities[i]);
3779 for (i = 0;i < numshadowentities_noselfshadow;i++)
3780 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3781 R_Shadow_RenderMode_VisibleLighting(false, false);
3784 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
3786 // optionally draw the illuminated areas
3787 // for performance analysis by level designers
3788 R_Shadow_RenderMode_VisibleLighting(false, false);
3790 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3791 for (i = 0;i < numlightentities;i++)
3792 R_Shadow_DrawEntityLight(lightentities[i]);
3793 for (i = 0;i < numlightentities_noselfshadow;i++)
3794 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3797 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
3799 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
3800 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
3801 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
3802 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
3804 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance/rtlight->radius));
3805 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
3806 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
3808 if (castshadows && (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE))
3814 int receivermask = 0;
3815 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
3816 Matrix4x4_Abs(&radiustolight);
3818 r_shadow_shadowmaplod = 0;
3819 for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
3820 if ((r_shadow_shadowmapmaxsize >> i) > lodlinear)
3821 r_shadow_shadowmaplod = i;
3823 if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
3824 size = max(1, r_shadow_shadowmapmaxsize >> r_shadow_shadowmaplod);
3826 size = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
3828 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
3830 surfacesides = NULL;
3833 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3835 castermask = rtlight->static_shadowmap_casters;
3836 receivermask = rtlight->static_shadowmap_receivers;
3840 surfacesides = r_shadow_buffer_surfacesides;
3841 for(i = 0;i < numsurfaces;i++)
3843 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
3844 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3845 castermask |= surfacesides[i];
3846 receivermask |= surfacesides[i];
3850 if (receivermask < 0x3F)
3852 for (i = 0;i < numlightentities;i++)
3853 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3854 if (receivermask < 0x3F)
3855 for(i = 0; i < numlightentities_noselfshadow;i++)
3856 receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3859 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
3863 for (i = 0;i < numshadowentities;i++)
3864 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3865 for (i = 0;i < numshadowentities_noselfshadow;i++)
3866 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3869 //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
3871 // render shadow casters into 6 sided depth texture
3872 for (side = 0;side < 6;side++) if (receivermask & (1 << side))
3874 R_Shadow_RenderMode_ShadowMap(side, receivermask, size);
3875 if (! (castermask & (1 << side))) continue;
3877 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
3878 for (i = 0;i < numshadowentities;i++) if (entitysides[i] & (1 << side))
3879 R_Shadow_DrawEntityShadow(shadowentities[i]);
3882 if (numlightentities_noselfshadow)
3884 // render lighting using the depth texture as shadowmap
3885 // draw lighting in the unmasked areas
3886 R_Shadow_RenderMode_Lighting(false, false, true);
3887 for (i = 0;i < numlightentities_noselfshadow;i++)
3888 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3891 // render shadow casters into 6 sided depth texture
3892 if (numshadowentities_noselfshadow)
3894 for (side = 0;side < 6;side++) if ((receivermask & castermask) & (1 << side))
3896 R_Shadow_RenderMode_ShadowMap(side, 0, size);
3897 for (i = 0;i < numshadowentities_noselfshadow;i++) if (entitysides_noselfshadow[i] & (1 << side))
3898 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3902 // render lighting using the depth texture as shadowmap
3903 // draw lighting in the unmasked areas
3904 R_Shadow_RenderMode_Lighting(false, false, true);
3905 // draw lighting in the unmasked areas
3907 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3908 for (i = 0;i < numlightentities;i++)
3909 R_Shadow_DrawEntityLight(lightentities[i]);
3911 else if (castshadows && vid.stencil)
3913 // draw stencil shadow volumes to mask off pixels that are in shadow
3914 // so that they won't receive lighting
3915 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
3916 R_Shadow_ClearStencil();
3919 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
3920 for (i = 0;i < numshadowentities;i++)
3921 R_Shadow_DrawEntityShadow(shadowentities[i]);
3923 // draw lighting in the unmasked areas
3924 R_Shadow_RenderMode_Lighting(true, false, false);
3925 for (i = 0;i < numlightentities_noselfshadow;i++)
3926 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3928 for (i = 0;i < numshadowentities_noselfshadow;i++)
3929 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3931 // draw lighting in the unmasked areas
3932 R_Shadow_RenderMode_Lighting(true, false, false);
3934 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3935 for (i = 0;i < numlightentities;i++)
3936 R_Shadow_DrawEntityLight(lightentities[i]);
3940 // draw lighting in the unmasked areas
3941 R_Shadow_RenderMode_Lighting(false, false, false);
3943 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3944 for (i = 0;i < numlightentities;i++)
3945 R_Shadow_DrawEntityLight(lightentities[i]);
3946 for (i = 0;i < numlightentities_noselfshadow;i++)
3947 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3950 if (r_shadow_usingdeferredprepass)
3952 // when rendering deferred lighting, we simply rasterize the box
3953 if (castshadows && (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE))
3954 R_Shadow_RenderMode_DrawDeferredLight(false, true);
3955 else if (castshadows && vid.stencil)
3956 R_Shadow_RenderMode_DrawDeferredLight(true, false);
3958 R_Shadow_RenderMode_DrawDeferredLight(false, false);
3962 static void R_Shadow_FreeDeferred(void)
3964 if (r_shadow_prepassgeometryfbo)
3965 qglDeleteFramebuffersEXT(1, &r_shadow_prepassgeometryfbo);CHECKGLERROR
3966 r_shadow_prepassgeometryfbo = 0;
3968 if (r_shadow_prepasslightingfbo)
3969 qglDeleteFramebuffersEXT(1, &r_shadow_prepasslightingfbo);CHECKGLERROR
3970 r_shadow_prepasslightingfbo = 0;
3972 if (r_shadow_prepassgeometrydepthtexture)
3973 R_FreeTexture(r_shadow_prepassgeometrydepthtexture);
3974 r_shadow_prepassgeometrydepthtexture = NULL;
3976 if (r_shadow_prepassgeometrynormalmaptexture)
3977 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
3978 r_shadow_prepassgeometrynormalmaptexture = NULL;
3980 if (r_shadow_prepasslightingdiffusetexture)
3981 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
3982 r_shadow_prepasslightingdiffusetexture = NULL;
3984 if (r_shadow_prepasslightingspeculartexture)
3985 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
3986 r_shadow_prepasslightingspeculartexture = NULL;
3989 void R_Shadow_DrawPrepass(void)
3997 entity_render_t *ent;
3999 GL_AlphaTest(false);
4000 R_Mesh_ResetTextureState();
4002 GL_ColorMask(1,1,1,1);
4003 GL_BlendFunc(GL_ONE, GL_ZERO);
4006 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepassgeometryfbo);CHECKGLERROR
4007 qglClearColor(0.5f,0.5f,0.5f,1.0f);CHECKGLERROR
4008 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);CHECKGLERROR
4010 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
4011 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
4012 if (r_timereport_active)
4013 R_TimeReport("prepassworld");
4015 for (i = 0;i < r_refdef.scene.numentities;i++)
4017 if (!r_refdef.viewcache.entityvisible[i])
4019 ent = r_refdef.scene.entities[i];
4020 if (ent->model && ent->model->DrawPrepass != NULL)
4021 ent->model->DrawPrepass(ent);
4024 if (r_timereport_active)
4025 R_TimeReport("prepassmodels");
4027 GL_DepthMask(false);
4028 GL_ColorMask(1,1,1,1);
4031 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepasslightingfbo);CHECKGLERROR
4032 qglClearColor(0.0f,0.0f,0.0f,0.0f);CHECKGLERROR
4033 GL_Clear(GL_COLOR_BUFFER_BIT);CHECKGLERROR
4034 if (r_refdef.fogenabled)
4035 qglClearColor(r_refdef.fogcolor[0],r_refdef.fogcolor[1],r_refdef.fogcolor[2],0);CHECKGLERROR
4037 R_Shadow_RenderMode_Begin();
4039 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4040 if (r_shadow_debuglight.integer >= 0)
4042 lightindex = r_shadow_debuglight.integer;
4043 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4044 if (light && (light->flags & flag))
4045 R_Shadow_DrawLight(&light->rtlight);
4049 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4050 for (lightindex = 0;lightindex < range;lightindex++)
4052 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4053 if (light && (light->flags & flag))
4054 R_Shadow_DrawLight(&light->rtlight);
4057 if (r_refdef.scene.rtdlight)
4058 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4059 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4061 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);CHECKGLERROR
4062 if (r_refdef.fogenabled)
4063 qglClearColor(r_refdef.fogcolor[0],r_refdef.fogcolor[1],r_refdef.fogcolor[2],0);CHECKGLERROR
4065 R_Shadow_RenderMode_End();
4067 if (r_timereport_active)
4068 R_TimeReport("prepasslights");
4071 void R_Shadow_DrawLightSprites(void);
4072 void R_Shadow_PrepareLights(void)
4082 if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4) ||
4083 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
4084 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0) ||
4085 r_shadow_shadowmaptexturetype != r_shadow_shadowmapping_texturetype.integer ||
4086 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
4087 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
4088 r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
4089 R_Shadow_FreeShadowMaps();
4091 r_shadow_usingshadowmaportho = false;
4093 switch (vid.renderpath)
4095 case RENDERPATH_GL20:
4096 case RENDERPATH_CGGL:
4097 if (!r_shadow_deferred.integer || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_STENCIL || !vid.support.ext_framebuffer_object || vid.maxdrawbuffers < 2)
4099 r_shadow_usingdeferredprepass = false;
4100 if (r_shadow_prepass_width)
4101 R_Shadow_FreeDeferred();
4102 r_shadow_prepass_width = r_shadow_prepass_height = 0;
4106 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
4108 R_Shadow_FreeDeferred();
4110 r_shadow_usingdeferredprepass = true;
4111 r_shadow_prepass_width = vid.width;
4112 r_shadow_prepass_height = vid.height;
4113 r_shadow_prepassgeometrydepthtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "prepassgeometrydepthmap", vid.width, vid.height, 24, false);
4114 r_shadow_prepassgeometrynormalmaptexture = R_LoadTexture2D(r_shadow_texturepool, "prepassgeometrynormalmap", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, NULL);
4115 r_shadow_prepasslightingdiffusetexture = R_LoadTexture2D(r_shadow_texturepool, "prepasslightingdiffuse", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, NULL);
4116 r_shadow_prepasslightingspeculartexture = R_LoadTexture2D(r_shadow_texturepool, "prepasslightingspecular", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, NULL);
4118 // set up the geometry pass fbo (depth + normalmap)
4119 qglGenFramebuffersEXT(1, &r_shadow_prepassgeometryfbo);CHECKGLERROR
4120 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepassgeometryfbo);CHECKGLERROR
4121 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_prepassgeometrydepthtexture), 0);CHECKGLERROR
4122 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_prepassgeometrynormalmaptexture), 0);CHECKGLERROR
4123 // render depth into one texture and normalmap into the other
4124 if (qglDrawBuffersARB)
4126 qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);CHECKGLERROR
4127 qglReadBuffer(GL_NONE);CHECKGLERROR
4129 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4130 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4132 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4133 Cvar_SetValueQuick(&r_shadow_deferred, 0);
4134 r_shadow_usingdeferredprepass = false;
4137 // set up the lighting pass fbo (diffuse + specular)
4138 qglGenFramebuffersEXT(1, &r_shadow_prepasslightingfbo);CHECKGLERROR
4139 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepasslightingfbo);CHECKGLERROR
4140 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_prepassgeometrydepthtexture), 0);CHECKGLERROR
4141 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_prepasslightingdiffusetexture), 0);CHECKGLERROR
4142 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_prepasslightingspeculartexture), 0);CHECKGLERROR
4143 // render diffuse into one texture and specular into another,
4144 // with depth and normalmap bound as textures,
4145 // with depth bound as attachment as well
4146 if (qglDrawBuffersARB)
4148 qglDrawBuffersARB(2, r_shadow_prepasslightingdrawbuffers);CHECKGLERROR
4149 qglReadBuffer(GL_NONE);CHECKGLERROR
4151 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4152 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4154 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4155 Cvar_SetValueQuick(&r_shadow_deferred, 0);
4156 r_shadow_usingdeferredprepass = false;
4160 case RENDERPATH_GL13:
4161 case RENDERPATH_GL11:
4162 r_shadow_usingdeferredprepass = false;
4166 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);
4168 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4169 if (r_shadow_debuglight.integer >= 0)
4171 lightindex = r_shadow_debuglight.integer;
4172 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4173 if (light && (light->flags & flag))
4174 R_Shadow_PrepareLight(&light->rtlight);
4178 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4179 for (lightindex = 0;lightindex < range;lightindex++)
4181 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4182 if (light && (light->flags & flag))
4183 R_Shadow_PrepareLight(&light->rtlight);
4186 if (r_refdef.scene.rtdlight)
4188 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4189 R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
4191 else if(gl_flashblend.integer)
4193 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4195 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
4196 f = (rtlight->style >= 0 ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4197 VectorScale(rtlight->color, f, rtlight->currentcolor);
4201 if (r_editlights.integer)
4202 R_Shadow_DrawLightSprites();
4205 void R_Shadow_DrawLights(void)
4213 R_Shadow_RenderMode_Begin();
4215 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4216 if (r_shadow_debuglight.integer >= 0)
4218 lightindex = r_shadow_debuglight.integer;
4219 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4220 if (light && (light->flags & flag))
4221 R_Shadow_DrawLight(&light->rtlight);
4225 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4226 for (lightindex = 0;lightindex < range;lightindex++)
4228 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4229 if (light && (light->flags & flag))
4230 R_Shadow_DrawLight(&light->rtlight);
4233 if (r_refdef.scene.rtdlight)
4234 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4235 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4237 R_Shadow_RenderMode_End();
4240 extern const float r_screenvertex3f[12];
4241 extern void R_SetupView(qboolean allowwaterclippingplane);
4242 extern void R_ResetViewRendering3D(void);
4243 extern void R_ResetViewRendering2D(void);
4244 extern cvar_t r_shadows;
4245 extern cvar_t r_shadows_darken;
4246 extern cvar_t r_shadows_drawafterrtlighting;
4247 extern cvar_t r_shadows_castfrombmodels;
4248 extern cvar_t r_shadows_throwdistance;
4249 extern cvar_t r_shadows_throwdirection;
4250 extern cvar_t r_shadows_focus;
4251 extern cvar_t r_shadows_shadowmapscale;
4253 void R_Shadow_PrepareModelShadows(void)
4256 float scale, size, radius, dot1, dot2;
4257 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
4258 entity_render_t *ent;
4260 if (!r_refdef.scene.numentities)
4263 switch (r_shadow_shadowmode)
4265 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4266 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
4267 if (r_shadows.integer >= 2)
4270 case R_SHADOW_SHADOWMODE_STENCIL:
4271 for (i = 0;i < r_refdef.scene.numentities;i++)
4273 ent = r_refdef.scene.entities[i];
4274 if (!ent->animcache_vertex3f && ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4275 R_AnimCache_GetEntity(ent, false, false);
4282 size = 2*r_shadow_shadowmapmaxsize;
4283 scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
4284 radius = 0.5f * size / scale;
4286 Math_atov(r_shadows_throwdirection.string, shadowdir);
4287 VectorNormalize(shadowdir);
4288 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4289 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4290 if (fabs(dot1) <= fabs(dot2))
4291 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4293 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4294 VectorNormalize(shadowforward);
4295 CrossProduct(shadowdir, shadowforward, shadowright);
4296 Math_atov(r_shadows_focus.string, shadowfocus);
4297 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4298 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4299 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4300 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4301 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4303 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4305 shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4306 shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4307 shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4308 shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4309 shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4310 shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4312 for (i = 0;i < r_refdef.scene.numentities;i++)
4314 ent = r_refdef.scene.entities[i];
4315 if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
4317 // cast shadows from anything of the map (submodels are optional)
4318 if (!ent->animcache_vertex3f && ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4319 R_AnimCache_GetEntity(ent, false, false);
4323 void R_DrawModelShadowMaps(void)
4326 float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
4327 entity_render_t *ent;
4328 vec3_t relativelightorigin;
4329 vec3_t relativelightdirection, relativeforward, relativeright;
4330 vec3_t relativeshadowmins, relativeshadowmaxs;
4331 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
4333 matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
4334 r_viewport_t viewport;
4337 if (!r_refdef.scene.numentities)
4340 switch (r_shadow_shadowmode)
4342 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4343 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
4350 R_ResetViewRendering3D();
4351 R_Shadow_RenderMode_Begin();
4352 R_Shadow_RenderMode_ActiveLight(NULL);
4354 switch (r_shadow_shadowmode)
4356 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4357 if (!r_shadow_shadowmap2dtexture)
4358 R_Shadow_MakeShadowMap(0, r_shadow_shadowmapmaxsize);
4359 fbo = r_shadow_fbo2d;
4360 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
4361 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
4362 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
4364 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
4365 if (!r_shadow_shadowmaprectangletexture)
4366 R_Shadow_MakeShadowMap(0, r_shadow_shadowmapmaxsize);
4367 fbo = r_shadow_fborectangle;
4368 r_shadow_shadowmap_texturescale[0] = 1.0f;
4369 r_shadow_shadowmap_texturescale[1] = 1.0f;
4370 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE;
4376 size = 2*r_shadow_shadowmapmaxsize;
4377 scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
4378 radius = 0.5f / scale;
4379 nearclip = -r_shadows_throwdistance.value;
4380 farclip = r_shadows_throwdistance.value;
4381 bias = r_shadow_shadowmapping_bias.value * r_shadow_shadowmapping_nearclip.value / (2 * r_shadows_throwdistance.value) * (1024.0f / size);
4383 r_shadow_shadowmap_parameters[0] = size;
4384 r_shadow_shadowmap_parameters[1] = size;
4385 r_shadow_shadowmap_parameters[2] = 1.0;
4386 r_shadow_shadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
4388 Math_atov(r_shadows_throwdirection.string, shadowdir);
4389 VectorNormalize(shadowdir);
4390 Math_atov(r_shadows_focus.string, shadowfocus);
4391 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4392 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4393 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4394 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4395 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4396 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4397 if (fabs(dot1) <= fabs(dot2))
4398 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4400 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4401 VectorNormalize(shadowforward);
4402 VectorM(scale, shadowforward, &m[0]);
4403 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4405 m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
4406 CrossProduct(shadowdir, shadowforward, shadowright);
4407 VectorM(scale, shadowright, &m[4]);
4408 m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
4409 VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
4410 m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
4411 Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
4412 Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
4413 R_Viewport_InitOrtho(&viewport, &cameramatrix, 0, 0, size, size, 0, 0, 1, 1, 0, -1, NULL);
4415 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4418 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);CHECKGLERROR
4419 R_SetupShader_ShowDepth();
4421 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);CHECKGLERROR
4422 R_SetupShader_DepthOrShadow();
4425 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
4428 R_SetViewport(&viewport);
4429 GL_Scissor(viewport.x, viewport.y, min(viewport.width + r_shadow_shadowmapborder, 2*r_shadow_shadowmapmaxsize), viewport.height + r_shadow_shadowmapborder);
4432 qglClearColor(1,1,1,1);
4433 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
4435 GL_Clear(GL_DEPTH_BUFFER_BIT);
4437 GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
4440 for (i = 0;i < r_refdef.scene.numentities;i++)
4442 ent = r_refdef.scene.entities[i];
4444 // cast shadows from anything of the map (submodels are optional)
4445 if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4447 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4448 Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
4449 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4450 Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
4451 Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
4452 relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4453 relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4454 relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4455 relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4456 relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4457 relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4458 RSurf_ActiveModelEntity(ent, false, false, false);
4459 ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
4460 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4464 R_Shadow_RenderMode_End();
4466 Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
4467 Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
4468 Matrix4x4_CreateScale3(&scalematrix, size, -size, 1);
4469 Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
4470 Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
4471 Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
4473 r_shadow_usingshadowmaportho = true;
4474 switch (r_shadow_shadowmode)
4476 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4477 r_shadow_usingshadowmap2d = true;
4479 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
4480 r_shadow_usingshadowmaprect = true;
4487 void R_DrawModelShadows(void)
4490 float relativethrowdistance;
4491 entity_render_t *ent;
4492 vec3_t relativelightorigin;
4493 vec3_t relativelightdirection;
4494 vec3_t relativeshadowmins, relativeshadowmaxs;
4495 vec3_t tmp, shadowdir;
4497 if (!r_refdef.scene.numentities || !vid.stencil || (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL && r_shadows.integer != 1))
4501 R_ResetViewRendering3D();
4502 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4503 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4504 R_Shadow_RenderMode_Begin();
4505 R_Shadow_RenderMode_ActiveLight(NULL);
4506 r_shadow_lightscissor[0] = r_refdef.view.x;
4507 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
4508 r_shadow_lightscissor[2] = r_refdef.view.width;
4509 r_shadow_lightscissor[3] = r_refdef.view.height;
4510 R_Shadow_RenderMode_StencilShadowVolumes(false);
4513 if (r_shadows.integer == 2)
4515 Math_atov(r_shadows_throwdirection.string, shadowdir);
4516 VectorNormalize(shadowdir);
4519 R_Shadow_ClearStencil();
4521 for (i = 0;i < r_refdef.scene.numentities;i++)
4523 ent = r_refdef.scene.entities[i];
4525 // cast shadows from anything of the map (submodels are optional)
4526 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4528 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4529 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
4530 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
4531 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
4532 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4535 if(ent->entitynumber != 0)
4537 if(ent->entitynumber >= MAX_EDICTS) // csqc entity
4539 // FIXME handle this
4540 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4544 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
4545 int entnum, entnum2, recursion;
4546 entnum = entnum2 = ent->entitynumber;
4547 for(recursion = 32; recursion > 0; --recursion)
4549 entnum2 = cl.entities[entnum].state_current.tagentity;
4550 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
4555 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
4557 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
4558 // transform into modelspace of OUR entity
4559 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
4560 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
4563 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4567 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4570 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
4571 RSurf_ActiveModelEntity(ent, false, false, false);
4572 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4573 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4577 // not really the right mode, but this will disable any silly stencil features
4578 R_Shadow_RenderMode_End();
4580 // set up ortho view for rendering this pass
4581 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4582 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4583 //GL_ScissorTest(true);
4584 //R_EntityMatrix(&identitymatrix);
4585 //R_Mesh_ResetTextureState();
4586 R_ResetViewRendering2D();
4588 // set up a darkening blend on shadowed areas
4589 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4590 //GL_DepthRange(0, 1);
4591 //GL_DepthTest(false);
4592 //GL_DepthMask(false);
4593 //GL_PolygonOffset(0, 0);CHECKGLERROR
4594 GL_Color(0, 0, 0, r_shadows_darken.value);
4595 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4596 //qglDepthFunc(GL_ALWAYS);CHECKGLERROR
4597 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
4598 qglStencilMask(255);CHECKGLERROR
4599 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
4600 qglStencilFunc(GL_NOTEQUAL, 128, 255);CHECKGLERROR
4602 // apply the blend to the shadowed areas
4603 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, NULL);
4604 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
4605 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4607 // restore the viewport
4608 R_SetViewport(&r_refdef.view.viewport);
4610 // restore other state to normal
4611 //R_Shadow_RenderMode_End();
4614 void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4617 vec3_t centerorigin;
4619 // if it's too close, skip it
4620 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
4622 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4625 if (usequery && r_numqueries + 2 <= r_maxqueries)
4627 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4628 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4629 // 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
4630 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4633 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use qglDepthFunc instead
4634 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
4635 qglDepthFunc(GL_ALWAYS);
4636 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4637 R_Mesh_PrepareVertices_Position_Arrays(4, vertex3f);
4638 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4639 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4640 qglDepthFunc(GL_LEQUAL);
4641 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
4642 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4643 R_Mesh_PrepareVertices_Position_Arrays(4, vertex3f);
4644 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4645 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4648 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4651 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
4653 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4656 GLint allpixels = 0, visiblepixels = 0;
4657 // now we have to check the query result
4658 if (rtlight->corona_queryindex_visiblepixels)
4661 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
4662 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
4664 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
4665 if (visiblepixels < 1 || allpixels < 1)
4667 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
4668 cscale *= rtlight->corona_visibility;
4672 // FIXME: these traces should scan all render entities instead of cl.world
4673 if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
4676 VectorScale(rtlight->currentcolor, cscale, color);
4677 if (VectorLength(color) > (1.0f / 256.0f))
4680 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
4683 VectorNegate(color, color);
4684 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
4686 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4687 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);
4688 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4690 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
4694 void R_Shadow_DrawCoronas(void)
4702 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4704 if (r_waterstate.renderingscene)
4706 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4707 R_EntityMatrix(&identitymatrix);
4709 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4711 // check occlusion of coronas
4712 // use GL_ARB_occlusion_query if available
4713 // otherwise use raytraces
4715 usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
4718 GL_ColorMask(0,0,0,0);
4719 if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
4720 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
4723 r_maxqueries = (range + r_refdef.scene.numlights) * 4;
4724 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
4726 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
4729 RSurf_ActiveWorldEntity();
4730 GL_BlendFunc(GL_ONE, GL_ZERO);
4731 GL_CullFace(GL_NONE);
4732 GL_DepthMask(false);
4733 GL_DepthRange(0, 1);
4734 GL_PolygonOffset(0, 0);
4736 R_Mesh_ResetTextureState();
4737 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
4739 for (lightindex = 0;lightindex < range;lightindex++)
4741 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4744 rtlight = &light->rtlight;
4745 rtlight->corona_visibility = 0;
4746 rtlight->corona_queryindex_visiblepixels = 0;
4747 rtlight->corona_queryindex_allpixels = 0;
4748 if (!(rtlight->flags & flag))
4750 if (rtlight->corona <= 0)
4752 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4754 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4756 for (i = 0;i < r_refdef.scene.numlights;i++)
4758 rtlight = r_refdef.scene.lights[i];
4759 rtlight->corona_visibility = 0;
4760 rtlight->corona_queryindex_visiblepixels = 0;
4761 rtlight->corona_queryindex_allpixels = 0;
4762 if (!(rtlight->flags & flag))
4764 if (rtlight->corona <= 0)
4766 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4769 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4771 // now draw the coronas using the query data for intensity info
4772 for (lightindex = 0;lightindex < range;lightindex++)
4774 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4777 rtlight = &light->rtlight;
4778 if (rtlight->corona_visibility <= 0)
4780 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4782 for (i = 0;i < r_refdef.scene.numlights;i++)
4784 rtlight = r_refdef.scene.lights[i];
4785 if (rtlight->corona_visibility <= 0)
4787 if (gl_flashblend.integer)
4788 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4790 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4796 dlight_t *R_Shadow_NewWorldLight(void)
4798 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4801 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)
4804 // validate parameters
4805 if (style < 0 || style >= MAX_LIGHTSTYLES)
4807 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
4813 // copy to light properties
4814 VectorCopy(origin, light->origin);
4815 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4816 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4817 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4819 light->color[0] = max(color[0], 0);
4820 light->color[1] = max(color[1], 0);
4821 light->color[2] = max(color[2], 0);
4823 light->color[0] = color[0];
4824 light->color[1] = color[1];
4825 light->color[2] = color[2];
4826 light->radius = max(radius, 0);
4827 light->style = style;
4828 light->shadow = shadowenable;
4829 light->corona = corona;
4830 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4831 light->coronasizescale = coronasizescale;
4832 light->ambientscale = ambientscale;
4833 light->diffusescale = diffusescale;
4834 light->specularscale = specularscale;
4835 light->flags = flags;
4837 // update renderable light data
4838 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4839 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);
4842 void R_Shadow_FreeWorldLight(dlight_t *light)
4844 if (r_shadow_selectedlight == light)
4845 r_shadow_selectedlight = NULL;
4846 R_RTLight_Uncompile(&light->rtlight);
4847 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4850 void R_Shadow_ClearWorldLights(void)
4854 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4855 for (lightindex = 0;lightindex < range;lightindex++)
4857 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4859 R_Shadow_FreeWorldLight(light);
4861 r_shadow_selectedlight = NULL;
4864 void R_Shadow_SelectLight(dlight_t *light)
4866 if (r_shadow_selectedlight)
4867 r_shadow_selectedlight->selected = false;
4868 r_shadow_selectedlight = light;
4869 if (r_shadow_selectedlight)
4870 r_shadow_selectedlight->selected = true;
4873 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4875 // this is never batched (there can be only one)
4877 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
4878 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4879 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4882 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4887 skinframe_t *skinframe;
4890 // this is never batched (due to the ent parameter changing every time)
4891 // so numsurfaces == 1 and surfacelist[0] == lightnumber
4892 const dlight_t *light = (dlight_t *)ent;
4895 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
4898 VectorScale(light->color, intensity, spritecolor);
4899 if (VectorLength(spritecolor) < 0.1732f)
4900 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
4901 if (VectorLength(spritecolor) > 1.0f)
4902 VectorNormalize(spritecolor);
4904 // draw light sprite
4905 if (light->cubemapname[0] && !light->shadow)
4906 skinframe = r_editlights_sprcubemapnoshadowlight;
4907 else if (light->cubemapname[0])
4908 skinframe = r_editlights_sprcubemaplight;
4909 else if (!light->shadow)
4910 skinframe = r_editlights_sprnoshadowlight;
4912 skinframe = r_editlights_sprlight;
4914 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);
4915 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4917 // draw selection sprite if light is selected
4918 if (light->selected)
4920 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4921 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4922 // VorteX todo: add normalmode/realtime mode light overlay sprites?
4926 void R_Shadow_DrawLightSprites(void)
4930 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4931 for (lightindex = 0;lightindex < range;lightindex++)
4933 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4935 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
4937 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
4940 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
4945 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
4946 if (lightindex >= range)
4948 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4951 rtlight = &light->rtlight;
4952 //if (!(rtlight->flags & flag))
4954 VectorCopy(rtlight->shadoworigin, origin);
4955 *radius = rtlight->radius;
4956 VectorCopy(rtlight->color, color);
4960 void R_Shadow_SelectLightInView(void)
4962 float bestrating, rating, temp[3];
4966 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4969 for (lightindex = 0;lightindex < range;lightindex++)
4971 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4974 VectorSubtract(light->origin, r_refdef.view.origin, temp);
4975 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
4978 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
4979 if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1.0f)
4981 bestrating = rating;
4986 R_Shadow_SelectLight(best);
4989 void R_Shadow_LoadWorldLights(void)
4991 int n, a, style, shadow, flags;
4992 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
4993 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
4994 if (cl.worldmodel == NULL)
4996 Con_Print("No map loaded.\n");
4999 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
5000 strlcat (name, ".rtlights", sizeof (name));
5001 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5011 for (;COM_Parse(t, true) && strcmp(
5012 if (COM_Parse(t, true))
5014 if (com_token[0] == '!')
5017 origin[0] = atof(com_token+1);
5020 origin[0] = atof(com_token);
5025 while (*s && *s != '\n' && *s != '\r')
5031 // check for modifier flags
5038 #if _MSC_VER >= 1400
5039 #define sscanf sscanf_s
5041 cubemapname[sizeof(cubemapname)-1] = 0;
5042 #if MAX_QPATH != 128
5043 #error update this code if MAX_QPATH changes
5045 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
5046 #if _MSC_VER >= 1400
5047 , sizeof(cubemapname)
5049 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
5052 flags = LIGHTFLAG_REALTIMEMODE;
5060 coronasizescale = 0.25f;
5062 VectorClear(angles);
5065 if (a < 9 || !strcmp(cubemapname, "\"\""))
5067 // remove quotes on cubemapname
5068 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
5071 namelen = strlen(cubemapname) - 2;
5072 memmove(cubemapname, cubemapname + 1, namelen);
5073 cubemapname[namelen] = '\0';
5077 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);
5080 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5088 Con_Printf("invalid rtlights file \"%s\"\n", name);
5089 Mem_Free(lightsstring);
5093 void R_Shadow_SaveWorldLights(void)
5097 size_t bufchars, bufmaxchars;
5099 char name[MAX_QPATH];
5100 char line[MAX_INPUTLINE];
5101 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
5102 // I hate lines which are 3 times my screen size :( --blub
5105 if (cl.worldmodel == NULL)
5107 Con_Print("No map loaded.\n");
5110 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
5111 strlcat (name, ".rtlights", sizeof (name));
5112 bufchars = bufmaxchars = 0;
5114 for (lightindex = 0;lightindex < range;lightindex++)
5116 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5119 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
5120 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);
5121 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
5122 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]);
5124 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);
5125 if (bufchars + strlen(line) > bufmaxchars)
5127 bufmaxchars = bufchars + strlen(line) + 2048;
5129 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
5133 memcpy(buf, oldbuf, bufchars);
5139 memcpy(buf + bufchars, line, strlen(line));
5140 bufchars += strlen(line);
5144 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
5149 void R_Shadow_LoadLightsFile(void)
5152 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
5153 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
5154 if (cl.worldmodel == NULL)
5156 Con_Print("No map loaded.\n");
5159 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
5160 strlcat (name, ".lights", sizeof (name));
5161 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5169 while (*s && *s != '\n' && *s != '\r')
5175 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);
5179 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);
5182 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
5183 radius = bound(15, radius, 4096);
5184 VectorScale(color, (2.0f / (8388608.0f)), color);
5185 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5193 Con_Printf("invalid lights file \"%s\"\n", name);
5194 Mem_Free(lightsstring);
5198 // tyrlite/hmap2 light types in the delay field
5199 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
5201 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
5213 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
5214 char key[256], value[MAX_INPUTLINE];
5216 if (cl.worldmodel == NULL)
5218 Con_Print("No map loaded.\n");
5221 // try to load a .ent file first
5222 FS_StripExtension (cl.worldmodel->name, key, sizeof (key));
5223 strlcat (key, ".ent", sizeof (key));
5224 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
5225 // and if that is not found, fall back to the bsp file entity string
5227 data = cl.worldmodel->brush.entities;
5230 for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
5232 type = LIGHTTYPE_MINUSX;
5233 origin[0] = origin[1] = origin[2] = 0;
5234 originhack[0] = originhack[1] = originhack[2] = 0;
5235 angles[0] = angles[1] = angles[2] = 0;
5236 color[0] = color[1] = color[2] = 1;
5237 light[0] = light[1] = light[2] = 1;light[3] = 300;
5238 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
5248 if (!COM_ParseToken_Simple(&data, false, false))
5250 if (com_token[0] == '}')
5251 break; // end of entity
5252 if (com_token[0] == '_')
5253 strlcpy(key, com_token + 1, sizeof(key));
5255 strlcpy(key, com_token, sizeof(key));
5256 while (key[strlen(key)-1] == ' ') // remove trailing spaces
5257 key[strlen(key)-1] = 0;
5258 if (!COM_ParseToken_Simple(&data, false, false))
5260 strlcpy(value, com_token, sizeof(value));
5262 // now that we have the key pair worked out...
5263 if (!strcmp("light", key))
5265 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5269 light[0] = vec[0] * (1.0f / 256.0f);
5270 light[1] = vec[0] * (1.0f / 256.0f);
5271 light[2] = vec[0] * (1.0f / 256.0f);
5277 light[0] = vec[0] * (1.0f / 255.0f);
5278 light[1] = vec[1] * (1.0f / 255.0f);
5279 light[2] = vec[2] * (1.0f / 255.0f);
5283 else if (!strcmp("delay", key))
5285 else if (!strcmp("origin", key))
5286 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5287 else if (!strcmp("angle", key))
5288 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5289 else if (!strcmp("angles", key))
5290 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5291 else if (!strcmp("color", key))
5292 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5293 else if (!strcmp("wait", key))
5294 fadescale = atof(value);
5295 else if (!strcmp("classname", key))
5297 if (!strncmp(value, "light", 5))
5300 if (!strcmp(value, "light_fluoro"))
5305 overridecolor[0] = 1;
5306 overridecolor[1] = 1;
5307 overridecolor[2] = 1;
5309 if (!strcmp(value, "light_fluorospark"))
5314 overridecolor[0] = 1;
5315 overridecolor[1] = 1;
5316 overridecolor[2] = 1;
5318 if (!strcmp(value, "light_globe"))
5323 overridecolor[0] = 1;
5324 overridecolor[1] = 0.8;
5325 overridecolor[2] = 0.4;
5327 if (!strcmp(value, "light_flame_large_yellow"))
5332 overridecolor[0] = 1;
5333 overridecolor[1] = 0.5;
5334 overridecolor[2] = 0.1;
5336 if (!strcmp(value, "light_flame_small_yellow"))
5341 overridecolor[0] = 1;
5342 overridecolor[1] = 0.5;
5343 overridecolor[2] = 0.1;
5345 if (!strcmp(value, "light_torch_small_white"))
5350 overridecolor[0] = 1;
5351 overridecolor[1] = 0.5;
5352 overridecolor[2] = 0.1;
5354 if (!strcmp(value, "light_torch_small_walltorch"))
5359 overridecolor[0] = 1;
5360 overridecolor[1] = 0.5;
5361 overridecolor[2] = 0.1;
5365 else if (!strcmp("style", key))
5366 style = atoi(value);
5367 else if (!strcmp("skin", key))
5368 skin = (int)atof(value);
5369 else if (!strcmp("pflags", key))
5370 pflags = (int)atof(value);
5371 //else if (!strcmp("effects", key))
5372 // effects = (int)atof(value);
5373 else if (cl.worldmodel->type == mod_brushq3)
5375 if (!strcmp("scale", key))
5376 lightscale = atof(value);
5377 if (!strcmp("fade", key))
5378 fadescale = atof(value);
5383 if (lightscale <= 0)
5387 if (color[0] == color[1] && color[0] == color[2])
5389 color[0] *= overridecolor[0];
5390 color[1] *= overridecolor[1];
5391 color[2] *= overridecolor[2];
5393 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5394 color[0] = color[0] * light[0];
5395 color[1] = color[1] * light[1];
5396 color[2] = color[2] * light[2];
5399 case LIGHTTYPE_MINUSX:
5401 case LIGHTTYPE_RECIPX:
5403 VectorScale(color, (1.0f / 16.0f), color);
5405 case LIGHTTYPE_RECIPXX:
5407 VectorScale(color, (1.0f / 16.0f), color);
5410 case LIGHTTYPE_NONE:
5414 case LIGHTTYPE_MINUSXX:
5417 VectorAdd(origin, originhack, origin);
5419 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);
5422 Mem_Free(entfiledata);
5426 void R_Shadow_SetCursorLocationForView(void)
5429 vec3_t dest, endpos;
5431 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5432 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
5433 if (trace.fraction < 1)
5435 dist = trace.fraction * r_editlights_cursordistance.value;
5436 push = r_editlights_cursorpushback.value;
5440 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5441 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5445 VectorClear( endpos );
5447 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5448 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5449 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5452 void R_Shadow_UpdateWorldLightSelection(void)
5454 if (r_editlights.integer)
5456 R_Shadow_SetCursorLocationForView();
5457 R_Shadow_SelectLightInView();
5460 R_Shadow_SelectLight(NULL);
5463 void R_Shadow_EditLights_Clear_f(void)
5465 R_Shadow_ClearWorldLights();
5468 void R_Shadow_EditLights_Reload_f(void)
5472 strlcpy(r_shadow_mapname, cl.worldmodel->name, sizeof(r_shadow_mapname));
5473 R_Shadow_ClearWorldLights();
5474 R_Shadow_LoadWorldLights();
5475 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5477 R_Shadow_LoadLightsFile();
5478 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5479 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5483 void R_Shadow_EditLights_Save_f(void)
5487 R_Shadow_SaveWorldLights();
5490 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
5492 R_Shadow_ClearWorldLights();
5493 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5496 void R_Shadow_EditLights_ImportLightsFile_f(void)
5498 R_Shadow_ClearWorldLights();
5499 R_Shadow_LoadLightsFile();
5502 void R_Shadow_EditLights_Spawn_f(void)
5505 if (!r_editlights.integer)
5507 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5510 if (Cmd_Argc() != 1)
5512 Con_Print("r_editlights_spawn does not take parameters\n");
5515 color[0] = color[1] = color[2] = 1;
5516 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5519 void R_Shadow_EditLights_Edit_f(void)
5521 vec3_t origin, angles, color;
5522 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5523 int style, shadows, flags, normalmode, realtimemode;
5524 char cubemapname[MAX_INPUTLINE];
5525 if (!r_editlights.integer)
5527 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5530 if (!r_shadow_selectedlight)
5532 Con_Print("No selected light.\n");
5535 VectorCopy(r_shadow_selectedlight->origin, origin);
5536 VectorCopy(r_shadow_selectedlight->angles, angles);
5537 VectorCopy(r_shadow_selectedlight->color, color);
5538 radius = r_shadow_selectedlight->radius;
5539 style = r_shadow_selectedlight->style;
5540 if (r_shadow_selectedlight->cubemapname)
5541 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5544 shadows = r_shadow_selectedlight->shadow;
5545 corona = r_shadow_selectedlight->corona;
5546 coronasizescale = r_shadow_selectedlight->coronasizescale;
5547 ambientscale = r_shadow_selectedlight->ambientscale;
5548 diffusescale = r_shadow_selectedlight->diffusescale;
5549 specularscale = r_shadow_selectedlight->specularscale;
5550 flags = r_shadow_selectedlight->flags;
5551 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5552 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5553 if (!strcmp(Cmd_Argv(1), "origin"))
5555 if (Cmd_Argc() != 5)
5557 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5560 origin[0] = atof(Cmd_Argv(2));
5561 origin[1] = atof(Cmd_Argv(3));
5562 origin[2] = atof(Cmd_Argv(4));
5564 else if (!strcmp(Cmd_Argv(1), "originx"))
5566 if (Cmd_Argc() != 3)
5568 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5571 origin[0] = atof(Cmd_Argv(2));
5573 else if (!strcmp(Cmd_Argv(1), "originy"))
5575 if (Cmd_Argc() != 3)
5577 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5580 origin[1] = atof(Cmd_Argv(2));
5582 else if (!strcmp(Cmd_Argv(1), "originz"))
5584 if (Cmd_Argc() != 3)
5586 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5589 origin[2] = atof(Cmd_Argv(2));
5591 else if (!strcmp(Cmd_Argv(1), "move"))
5593 if (Cmd_Argc() != 5)
5595 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5598 origin[0] += atof(Cmd_Argv(2));
5599 origin[1] += atof(Cmd_Argv(3));
5600 origin[2] += atof(Cmd_Argv(4));
5602 else if (!strcmp(Cmd_Argv(1), "movex"))
5604 if (Cmd_Argc() != 3)
5606 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5609 origin[0] += atof(Cmd_Argv(2));
5611 else if (!strcmp(Cmd_Argv(1), "movey"))
5613 if (Cmd_Argc() != 3)
5615 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5618 origin[1] += atof(Cmd_Argv(2));
5620 else if (!strcmp(Cmd_Argv(1), "movez"))
5622 if (Cmd_Argc() != 3)
5624 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5627 origin[2] += atof(Cmd_Argv(2));
5629 else if (!strcmp(Cmd_Argv(1), "angles"))
5631 if (Cmd_Argc() != 5)
5633 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5636 angles[0] = atof(Cmd_Argv(2));
5637 angles[1] = atof(Cmd_Argv(3));
5638 angles[2] = atof(Cmd_Argv(4));
5640 else if (!strcmp(Cmd_Argv(1), "anglesx"))
5642 if (Cmd_Argc() != 3)
5644 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5647 angles[0] = atof(Cmd_Argv(2));
5649 else if (!strcmp(Cmd_Argv(1), "anglesy"))
5651 if (Cmd_Argc() != 3)
5653 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5656 angles[1] = atof(Cmd_Argv(2));
5658 else if (!strcmp(Cmd_Argv(1), "anglesz"))
5660 if (Cmd_Argc() != 3)
5662 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5665 angles[2] = atof(Cmd_Argv(2));
5667 else if (!strcmp(Cmd_Argv(1), "color"))
5669 if (Cmd_Argc() != 5)
5671 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
5674 color[0] = atof(Cmd_Argv(2));
5675 color[1] = atof(Cmd_Argv(3));
5676 color[2] = atof(Cmd_Argv(4));
5678 else if (!strcmp(Cmd_Argv(1), "radius"))
5680 if (Cmd_Argc() != 3)
5682 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5685 radius = atof(Cmd_Argv(2));
5687 else if (!strcmp(Cmd_Argv(1), "colorscale"))
5689 if (Cmd_Argc() == 3)
5691 double scale = atof(Cmd_Argv(2));
5698 if (Cmd_Argc() != 5)
5700 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
5703 color[0] *= atof(Cmd_Argv(2));
5704 color[1] *= atof(Cmd_Argv(3));
5705 color[2] *= atof(Cmd_Argv(4));
5708 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
5710 if (Cmd_Argc() != 3)
5712 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5715 radius *= atof(Cmd_Argv(2));
5717 else if (!strcmp(Cmd_Argv(1), "style"))
5719 if (Cmd_Argc() != 3)
5721 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5724 style = atoi(Cmd_Argv(2));
5726 else if (!strcmp(Cmd_Argv(1), "cubemap"))
5730 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5733 if (Cmd_Argc() == 3)
5734 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
5738 else if (!strcmp(Cmd_Argv(1), "shadows"))
5740 if (Cmd_Argc() != 3)
5742 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5745 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5747 else if (!strcmp(Cmd_Argv(1), "corona"))
5749 if (Cmd_Argc() != 3)
5751 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5754 corona = atof(Cmd_Argv(2));
5756 else if (!strcmp(Cmd_Argv(1), "coronasize"))
5758 if (Cmd_Argc() != 3)
5760 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5763 coronasizescale = atof(Cmd_Argv(2));
5765 else if (!strcmp(Cmd_Argv(1), "ambient"))
5767 if (Cmd_Argc() != 3)
5769 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5772 ambientscale = atof(Cmd_Argv(2));
5774 else if (!strcmp(Cmd_Argv(1), "diffuse"))
5776 if (Cmd_Argc() != 3)
5778 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5781 diffusescale = atof(Cmd_Argv(2));
5783 else if (!strcmp(Cmd_Argv(1), "specular"))
5785 if (Cmd_Argc() != 3)
5787 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5790 specularscale = atof(Cmd_Argv(2));
5792 else if (!strcmp(Cmd_Argv(1), "normalmode"))
5794 if (Cmd_Argc() != 3)
5796 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5799 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5801 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
5803 if (Cmd_Argc() != 3)
5805 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5808 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5812 Con_Print("usage: r_editlights_edit [property] [value]\n");
5813 Con_Print("Selected light's properties:\n");
5814 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5815 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5816 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5817 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
5818 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
5819 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
5820 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5821 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
5822 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
5823 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
5824 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
5825 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
5826 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5827 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5830 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5831 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5834 void R_Shadow_EditLights_EditAll_f(void)
5840 if (!r_editlights.integer)
5842 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5846 // EditLights doesn't seem to have a "remove" command or something so:
5847 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5848 for (lightindex = 0;lightindex < range;lightindex++)
5850 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5853 R_Shadow_SelectLight(light);
5854 R_Shadow_EditLights_Edit_f();
5858 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
5860 int lightnumber, lightcount;
5861 size_t lightindex, range;
5865 if (!r_editlights.integer)
5867 x = vid_conwidth.value - 240;
5869 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
5872 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5873 for (lightindex = 0;lightindex < range;lightindex++)
5875 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5878 if (light == r_shadow_selectedlight)
5879 lightnumber = lightindex;
5882 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;
5883 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;
5885 if (r_shadow_selectedlight == NULL)
5887 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;
5888 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;
5889 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;
5890 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;
5891 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;
5892 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;
5893 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;
5894 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;
5895 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;
5896 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;
5897 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;
5898 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;
5899 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;
5900 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;
5901 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;
5904 void R_Shadow_EditLights_ToggleShadow_f(void)
5906 if (!r_editlights.integer)
5908 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5911 if (!r_shadow_selectedlight)
5913 Con_Print("No selected light.\n");
5916 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);
5919 void R_Shadow_EditLights_ToggleCorona_f(void)
5921 if (!r_editlights.integer)
5923 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5926 if (!r_shadow_selectedlight)
5928 Con_Print("No selected light.\n");
5931 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);
5934 void R_Shadow_EditLights_Remove_f(void)
5936 if (!r_editlights.integer)
5938 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
5941 if (!r_shadow_selectedlight)
5943 Con_Print("No selected light.\n");
5946 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
5947 r_shadow_selectedlight = NULL;
5950 void R_Shadow_EditLights_Help_f(void)
5953 "Documentation on r_editlights system:\n"
5955 "r_editlights : enable/disable editing mode\n"
5956 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
5957 "r_editlights_cursorpushback : push back cursor this far from surface\n"
5958 "r_editlights_cursorpushoff : push cursor off surface this far\n"
5959 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
5960 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
5962 "r_editlights_help : this help\n"
5963 "r_editlights_clear : remove all lights\n"
5964 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
5965 "r_editlights_save : save to .rtlights file\n"
5966 "r_editlights_spawn : create a light with default settings\n"
5967 "r_editlights_edit command : edit selected light - more documentation below\n"
5968 "r_editlights_remove : remove selected light\n"
5969 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
5970 "r_editlights_importlightentitiesfrommap : reload light entities\n"
5971 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
5973 "origin x y z : set light location\n"
5974 "originx x: set x component of light location\n"
5975 "originy y: set y component of light location\n"
5976 "originz z: set z component of light location\n"
5977 "move x y z : adjust light location\n"
5978 "movex x: adjust x component of light location\n"
5979 "movey y: adjust y component of light location\n"
5980 "movez z: adjust z component of light location\n"
5981 "angles x y z : set light angles\n"
5982 "anglesx x: set x component of light angles\n"
5983 "anglesy y: set y component of light angles\n"
5984 "anglesz z: set z component of light angles\n"
5985 "color r g b : set color of light (can be brighter than 1 1 1)\n"
5986 "radius radius : set radius (size) of light\n"
5987 "colorscale grey : multiply color of light (1 does nothing)\n"
5988 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
5989 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
5990 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
5991 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
5992 "cubemap basename : set filter cubemap of light (not yet supported)\n"
5993 "shadows 1/0 : turn on/off shadows\n"
5994 "corona n : set corona intensity\n"
5995 "coronasize n : set corona size (0-1)\n"
5996 "ambient n : set ambient intensity (0-1)\n"
5997 "diffuse n : set diffuse intensity (0-1)\n"
5998 "specular n : set specular intensity (0-1)\n"
5999 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
6000 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
6001 "<nothing> : print light properties to console\n"
6005 void R_Shadow_EditLights_CopyInfo_f(void)
6007 if (!r_editlights.integer)
6009 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
6012 if (!r_shadow_selectedlight)
6014 Con_Print("No selected light.\n");
6017 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
6018 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
6019 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
6020 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
6021 if (r_shadow_selectedlight->cubemapname)
6022 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
6024 r_shadow_bufferlight.cubemapname[0] = 0;
6025 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
6026 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
6027 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
6028 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
6029 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
6030 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
6031 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
6034 void R_Shadow_EditLights_PasteInfo_f(void)
6036 if (!r_editlights.integer)
6038 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
6041 if (!r_shadow_selectedlight)
6043 Con_Print("No selected light.\n");
6046 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);
6049 void R_Shadow_EditLights_Init(void)
6051 Cvar_RegisterVariable(&r_editlights);
6052 Cvar_RegisterVariable(&r_editlights_cursordistance);
6053 Cvar_RegisterVariable(&r_editlights_cursorpushback);
6054 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
6055 Cvar_RegisterVariable(&r_editlights_cursorgrid);
6056 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
6057 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
6058 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
6059 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)");
6060 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
6061 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
6062 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
6063 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)");
6064 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
6065 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
6066 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
6067 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
6068 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
6069 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
6070 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)");
6076 =============================================================================
6080 =============================================================================
6083 void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, int dynamic)
6085 VectorClear(diffusecolor);
6086 VectorClear(diffusenormal);
6088 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
6090 ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_refdef.scene.ambient;
6091 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
6094 VectorSet(ambientcolor, 1, 1, 1);
6101 for (i = 0;i < r_refdef.scene.numlights;i++)
6103 light = r_refdef.scene.lights[i];
6104 Matrix4x4_Transform(&light->matrix_worldtolight, p, v);
6105 f = 1 - VectorLength2(v);
6106 if (f > 0 && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
6107 VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);