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 int r_shadow_shadowmapside;
184 float r_shadow_shadowmap_texturescale[2];
185 float r_shadow_shadowmap_parameters[4];
187 int r_shadow_drawbuffer;
188 int r_shadow_readbuffer;
190 int r_shadow_cullface_front, r_shadow_cullface_back;
191 GLuint r_shadow_fborectangle;
192 GLuint r_shadow_fbocubeside[R_SHADOW_SHADOWMAP_NUMCUBEMAPS];
193 GLuint r_shadow_fbo2d;
194 r_shadow_shadowmode_t r_shadow_shadowmode;
195 int r_shadow_shadowmapfilterquality;
196 int r_shadow_shadowmaptexturetype;
197 int r_shadow_shadowmapdepthbits;
198 int r_shadow_shadowmapmaxsize;
199 qboolean r_shadow_shadowmapvsdct;
200 qboolean r_shadow_shadowmapsampler;
201 int r_shadow_shadowmappcf;
202 int r_shadow_shadowmapborder;
203 int r_shadow_lightscissor[4];
204 qboolean r_shadow_usingdeferredprepass;
206 int maxshadowtriangles;
209 int maxshadowvertices;
210 float *shadowvertex3f;
220 unsigned char *shadowsides;
221 int *shadowsideslist;
228 int r_shadow_buffer_numleafpvsbytes;
229 unsigned char *r_shadow_buffer_visitingleafpvs;
230 unsigned char *r_shadow_buffer_leafpvs;
231 int *r_shadow_buffer_leaflist;
233 int r_shadow_buffer_numsurfacepvsbytes;
234 unsigned char *r_shadow_buffer_surfacepvs;
235 int *r_shadow_buffer_surfacelist;
236 unsigned char *r_shadow_buffer_surfacesides;
238 int r_shadow_buffer_numshadowtrispvsbytes;
239 unsigned char *r_shadow_buffer_shadowtrispvs;
240 int r_shadow_buffer_numlighttrispvsbytes;
241 unsigned char *r_shadow_buffer_lighttrispvs;
243 rtexturepool_t *r_shadow_texturepool;
244 rtexture_t *r_shadow_attenuationgradienttexture;
245 rtexture_t *r_shadow_attenuation2dtexture;
246 rtexture_t *r_shadow_attenuation3dtexture;
247 skinframe_t *r_shadow_lightcorona;
248 rtexture_t *r_shadow_shadowmaprectangletexture;
249 rtexture_t *r_shadow_shadowmap2dtexture;
250 rtexture_t *r_shadow_shadowmapcubetexture[R_SHADOW_SHADOWMAP_NUMCUBEMAPS];
251 rtexture_t *r_shadow_shadowmapvsdcttexture;
252 int r_shadow_shadowmapsize; // changes for each light based on distance
253 int r_shadow_shadowmaplod; // changes for each light based on distance
255 GLuint r_shadow_prepassgeometryfbo;
256 GLuint r_shadow_prepasslightingfbo;
257 int r_shadow_prepass_width;
258 int r_shadow_prepass_height;
259 rtexture_t *r_shadow_prepassgeometrydepthtexture;
260 rtexture_t *r_shadow_prepassgeometrynormalmaptexture;
261 rtexture_t *r_shadow_prepasslightingdiffusetexture;
262 rtexture_t *r_shadow_prepasslightingspeculartexture;
264 // lights are reloaded when this changes
265 char r_shadow_mapname[MAX_QPATH];
267 // used only for light filters (cubemaps)
268 rtexturepool_t *r_shadow_filters_texturepool;
270 static const GLenum r_shadow_prepasslightingdrawbuffers[2] = {GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT};
272 cvar_t r_shadow_bumpscale_basetexture = {0, "r_shadow_bumpscale_basetexture", "0", "generate fake bumpmaps from diffuse textures at this bumpyness, try 4 to match tenebrae, higher values increase depth, requires r_restart to take effect"};
273 cvar_t r_shadow_bumpscale_bumpmap = {0, "r_shadow_bumpscale_bumpmap", "4", "what magnitude to interpret _bump.tga textures as, higher values increase depth, requires r_restart to take effect"};
274 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
275 cvar_t r_shadow_deferred = {CVAR_SAVE, "r_shadow_deferred", "0", "uses image-based lighting instead of geometry-based lighting, the method used renders a depth image and a normalmap image, renders lights into separate diffuse and specular images, and then combines this into the normal rendering, requires r_shadow_shadowmapping"};
276 cvar_t r_shadow_deferred_8bitrange = {CVAR_SAVE, "r_shadow_deferred_8bitrange", "2", "dynamic range of image-based lighting when using 32bit color (does not apply to fp)"};
277 //cvar_t r_shadow_deferred_fp = {CVAR_SAVE, "r_shadow_deferred_fp", "0", "use 16bit (1) or 32bit (2) floating point for accumulation of image-based lighting"};
278 cvar_t r_shadow_usenormalmap = {CVAR_SAVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"};
279 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)"};
280 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"};
281 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
282 cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
283 cvar_t r_shadow_gloss2exponent = {0, "r_shadow_gloss2exponent", "32", "same as r_shadow_glossexponent but for forced gloss (gloss 2) surfaces"};
284 cvar_t r_shadow_glossexact = {0, "r_shadow_glossexact", "0", "use exact reflection math for gloss (slightly slower, but should look a tad better)"};
285 cvar_t r_shadow_lightattenuationdividebias = {0, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"};
286 cvar_t r_shadow_lightattenuationlinearscale = {0, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"};
287 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
288 cvar_t r_shadow_lightradiusscale = {0, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
289 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "0", "how far to cast shadows"};
290 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)"};
291 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
292 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
293 cvar_t r_shadow_realtime_dlight_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
294 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
295 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)"};
296 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"};
297 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
298 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
299 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"};
300 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)"};
301 cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "0", "enables portal-based culling optimization during compilation (overrides compilesvbsp)"};
302 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)"};
303 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"};
304 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"};
305 cvar_t r_shadow_shadowmapping_filterquality = {CVAR_SAVE, "r_shadow_shadowmapping_filterquality", "-1", "shadowmap filter modes: -1 = auto-select, 0 = no filtering, 1 = bilinear, 2 = bilinear 2x2 blur (fast), 3 = 3x3 blur (moderate), 4 = 4x4 blur (slow)"};
306 cvar_t r_shadow_shadowmapping_depthbits = {CVAR_SAVE, "r_shadow_shadowmapping_depthbits", "24", "requested minimum shadowmap texture depth bits"};
307 cvar_t r_shadow_shadowmapping_vsdct = {CVAR_SAVE, "r_shadow_shadowmapping_vsdct", "1", "enables use of virtual shadow depth cube texture"};
308 cvar_t r_shadow_shadowmapping_minsize = {CVAR_SAVE, "r_shadow_shadowmapping_minsize", "32", "shadowmap size limit"};
309 cvar_t r_shadow_shadowmapping_maxsize = {CVAR_SAVE, "r_shadow_shadowmapping_maxsize", "512", "shadowmap size limit"};
310 cvar_t r_shadow_shadowmapping_precision = {CVAR_SAVE, "r_shadow_shadowmapping_precision", "1", "makes shadowmaps have a maximum resolution of this number of pixels per light source radius unit such that, for example, at precision 0.5 a light with radius 200 will have a maximum resolution of 100 pixels"};
311 //cvar_t r_shadow_shadowmapping_lod_bias = {CVAR_SAVE, "r_shadow_shadowmapping_lod_bias", "16", "shadowmap size bias"};
312 //cvar_t r_shadow_shadowmapping_lod_scale = {CVAR_SAVE, "r_shadow_shadowmapping_lod_scale", "128", "shadowmap size scaling parameter"};
313 cvar_t r_shadow_shadowmapping_bordersize = {CVAR_SAVE, "r_shadow_shadowmapping_bordersize", "4", "shadowmap size bias for filtering"};
314 cvar_t r_shadow_shadowmapping_nearclip = {CVAR_SAVE, "r_shadow_shadowmapping_nearclip", "1", "shadowmap nearclip in world units"};
315 cvar_t r_shadow_shadowmapping_bias = {CVAR_SAVE, "r_shadow_shadowmapping_bias", "0.03", "shadowmap bias parameter (this is multiplied by nearclip * 1024 / lodsize)"};
316 cvar_t r_shadow_shadowmapping_polygonfactor = {CVAR_SAVE, "r_shadow_shadowmapping_polygonfactor", "2", "slope-dependent shadowmapping bias"};
317 cvar_t r_shadow_shadowmapping_polygonoffset = {CVAR_SAVE, "r_shadow_shadowmapping_polygonoffset", "0", "constant shadowmapping bias"};
318 cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
319 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)"};
320 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)"};
321 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "1", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
322 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"};
323 cvar_t r_coronas_occlusionquery = {CVAR_SAVE, "r_coronas_occlusionquery", "1", "use GL_ARB_occlusion_query extension if supported (fades coronas according to visibility)"};
324 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
325 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
326 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
327 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
328 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
329 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
330 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
331 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
332 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
334 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
335 #define ATTENTABLESIZE 256
336 // 1D gradient, 2D circle and 3D sphere attenuation textures
337 #define ATTEN1DSIZE 32
338 #define ATTEN2DSIZE 64
339 #define ATTEN3DSIZE 32
341 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
342 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
343 static float r_shadow_attentable[ATTENTABLESIZE+1];
345 rtlight_t *r_shadow_compilingrtlight;
346 static memexpandablearray_t r_shadow_worldlightsarray;
347 dlight_t *r_shadow_selectedlight;
348 dlight_t r_shadow_bufferlight;
349 vec3_t r_editlights_cursorlocation;
351 extern int con_vislines;
353 typedef struct cubemapinfo_s
360 static int numcubemaps;
361 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
363 void R_Shadow_UncompileWorldLights(void);
364 void R_Shadow_ClearWorldLights(void);
365 void R_Shadow_SaveWorldLights(void);
366 void R_Shadow_LoadWorldLights(void);
367 void R_Shadow_LoadLightsFile(void);
368 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
369 void R_Shadow_EditLights_Reload_f(void);
370 void R_Shadow_ValidateCvars(void);
371 static void R_Shadow_MakeTextures(void);
373 #define EDLIGHTSPRSIZE 8
374 skinframe_t *r_editlights_sprcursor;
375 skinframe_t *r_editlights_sprlight;
376 skinframe_t *r_editlights_sprnoshadowlight;
377 skinframe_t *r_editlights_sprcubemaplight;
378 skinframe_t *r_editlights_sprcubemapnoshadowlight;
379 skinframe_t *r_editlights_sprselection;
381 void R_Shadow_SetShadowMode(void)
383 r_shadow_shadowmapmaxsize = bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4);
384 r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer != 0;
385 r_shadow_shadowmapfilterquality = r_shadow_shadowmapping_filterquality.integer;
386 r_shadow_shadowmaptexturetype = r_shadow_shadowmapping_texturetype.integer;
387 r_shadow_shadowmapdepthbits = r_shadow_shadowmapping_depthbits.integer;
388 r_shadow_shadowmapborder = bound(0, r_shadow_shadowmapping_bordersize.integer, 16);
389 r_shadow_shadowmaplod = -1;
390 r_shadow_shadowmapsize = 0;
391 r_shadow_shadowmapsampler = false;
392 r_shadow_shadowmappcf = 0;
393 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
394 switch(vid.renderpath)
396 case RENDERPATH_GL20:
397 case RENDERPATH_CGGL:
398 if ((r_shadow_shadowmapping.integer || r_shadow_deferred.integer) && vid.support.ext_framebuffer_object)
400 if(r_shadow_shadowmapfilterquality < 0)
402 if(strstr(gl_vendor, "NVIDIA"))
404 r_shadow_shadowmapsampler = vid.support.arb_shadow;
405 r_shadow_shadowmappcf = 1;
407 else if(vid.support.amd_texture_texture4 || vid.support.arb_texture_gather)
408 r_shadow_shadowmappcf = 1;
409 else if(strstr(gl_vendor, "ATI"))
410 r_shadow_shadowmappcf = 1;
412 r_shadow_shadowmapsampler = vid.support.arb_shadow;
416 switch (r_shadow_shadowmapfilterquality)
419 r_shadow_shadowmapsampler = vid.support.arb_shadow;
422 r_shadow_shadowmapsampler = vid.support.arb_shadow;
423 r_shadow_shadowmappcf = 1;
426 r_shadow_shadowmappcf = 1;
429 r_shadow_shadowmappcf = 2;
433 switch (r_shadow_shadowmaptexturetype)
436 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
439 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE;
442 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE;
445 if((vid.support.amd_texture_texture4 || vid.support.arb_texture_gather) && r_shadow_shadowmappcf && !r_shadow_shadowmapsampler)
446 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
447 else if(vid.support.arb_texture_rectangle)
448 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE;
450 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
455 case RENDERPATH_GL13:
457 case RENDERPATH_GL11:
462 void R_Shadow_FreeShadowMaps(void)
466 R_Shadow_SetShadowMode();
468 if (!vid.support.ext_framebuffer_object || !vid.support.arb_fragment_shader)
473 if (r_shadow_fborectangle)
474 qglDeleteFramebuffersEXT(1, &r_shadow_fborectangle);CHECKGLERROR
475 r_shadow_fborectangle = 0;
478 qglDeleteFramebuffersEXT(1, &r_shadow_fbo2d);CHECKGLERROR
480 for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
481 if (r_shadow_fbocubeside[i])
482 qglDeleteFramebuffersEXT(1, &r_shadow_fbocubeside[i]);CHECKGLERROR
483 memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
485 if (r_shadow_shadowmaprectangletexture)
486 R_FreeTexture(r_shadow_shadowmaprectangletexture);
487 r_shadow_shadowmaprectangletexture = NULL;
489 if (r_shadow_shadowmap2dtexture)
490 R_FreeTexture(r_shadow_shadowmap2dtexture);
491 r_shadow_shadowmap2dtexture = NULL;
493 for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
494 if (r_shadow_shadowmapcubetexture[i])
495 R_FreeTexture(r_shadow_shadowmapcubetexture[i]);
496 memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
498 if (r_shadow_shadowmapvsdcttexture)
499 R_FreeTexture(r_shadow_shadowmapvsdcttexture);
500 r_shadow_shadowmapvsdcttexture = NULL;
505 void r_shadow_start(void)
507 // allocate vertex processing arrays
509 r_shadow_attenuationgradienttexture = NULL;
510 r_shadow_attenuation2dtexture = NULL;
511 r_shadow_attenuation3dtexture = NULL;
512 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
513 r_shadow_shadowmaprectangletexture = NULL;
514 r_shadow_shadowmap2dtexture = NULL;
515 memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
516 r_shadow_shadowmapvsdcttexture = NULL;
517 r_shadow_shadowmapmaxsize = 0;
518 r_shadow_shadowmapsize = 0;
519 r_shadow_shadowmaplod = 0;
520 r_shadow_shadowmapfilterquality = -1;
521 r_shadow_shadowmaptexturetype = -1;
522 r_shadow_shadowmapdepthbits = 0;
523 r_shadow_shadowmapvsdct = false;
524 r_shadow_shadowmapsampler = false;
525 r_shadow_shadowmappcf = 0;
526 r_shadow_fborectangle = 0;
528 memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
530 R_Shadow_FreeShadowMaps();
532 r_shadow_texturepool = NULL;
533 r_shadow_filters_texturepool = NULL;
534 R_Shadow_ValidateCvars();
535 R_Shadow_MakeTextures();
536 maxshadowtriangles = 0;
537 shadowelements = NULL;
538 maxshadowvertices = 0;
539 shadowvertex3f = NULL;
547 shadowmarklist = NULL;
552 shadowsideslist = NULL;
553 r_shadow_buffer_numleafpvsbytes = 0;
554 r_shadow_buffer_visitingleafpvs = NULL;
555 r_shadow_buffer_leafpvs = NULL;
556 r_shadow_buffer_leaflist = NULL;
557 r_shadow_buffer_numsurfacepvsbytes = 0;
558 r_shadow_buffer_surfacepvs = NULL;
559 r_shadow_buffer_surfacelist = NULL;
560 r_shadow_buffer_surfacesides = NULL;
561 r_shadow_buffer_numshadowtrispvsbytes = 0;
562 r_shadow_buffer_shadowtrispvs = NULL;
563 r_shadow_buffer_numlighttrispvsbytes = 0;
564 r_shadow_buffer_lighttrispvs = NULL;
566 r_shadow_usingdeferredprepass = false;
567 r_shadow_prepass_width = r_shadow_prepass_height = 0;
570 static void R_Shadow_FreeDeferred(void);
571 void r_shadow_shutdown(void)
574 R_Shadow_UncompileWorldLights();
576 R_Shadow_FreeShadowMaps();
578 r_shadow_usingdeferredprepass = false;
579 if (r_shadow_prepass_width)
580 R_Shadow_FreeDeferred();
581 r_shadow_prepass_width = r_shadow_prepass_height = 0;
585 r_shadow_attenuationgradienttexture = NULL;
586 r_shadow_attenuation2dtexture = NULL;
587 r_shadow_attenuation3dtexture = NULL;
588 R_FreeTexturePool(&r_shadow_texturepool);
589 R_FreeTexturePool(&r_shadow_filters_texturepool);
590 maxshadowtriangles = 0;
592 Mem_Free(shadowelements);
593 shadowelements = NULL;
595 Mem_Free(shadowvertex3f);
596 shadowvertex3f = NULL;
599 Mem_Free(vertexupdate);
602 Mem_Free(vertexremap);
608 Mem_Free(shadowmark);
611 Mem_Free(shadowmarklist);
612 shadowmarklist = NULL;
617 Mem_Free(shadowsides);
620 Mem_Free(shadowsideslist);
621 shadowsideslist = NULL;
622 r_shadow_buffer_numleafpvsbytes = 0;
623 if (r_shadow_buffer_visitingleafpvs)
624 Mem_Free(r_shadow_buffer_visitingleafpvs);
625 r_shadow_buffer_visitingleafpvs = NULL;
626 if (r_shadow_buffer_leafpvs)
627 Mem_Free(r_shadow_buffer_leafpvs);
628 r_shadow_buffer_leafpvs = NULL;
629 if (r_shadow_buffer_leaflist)
630 Mem_Free(r_shadow_buffer_leaflist);
631 r_shadow_buffer_leaflist = NULL;
632 r_shadow_buffer_numsurfacepvsbytes = 0;
633 if (r_shadow_buffer_surfacepvs)
634 Mem_Free(r_shadow_buffer_surfacepvs);
635 r_shadow_buffer_surfacepvs = NULL;
636 if (r_shadow_buffer_surfacelist)
637 Mem_Free(r_shadow_buffer_surfacelist);
638 r_shadow_buffer_surfacelist = NULL;
639 if (r_shadow_buffer_surfacesides)
640 Mem_Free(r_shadow_buffer_surfacesides);
641 r_shadow_buffer_surfacesides = NULL;
642 r_shadow_buffer_numshadowtrispvsbytes = 0;
643 if (r_shadow_buffer_shadowtrispvs)
644 Mem_Free(r_shadow_buffer_shadowtrispvs);
645 r_shadow_buffer_numlighttrispvsbytes = 0;
646 if (r_shadow_buffer_lighttrispvs)
647 Mem_Free(r_shadow_buffer_lighttrispvs);
650 void r_shadow_newmap(void)
652 if (r_shadow_lightcorona) R_SkinFrame_MarkUsed(r_shadow_lightcorona);
653 if (r_editlights_sprcursor) R_SkinFrame_MarkUsed(r_editlights_sprcursor);
654 if (r_editlights_sprlight) R_SkinFrame_MarkUsed(r_editlights_sprlight);
655 if (r_editlights_sprnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprnoshadowlight);
656 if (r_editlights_sprcubemaplight) R_SkinFrame_MarkUsed(r_editlights_sprcubemaplight);
657 if (r_editlights_sprcubemapnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprcubemapnoshadowlight);
658 if (r_editlights_sprselection) R_SkinFrame_MarkUsed(r_editlights_sprselection);
659 if (cl.worldmodel && strncmp(cl.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
660 R_Shadow_EditLights_Reload_f();
663 void R_Shadow_Init(void)
665 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
666 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
667 Cvar_RegisterVariable(&r_shadow_usenormalmap);
668 Cvar_RegisterVariable(&r_shadow_debuglight);
669 Cvar_RegisterVariable(&r_shadow_deferred);
670 Cvar_RegisterVariable(&r_shadow_deferred_8bitrange);
671 // Cvar_RegisterVariable(&r_shadow_deferred_fp);
672 Cvar_RegisterVariable(&r_shadow_gloss);
673 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
674 Cvar_RegisterVariable(&r_shadow_glossintensity);
675 Cvar_RegisterVariable(&r_shadow_glossexponent);
676 Cvar_RegisterVariable(&r_shadow_gloss2exponent);
677 Cvar_RegisterVariable(&r_shadow_glossexact);
678 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
679 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
680 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
681 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
682 Cvar_RegisterVariable(&r_shadow_projectdistance);
683 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
684 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
685 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
686 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
687 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
688 Cvar_RegisterVariable(&r_shadow_realtime_world);
689 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
690 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
691 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
692 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
693 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
694 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
695 Cvar_RegisterVariable(&r_shadow_scissor);
696 Cvar_RegisterVariable(&r_shadow_shadowmapping);
697 Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
698 Cvar_RegisterVariable(&r_shadow_shadowmapping_texturetype);
699 Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
700 Cvar_RegisterVariable(&r_shadow_shadowmapping_depthbits);
701 Cvar_RegisterVariable(&r_shadow_shadowmapping_precision);
702 Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
703 Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
704 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
705 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
706 Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
707 Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
708 Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
709 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonfactor);
710 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonoffset);
711 Cvar_RegisterVariable(&r_shadow_polygonfactor);
712 Cvar_RegisterVariable(&r_shadow_polygonoffset);
713 Cvar_RegisterVariable(&r_shadow_texture3d);
714 Cvar_RegisterVariable(&r_coronas);
715 Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
716 Cvar_RegisterVariable(&r_coronas_occlusionquery);
717 Cvar_RegisterVariable(&gl_flashblend);
718 Cvar_RegisterVariable(&gl_ext_separatestencil);
719 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
720 if (gamemode == GAME_TENEBRAE)
722 Cvar_SetValue("r_shadow_gloss", 2);
723 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
725 R_Shadow_EditLights_Init();
726 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
727 maxshadowtriangles = 0;
728 shadowelements = NULL;
729 maxshadowvertices = 0;
730 shadowvertex3f = NULL;
738 shadowmarklist = NULL;
743 shadowsideslist = NULL;
744 r_shadow_buffer_numleafpvsbytes = 0;
745 r_shadow_buffer_visitingleafpvs = NULL;
746 r_shadow_buffer_leafpvs = NULL;
747 r_shadow_buffer_leaflist = NULL;
748 r_shadow_buffer_numsurfacepvsbytes = 0;
749 r_shadow_buffer_surfacepvs = NULL;
750 r_shadow_buffer_surfacelist = NULL;
751 r_shadow_buffer_surfacesides = NULL;
752 r_shadow_buffer_shadowtrispvs = NULL;
753 r_shadow_buffer_lighttrispvs = NULL;
754 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
757 matrix4x4_t matrix_attenuationxyz =
760 {0.5, 0.0, 0.0, 0.5},
761 {0.0, 0.5, 0.0, 0.5},
762 {0.0, 0.0, 0.5, 0.5},
767 matrix4x4_t matrix_attenuationz =
770 {0.0, 0.0, 0.5, 0.5},
771 {0.0, 0.0, 0.0, 0.5},
772 {0.0, 0.0, 0.0, 0.5},
777 void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles, int vertscale, int triscale)
779 numvertices = ((numvertices + 255) & ~255) * vertscale;
780 numtriangles = ((numtriangles + 255) & ~255) * triscale;
781 // make sure shadowelements is big enough for this volume
782 if (maxshadowtriangles < numtriangles)
784 maxshadowtriangles = numtriangles;
786 Mem_Free(shadowelements);
787 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[3]));
789 // make sure shadowvertex3f is big enough for this volume
790 if (maxshadowvertices < numvertices)
792 maxshadowvertices = numvertices;
794 Mem_Free(shadowvertex3f);
795 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[3]));
799 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
801 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
802 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
803 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
804 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
805 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
807 if (r_shadow_buffer_visitingleafpvs)
808 Mem_Free(r_shadow_buffer_visitingleafpvs);
809 if (r_shadow_buffer_leafpvs)
810 Mem_Free(r_shadow_buffer_leafpvs);
811 if (r_shadow_buffer_leaflist)
812 Mem_Free(r_shadow_buffer_leaflist);
813 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
814 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
815 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
816 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
818 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
820 if (r_shadow_buffer_surfacepvs)
821 Mem_Free(r_shadow_buffer_surfacepvs);
822 if (r_shadow_buffer_surfacelist)
823 Mem_Free(r_shadow_buffer_surfacelist);
824 if (r_shadow_buffer_surfacesides)
825 Mem_Free(r_shadow_buffer_surfacesides);
826 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
827 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
828 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
829 r_shadow_buffer_surfacesides = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
831 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
833 if (r_shadow_buffer_shadowtrispvs)
834 Mem_Free(r_shadow_buffer_shadowtrispvs);
835 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
836 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
838 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
840 if (r_shadow_buffer_lighttrispvs)
841 Mem_Free(r_shadow_buffer_lighttrispvs);
842 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
843 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
847 void R_Shadow_PrepareShadowMark(int numtris)
849 // make sure shadowmark is big enough for this volume
850 if (maxshadowmark < numtris)
852 maxshadowmark = numtris;
854 Mem_Free(shadowmark);
856 Mem_Free(shadowmarklist);
857 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
858 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
862 // if shadowmarkcount wrapped we clear the array and adjust accordingly
863 if (shadowmarkcount == 0)
866 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
871 void R_Shadow_PrepareShadowSides(int numtris)
873 if (maxshadowsides < numtris)
875 maxshadowsides = numtris;
877 Mem_Free(shadowsides);
879 Mem_Free(shadowsideslist);
880 shadowsides = (unsigned char *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsides));
881 shadowsideslist = (int *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsideslist));
886 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)
889 int outtriangles = 0, outvertices = 0;
892 float ratio, direction[3], projectvector[3];
894 if (projectdirection)
895 VectorScale(projectdirection, projectdistance, projectvector);
897 VectorClear(projectvector);
899 // create the vertices
900 if (projectdirection)
902 for (i = 0;i < numshadowmarktris;i++)
904 element = inelement3i + shadowmarktris[i] * 3;
905 for (j = 0;j < 3;j++)
907 if (vertexupdate[element[j]] != vertexupdatenum)
909 vertexupdate[element[j]] = vertexupdatenum;
910 vertexremap[element[j]] = outvertices;
911 vertex = invertex3f + element[j] * 3;
912 // project one copy of the vertex according to projectvector
913 VectorCopy(vertex, outvertex3f);
914 VectorAdd(vertex, projectvector, (outvertex3f + 3));
923 for (i = 0;i < numshadowmarktris;i++)
925 element = inelement3i + shadowmarktris[i] * 3;
926 for (j = 0;j < 3;j++)
928 if (vertexupdate[element[j]] != vertexupdatenum)
930 vertexupdate[element[j]] = vertexupdatenum;
931 vertexremap[element[j]] = outvertices;
932 vertex = invertex3f + element[j] * 3;
933 // project one copy of the vertex to the sphere radius of the light
934 // (FIXME: would projecting it to the light box be better?)
935 VectorSubtract(vertex, projectorigin, direction);
936 ratio = projectdistance / VectorLength(direction);
937 VectorCopy(vertex, outvertex3f);
938 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
946 if (r_shadow_frontsidecasting.integer)
948 for (i = 0;i < numshadowmarktris;i++)
950 int remappedelement[3];
952 const int *neighbortriangle;
954 markindex = shadowmarktris[i] * 3;
955 element = inelement3i + markindex;
956 neighbortriangle = inneighbor3i + markindex;
957 // output the front and back triangles
958 outelement3i[0] = vertexremap[element[0]];
959 outelement3i[1] = vertexremap[element[1]];
960 outelement3i[2] = vertexremap[element[2]];
961 outelement3i[3] = vertexremap[element[2]] + 1;
962 outelement3i[4] = vertexremap[element[1]] + 1;
963 outelement3i[5] = vertexremap[element[0]] + 1;
967 // output the sides (facing outward from this triangle)
968 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
970 remappedelement[0] = vertexremap[element[0]];
971 remappedelement[1] = vertexremap[element[1]];
972 outelement3i[0] = remappedelement[1];
973 outelement3i[1] = remappedelement[0];
974 outelement3i[2] = remappedelement[0] + 1;
975 outelement3i[3] = remappedelement[1];
976 outelement3i[4] = remappedelement[0] + 1;
977 outelement3i[5] = remappedelement[1] + 1;
982 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
984 remappedelement[1] = vertexremap[element[1]];
985 remappedelement[2] = vertexremap[element[2]];
986 outelement3i[0] = remappedelement[2];
987 outelement3i[1] = remappedelement[1];
988 outelement3i[2] = remappedelement[1] + 1;
989 outelement3i[3] = remappedelement[2];
990 outelement3i[4] = remappedelement[1] + 1;
991 outelement3i[5] = remappedelement[2] + 1;
996 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
998 remappedelement[0] = vertexremap[element[0]];
999 remappedelement[2] = vertexremap[element[2]];
1000 outelement3i[0] = remappedelement[0];
1001 outelement3i[1] = remappedelement[2];
1002 outelement3i[2] = remappedelement[2] + 1;
1003 outelement3i[3] = remappedelement[0];
1004 outelement3i[4] = remappedelement[2] + 1;
1005 outelement3i[5] = remappedelement[0] + 1;
1014 for (i = 0;i < numshadowmarktris;i++)
1016 int remappedelement[3];
1018 const int *neighbortriangle;
1020 markindex = shadowmarktris[i] * 3;
1021 element = inelement3i + markindex;
1022 neighbortriangle = inneighbor3i + markindex;
1023 // output the front and back triangles
1024 outelement3i[0] = vertexremap[element[2]];
1025 outelement3i[1] = vertexremap[element[1]];
1026 outelement3i[2] = vertexremap[element[0]];
1027 outelement3i[3] = vertexremap[element[0]] + 1;
1028 outelement3i[4] = vertexremap[element[1]] + 1;
1029 outelement3i[5] = vertexremap[element[2]] + 1;
1033 // output the sides (facing outward from this triangle)
1034 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
1036 remappedelement[0] = vertexremap[element[0]];
1037 remappedelement[1] = vertexremap[element[1]];
1038 outelement3i[0] = remappedelement[0];
1039 outelement3i[1] = remappedelement[1];
1040 outelement3i[2] = remappedelement[1] + 1;
1041 outelement3i[3] = remappedelement[0];
1042 outelement3i[4] = remappedelement[1] + 1;
1043 outelement3i[5] = remappedelement[0] + 1;
1048 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1050 remappedelement[1] = vertexremap[element[1]];
1051 remappedelement[2] = vertexremap[element[2]];
1052 outelement3i[0] = remappedelement[1];
1053 outelement3i[1] = remappedelement[2];
1054 outelement3i[2] = remappedelement[2] + 1;
1055 outelement3i[3] = remappedelement[1];
1056 outelement3i[4] = remappedelement[2] + 1;
1057 outelement3i[5] = remappedelement[1] + 1;
1062 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1064 remappedelement[0] = vertexremap[element[0]];
1065 remappedelement[2] = vertexremap[element[2]];
1066 outelement3i[0] = remappedelement[2];
1067 outelement3i[1] = remappedelement[0];
1068 outelement3i[2] = remappedelement[0] + 1;
1069 outelement3i[3] = remappedelement[2];
1070 outelement3i[4] = remappedelement[0] + 1;
1071 outelement3i[5] = remappedelement[2] + 1;
1079 *outnumvertices = outvertices;
1080 return outtriangles;
1083 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)
1086 int outtriangles = 0, outvertices = 0;
1088 const float *vertex;
1089 float ratio, direction[3], projectvector[3];
1092 if (projectdirection)
1093 VectorScale(projectdirection, projectdistance, projectvector);
1095 VectorClear(projectvector);
1097 for (i = 0;i < numshadowmarktris;i++)
1099 int remappedelement[3];
1101 const int *neighbortriangle;
1103 markindex = shadowmarktris[i] * 3;
1104 neighbortriangle = inneighbor3i + markindex;
1105 side[0] = shadowmark[neighbortriangle[0]] == shadowmarkcount;
1106 side[1] = shadowmark[neighbortriangle[1]] == shadowmarkcount;
1107 side[2] = shadowmark[neighbortriangle[2]] == shadowmarkcount;
1108 if (side[0] + side[1] + side[2] == 0)
1112 element = inelement3i + markindex;
1114 // create the vertices
1115 for (j = 0;j < 3;j++)
1117 if (side[j] + side[j+1] == 0)
1120 if (vertexupdate[k] != vertexupdatenum)
1122 vertexupdate[k] = vertexupdatenum;
1123 vertexremap[k] = outvertices;
1124 vertex = invertex3f + k * 3;
1125 VectorCopy(vertex, outvertex3f);
1126 if (projectdirection)
1128 // project one copy of the vertex according to projectvector
1129 VectorAdd(vertex, projectvector, (outvertex3f + 3));
1133 // project one copy of the vertex to the sphere radius of the light
1134 // (FIXME: would projecting it to the light box be better?)
1135 VectorSubtract(vertex, projectorigin, direction);
1136 ratio = projectdistance / VectorLength(direction);
1137 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1144 // output the sides (facing outward from this triangle)
1147 remappedelement[0] = vertexremap[element[0]];
1148 remappedelement[1] = vertexremap[element[1]];
1149 outelement3i[0] = remappedelement[1];
1150 outelement3i[1] = remappedelement[0];
1151 outelement3i[2] = remappedelement[0] + 1;
1152 outelement3i[3] = remappedelement[1];
1153 outelement3i[4] = remappedelement[0] + 1;
1154 outelement3i[5] = remappedelement[1] + 1;
1161 remappedelement[1] = vertexremap[element[1]];
1162 remappedelement[2] = vertexremap[element[2]];
1163 outelement3i[0] = remappedelement[2];
1164 outelement3i[1] = remappedelement[1];
1165 outelement3i[2] = remappedelement[1] + 1;
1166 outelement3i[3] = remappedelement[2];
1167 outelement3i[4] = remappedelement[1] + 1;
1168 outelement3i[5] = remappedelement[2] + 1;
1175 remappedelement[0] = vertexremap[element[0]];
1176 remappedelement[2] = vertexremap[element[2]];
1177 outelement3i[0] = remappedelement[0];
1178 outelement3i[1] = remappedelement[2];
1179 outelement3i[2] = remappedelement[2] + 1;
1180 outelement3i[3] = remappedelement[0];
1181 outelement3i[4] = remappedelement[2] + 1;
1182 outelement3i[5] = remappedelement[0] + 1;
1189 *outnumvertices = outvertices;
1190 return outtriangles;
1193 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)
1199 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1201 tend = firsttriangle + numtris;
1202 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1204 // surface box entirely inside light box, no box cull
1205 if (projectdirection)
1207 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1209 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
1210 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1211 shadowmarklist[numshadowmark++] = t;
1216 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1217 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
1218 shadowmarklist[numshadowmark++] = t;
1223 // surface box not entirely inside light box, cull each triangle
1224 if (projectdirection)
1226 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1228 v[0] = invertex3f + e[0] * 3;
1229 v[1] = invertex3f + e[1] * 3;
1230 v[2] = invertex3f + e[2] * 3;
1231 TriangleNormal(v[0], v[1], v[2], normal);
1232 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1233 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1234 shadowmarklist[numshadowmark++] = t;
1239 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1241 v[0] = invertex3f + e[0] * 3;
1242 v[1] = invertex3f + e[1] * 3;
1243 v[2] = invertex3f + e[2] * 3;
1244 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1245 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1246 shadowmarklist[numshadowmark++] = t;
1252 qboolean R_Shadow_UseZPass(vec3_t mins, vec3_t maxs)
1257 if (r_shadow_compilingrtlight || !r_shadow_frontsidecasting.integer || !r_shadow_usezpassifpossible.integer)
1259 // check if the shadow volume intersects the near plane
1261 // a ray between the eye and light origin may intersect the caster,
1262 // indicating that the shadow may touch the eye location, however we must
1263 // test the near plane (a polygon), not merely the eye location, so it is
1264 // easiest to enlarge the caster bounding shape slightly for this.
1270 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)
1272 int i, tris, outverts;
1273 if (projectdistance < 0.1)
1275 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
1278 if (!numverts || !nummarktris)
1280 // make sure shadowelements is big enough for this volume
1281 if (maxshadowtriangles < nummarktris*8 || maxshadowvertices < numverts*2)
1282 R_Shadow_ResizeShadowArrays(numverts, nummarktris, 2, 8);
1284 if (maxvertexupdate < numverts)
1286 maxvertexupdate = numverts;
1288 Mem_Free(vertexupdate);
1290 Mem_Free(vertexremap);
1291 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1292 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1293 vertexupdatenum = 0;
1296 if (vertexupdatenum == 0)
1298 vertexupdatenum = 1;
1299 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
1300 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
1303 for (i = 0;i < nummarktris;i++)
1304 shadowmark[marktris[i]] = shadowmarkcount;
1306 if (r_shadow_compilingrtlight)
1308 // if we're compiling an rtlight, capture the mesh
1309 //tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1310 //Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zpass, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1311 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1312 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zfail, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1314 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
1316 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1317 R_Mesh_VertexPointer(shadowvertex3f, 0, 0);
1318 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1322 // decide which type of shadow to generate and set stencil mode
1323 R_Shadow_RenderMode_StencilShadowVolumes(R_Shadow_UseZPass(trismins, trismaxs));
1324 // generate the sides or a solid volume, depending on type
1325 if (r_shadow_rendermode >= R_SHADOW_RENDERMODE_ZPASS_STENCIL && r_shadow_rendermode <= R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE)
1326 tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1328 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1329 r_refdef.stats.lights_dynamicshadowtriangles += tris;
1330 r_refdef.stats.lights_shadowtriangles += tris;
1332 R_Mesh_VertexPointer(shadowvertex3f, 0, 0);
1333 GL_LockArrays(0, outverts);
1334 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
1336 // increment stencil if frontface is infront of depthbuffer
1337 GL_CullFace(r_refdef.view.cullface_front);
1338 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1339 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1340 // decrement stencil if backface is infront of depthbuffer
1341 GL_CullFace(r_refdef.view.cullface_back);
1342 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1344 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
1346 // decrement stencil if backface is behind depthbuffer
1347 GL_CullFace(r_refdef.view.cullface_front);
1348 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1349 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1350 // increment stencil if frontface is behind depthbuffer
1351 GL_CullFace(r_refdef.view.cullface_back);
1352 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1354 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1355 GL_LockArrays(0, 0);
1360 int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias)
1362 // p1, p2, p3 are in the cubemap's local coordinate system
1363 // bias = border/(size - border)
1366 float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1367 dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2),
1368 dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3);
1369 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1371 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1372 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1373 | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1374 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1376 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1377 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1378 | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1380 dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1381 dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2),
1382 dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3);
1383 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1385 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1386 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1387 | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1388 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1390 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1391 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1392 | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1394 dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1395 dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2),
1396 dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3);
1397 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1399 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1400 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1401 | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1402 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1404 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1405 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1406 | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1411 int R_Shadow_CalcBBoxSideMask(const vec3_t mins, const vec3_t maxs, const matrix4x4_t *worldtolight, const matrix4x4_t *radiustolight, float bias)
1413 vec3_t center, radius, lightcenter, lightradius, pmin, pmax;
1414 float dp1, dn1, ap1, an1, dp2, dn2, ap2, an2;
1417 VectorSubtract(maxs, mins, radius);
1418 VectorScale(radius, 0.5f, radius);
1419 VectorAdd(mins, radius, center);
1420 Matrix4x4_Transform(worldtolight, center, lightcenter);
1421 Matrix4x4_Transform3x3(radiustolight, radius, lightradius);
1422 VectorSubtract(lightcenter, lightradius, pmin);
1423 VectorAdd(lightcenter, lightradius, pmax);
1425 dp1 = pmax[0] + pmax[1], dn1 = pmax[0] - pmin[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1426 dp2 = pmin[0] + pmin[1], dn2 = pmin[0] - pmax[1], ap2 = fabs(dp2), an2 = fabs(dn2);
1427 if(ap1 > bias*an1 && ap2 > bias*an2)
1429 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1430 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1431 if(an1 > bias*ap1 && an2 > bias*ap2)
1433 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1434 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1436 dp1 = pmax[1] + pmax[2], dn1 = pmax[1] - pmin[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1437 dp2 = pmin[1] + pmin[2], dn2 = pmin[1] - pmax[2], ap2 = fabs(dp2), an2 = fabs(dn2);
1438 if(ap1 > bias*an1 && ap2 > bias*an2)
1440 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1441 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1442 if(an1 > bias*ap1 && an2 > bias*ap2)
1444 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1445 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1447 dp1 = pmax[2] + pmax[0], dn1 = pmax[2] - pmin[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1448 dp2 = pmin[2] + pmin[0], dn2 = pmin[2] - pmax[0], ap2 = fabs(dp2), an2 = fabs(dn2);
1449 if(ap1 > bias*an1 && ap2 > bias*an2)
1451 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1452 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1453 if(an1 > bias*ap1 && an2 > bias*ap2)
1455 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1456 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1461 #define R_Shadow_CalcEntitySideMask(ent, worldtolight, radiustolight, bias) R_Shadow_CalcBBoxSideMask((ent)->mins, (ent)->maxs, worldtolight, radiustolight, bias)
1463 int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
1465 // p is in the cubemap's local coordinate system
1466 // bias = border/(size - border)
1467 float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn);
1468 float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn);
1469 float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn);
1471 if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
1472 if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
1473 if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
1474 if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
1475 if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
1476 if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
1480 int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
1484 int sides = 0x3F, masks[6] = { 3<<4, 3<<4, 3<<0, 3<<0, 3<<2, 3<<2 };
1485 float scale = (size - 2*border)/size, len;
1486 float bias = border / (float)(size - border), dp, dn, ap, an;
1487 // check if cone enclosing side would cross frustum plane
1488 scale = 2 / (scale*scale + 2);
1489 for (i = 0;i < 5;i++)
1491 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) > -0.03125)
1493 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[i].normal, n);
1494 len = scale*VectorLength2(n);
1495 if(n[0]*n[0] > len) sides &= n[0] < 0 ? ~(1<<0) : ~(2 << 0);
1496 if(n[1]*n[1] > len) sides &= n[1] < 0 ? ~(1<<2) : ~(2 << 2);
1497 if(n[2]*n[2] > len) sides &= n[2] < 0 ? ~(1<<4) : ~(2 << 4);
1499 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[4]) >= r_refdef.farclip - r_refdef.nearclip + 0.03125)
1501 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[4].normal, n);
1502 len = scale*VectorLength(n);
1503 if(n[0]*n[0] > len) sides &= n[0] >= 0 ? ~(1<<0) : ~(2 << 0);
1504 if(n[1]*n[1] > len) sides &= n[1] >= 0 ? ~(1<<2) : ~(2 << 2);
1505 if(n[2]*n[2] > len) sides &= n[2] >= 0 ? ~(1<<4) : ~(2 << 4);
1507 // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results
1508 // check if frustum corners/origin cross plane sides
1509 for (i = 0;i < 5;i++)
1511 Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p);
1512 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn),
1513 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1514 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1515 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn),
1516 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1517 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1518 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn),
1519 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1520 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1522 return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5];
1525 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)
1533 int mask, surfacemask = 0;
1534 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1536 bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
1537 tend = firsttriangle + numtris;
1538 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1540 // surface box entirely inside light box, no box cull
1541 if (projectdirection)
1543 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1545 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1546 TriangleNormal(v[0], v[1], v[2], normal);
1547 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1549 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1550 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1551 surfacemask |= mask;
1554 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;
1555 shadowsides[numshadowsides] = mask;
1556 shadowsideslist[numshadowsides++] = t;
1563 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1565 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1566 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]))
1568 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1569 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1570 surfacemask |= mask;
1573 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;
1574 shadowsides[numshadowsides] = mask;
1575 shadowsideslist[numshadowsides++] = t;
1583 // surface box not entirely inside light box, cull each triangle
1584 if (projectdirection)
1586 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1588 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1589 TriangleNormal(v[0], v[1], v[2], normal);
1590 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1591 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1593 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1594 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1595 surfacemask |= mask;
1598 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;
1599 shadowsides[numshadowsides] = mask;
1600 shadowsideslist[numshadowsides++] = t;
1607 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1609 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1610 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1611 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1613 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1614 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1615 surfacemask |= mask;
1618 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;
1619 shadowsides[numshadowsides] = mask;
1620 shadowsideslist[numshadowsides++] = t;
1629 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)
1631 int i, j, outtriangles = 0;
1632 int *outelement3i[6];
1633 if (!numverts || !numsidetris || !r_shadow_compilingrtlight)
1635 outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5];
1636 // make sure shadowelements is big enough for this mesh
1637 if (maxshadowtriangles < outtriangles)
1638 R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1);
1640 // compute the offset and size of the separate index lists for each cubemap side
1642 for (i = 0;i < 6;i++)
1644 outelement3i[i] = shadowelements + outtriangles * 3;
1645 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles;
1646 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i];
1647 outtriangles += sidetotals[i];
1650 // gather up the (sparse) triangles into separate index lists for each cubemap side
1651 for (i = 0;i < numsidetris;i++)
1653 const int *element = elements + sidetris[i] * 3;
1654 for (j = 0;j < 6;j++)
1656 if (sides[i] & (1 << j))
1658 outelement3i[j][0] = element[0];
1659 outelement3i[j][1] = element[1];
1660 outelement3i[j][2] = element[2];
1661 outelement3i[j] += 3;
1666 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, outtriangles, shadowelements);
1669 static void R_Shadow_MakeTextures_MakeCorona(void)
1673 unsigned char pixels[32][32][4];
1674 for (y = 0;y < 32;y++)
1676 dy = (y - 15.5f) * (1.0f / 16.0f);
1677 for (x = 0;x < 32;x++)
1679 dx = (x - 15.5f) * (1.0f / 16.0f);
1680 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1681 a = bound(0, a, 255);
1682 pixels[y][x][0] = a;
1683 pixels[y][x][1] = a;
1684 pixels[y][x][2] = a;
1685 pixels[y][x][3] = 255;
1688 r_shadow_lightcorona = R_SkinFrame_LoadInternalBGRA("lightcorona", TEXF_FORCELINEAR, &pixels[0][0][0], 32, 32);
1691 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1693 float dist = sqrt(x*x+y*y+z*z);
1694 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1695 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1696 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1699 static void R_Shadow_MakeTextures(void)
1702 float intensity, dist;
1704 R_Shadow_FreeShadowMaps();
1705 R_FreeTexturePool(&r_shadow_texturepool);
1706 r_shadow_texturepool = R_AllocTexturePool();
1707 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1708 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1709 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1710 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1711 for (x = 0;x <= ATTENTABLESIZE;x++)
1713 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1714 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1715 r_shadow_attentable[x] = bound(0, intensity, 1);
1717 // 1D gradient texture
1718 for (x = 0;x < ATTEN1DSIZE;x++)
1719 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1720 r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, NULL);
1721 // 2D circle texture
1722 for (y = 0;y < ATTEN2DSIZE;y++)
1723 for (x = 0;x < ATTEN2DSIZE;x++)
1724 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);
1725 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, NULL);
1726 // 3D sphere texture
1727 if (r_shadow_texture3d.integer && vid.support.ext_texture_3d)
1729 for (z = 0;z < ATTEN3DSIZE;z++)
1730 for (y = 0;y < ATTEN3DSIZE;y++)
1731 for (x = 0;x < ATTEN3DSIZE;x++)
1732 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));
1733 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, NULL);
1736 r_shadow_attenuation3dtexture = NULL;
1739 R_Shadow_MakeTextures_MakeCorona();
1741 // Editor light sprites
1742 r_editlights_sprcursor = R_SkinFrame_LoadInternal8bit("gfx/editlights/cursor", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1759 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1760 r_editlights_sprlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/light", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1777 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1778 r_editlights_sprnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/noshadow", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1795 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1796 r_editlights_sprcubemaplight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemaplight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1813 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1814 r_editlights_sprcubemapnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemapnoshadowlight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1831 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1832 r_editlights_sprselection = R_SkinFrame_LoadInternal8bit("gfx/editlights/selection", TEXF_ALPHA | TEXF_CLAMP, (unsigned char *)
1849 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1852 void R_Shadow_ValidateCvars(void)
1854 if (r_shadow_texture3d.integer && !vid.support.ext_texture_3d)
1855 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1856 if (gl_ext_separatestencil.integer && !vid.support.ati_separate_stencil)
1857 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
1858 if (gl_ext_stenciltwoside.integer && !vid.support.ext_stencil_two_side)
1859 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1862 void R_Shadow_RenderMode_Begin(void)
1868 R_Shadow_ValidateCvars();
1870 if (!r_shadow_attenuation2dtexture
1871 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1872 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1873 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1874 R_Shadow_MakeTextures();
1877 R_Mesh_ColorPointer(NULL, 0, 0);
1878 R_Mesh_ResetTextureState();
1879 GL_BlendFunc(GL_ONE, GL_ZERO);
1880 GL_DepthRange(0, 1);
1881 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1883 GL_DepthMask(false);
1884 GL_Color(0, 0, 0, 1);
1885 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1887 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1889 if (gl_ext_separatestencil.integer && vid.support.ati_separate_stencil)
1891 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
1892 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
1894 else if (gl_ext_stenciltwoside.integer && vid.support.ext_stencil_two_side)
1896 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
1897 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
1901 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
1902 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
1905 switch(vid.renderpath)
1907 case RENDERPATH_GL20:
1908 case RENDERPATH_CGGL:
1909 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1911 case RENDERPATH_GL13:
1912 case RENDERPATH_GL11:
1913 if (r_textureunits.integer >= 2 && vid.texunits >= 2 && r_shadow_texture3d.integer && r_shadow_attenuation3dtexture)
1914 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN;
1915 else if (r_textureunits.integer >= 3 && vid.texunits >= 3)
1916 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN;
1917 else if (r_textureunits.integer >= 2 && vid.texunits >= 2)
1918 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN;
1920 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1926 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
1927 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
1928 r_shadow_drawbuffer = drawbuffer;
1929 r_shadow_readbuffer = readbuffer;
1931 r_shadow_cullface_front = r_refdef.view.cullface_front;
1932 r_shadow_cullface_back = r_refdef.view.cullface_back;
1935 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
1937 rsurface.rtlight = rtlight;
1940 void R_Shadow_RenderMode_Reset(void)
1943 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE)
1945 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1947 if (vid.support.ext_framebuffer_object)
1949 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);CHECKGLERROR
1952 qglDrawBuffer(r_shadow_drawbuffer);CHECKGLERROR
1953 qglReadBuffer(r_shadow_readbuffer);CHECKGLERROR
1955 R_SetViewport(&r_refdef.view.viewport);
1956 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
1957 R_Mesh_ColorPointer(NULL, 0, 0);
1958 R_Mesh_ResetTextureState();
1959 GL_DepthRange(0, 1);
1961 GL_DepthMask(false);
1962 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1963 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1964 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
1965 qglStencilMask(255);CHECKGLERROR
1966 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
1967 qglStencilFunc(GL_ALWAYS, 128, 255);CHECKGLERROR
1968 r_refdef.view.cullface_front = r_shadow_cullface_front;
1969 r_refdef.view.cullface_back = r_shadow_cullface_back;
1970 GL_CullFace(r_refdef.view.cullface_back);
1971 GL_Color(1, 1, 1, 1);
1972 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
1973 GL_BlendFunc(GL_ONE, GL_ZERO);
1974 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
1975 r_shadow_usingshadowmaprect = false;
1976 r_shadow_usingshadowmapcube = false;
1977 r_shadow_usingshadowmap2d = false;
1981 void R_Shadow_ClearStencil(void)
1984 GL_Clear(GL_STENCIL_BUFFER_BIT);
1985 r_refdef.stats.lights_clears++;
1988 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
1990 r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
1991 if (r_shadow_rendermode == mode)
1994 R_Shadow_RenderMode_Reset();
1995 GL_ColorMask(0, 0, 0, 0);
1996 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1997 R_SetupShader_DepthOrShadow();
1998 qglDepthFunc(GL_LESS);CHECKGLERROR
1999 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2000 r_shadow_rendermode = mode;
2005 case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
2006 GL_CullFace(GL_NONE);
2007 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
2008 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
2010 case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
2011 GL_CullFace(GL_NONE);
2012 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
2013 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
2015 case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
2016 GL_CullFace(GL_NONE);
2017 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
2018 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
2019 qglStencilMask(255);CHECKGLERROR
2020 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
2021 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
2022 qglStencilMask(255);CHECKGLERROR
2023 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
2025 case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
2026 GL_CullFace(GL_NONE);
2027 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
2028 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
2029 qglStencilMask(255);CHECKGLERROR
2030 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
2031 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
2032 qglStencilMask(255);CHECKGLERROR
2033 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
2038 static void R_Shadow_MakeVSDCT(void)
2040 // maps to a 2x3 texture rectangle with normalized coordinates
2045 // stores abs(dir.xy), offset.xy/2.5
2046 unsigned char data[4*6] =
2048 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
2049 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
2050 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
2051 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
2052 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
2053 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
2055 r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, NULL);
2058 void R_Shadow_RenderMode_ShadowMap(int side, int clear, int size)
2062 float nearclip, farclip, bias;
2063 r_viewport_t viewport;
2066 maxsize = r_shadow_shadowmapmaxsize;
2067 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
2069 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
2070 r_shadow_shadowmap_parameters[2] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
2071 r_shadow_shadowmap_parameters[3] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
2072 r_shadow_shadowmapside = side;
2073 r_shadow_shadowmapsize = size;
2074 if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
2076 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2077 r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2078 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
2079 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D) goto init_done;
2081 // complex unrolled cube approach (more flexible)
2082 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2083 R_Shadow_MakeVSDCT();
2084 if (!r_shadow_shadowmap2dtexture)
2087 int w = maxsize*2, h = vid.support.arb_texture_non_power_of_two ? maxsize*3 : maxsize*4;
2088 r_shadow_shadowmap2dtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "shadowmap", w, h, r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
2089 qglGenFramebuffersEXT(1, &r_shadow_fbo2d);CHECKGLERROR
2090 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbo2d);CHECKGLERROR
2091 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_shadowmap2dtexture), 0);CHECKGLERROR
2092 // render depth into the fbo, do not render color at all
2093 qglDrawBuffer(GL_NONE);CHECKGLERROR
2094 qglReadBuffer(GL_NONE);CHECKGLERROR
2095 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2096 if (status != GL_FRAMEBUFFER_COMPLETE_EXT && (r_shadow_shadowmapping.integer || r_shadow_deferred.integer))
2098 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2099 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2100 Cvar_SetValueQuick(&r_shadow_deferred, 0);
2105 if (r_shadow_shadowmap2dtexture) fbo = r_shadow_fbo2d;
2106 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
2107 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
2108 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
2110 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE)
2112 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2113 r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2114 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
2115 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE) goto init_done;
2117 // complex unrolled cube approach (more flexible)
2118 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2119 R_Shadow_MakeVSDCT();
2120 if (!r_shadow_shadowmaprectangletexture)
2123 r_shadow_shadowmaprectangletexture = R_LoadTextureShadowMapRectangle(r_shadow_texturepool, "shadowmap", maxsize*2, maxsize*3, r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
2124 qglGenFramebuffersEXT(1, &r_shadow_fborectangle);CHECKGLERROR
2125 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fborectangle);CHECKGLERROR
2126 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, R_GetTexture(r_shadow_shadowmaprectangletexture), 0);CHECKGLERROR
2127 // render depth into the fbo, do not render color at all
2128 qglDrawBuffer(GL_NONE);CHECKGLERROR
2129 qglReadBuffer(GL_NONE);CHECKGLERROR
2130 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2131 if (status != GL_FRAMEBUFFER_COMPLETE_EXT && (r_shadow_shadowmapping.integer || r_shadow_deferred.integer))
2133 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2134 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2135 Cvar_SetValueQuick(&r_shadow_deferred, 0);
2140 if(r_shadow_shadowmaprectangletexture) fbo = r_shadow_fborectangle;
2141 r_shadow_shadowmap_texturescale[0] = 1.0f;
2142 r_shadow_shadowmap_texturescale[1] = 1.0f;
2143 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE;
2145 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
2147 r_shadow_shadowmap_parameters[0] = 1.0f;
2148 r_shadow_shadowmap_parameters[1] = 1.0f;
2149 R_Viewport_InitCubeSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, nearclip, farclip, NULL);
2150 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE) goto init_done;
2152 // simple cube approach
2153 if (!r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod])
2156 r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod] = R_LoadTextureShadowMapCube(r_shadow_texturepool, "shadowmapcube", size, r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
2157 qglGenFramebuffersEXT(1, &r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR
2158 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR
2159 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
2160 // render depth into the fbo, do not render color at all
2161 qglDrawBuffer(GL_NONE);CHECKGLERROR
2162 qglReadBuffer(GL_NONE);CHECKGLERROR
2163 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2164 if (status != GL_FRAMEBUFFER_COMPLETE_EXT && (r_shadow_shadowmapping.integer || r_shadow_deferred.integer))
2166 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2167 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2168 Cvar_SetValueQuick(&r_shadow_deferred, 0);
2173 if (r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]) fbo = r_shadow_fbocubeside[r_shadow_shadowmaplod];
2174 r_shadow_shadowmap_texturescale[0] = 0.0f;
2175 r_shadow_shadowmap_texturescale[1] = 0.0f;
2176 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE;
2179 R_Shadow_RenderMode_Reset();
2182 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);CHECKGLERROR
2183 R_SetupShader_DepthOrShadow();
2187 R_SetupShader_ShowDepth();
2188 qglClearColor(1,1,1,1);CHECKGLERROR
2191 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
2198 R_SetViewport(&viewport);
2199 if(r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE)
2201 int flipped = (side & 1) ^ (side >> 2);
2202 r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
2203 r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
2204 GL_CullFace(r_refdef.view.cullface_back);
2205 if ((clear & ((2 << side) - 1)) == (1 << side)) // only clear if the side is the first in the mask
2207 // get tightest scissor rectangle that encloses all viewports in the clear mask
2208 int x1 = clear & 0x15 ? 0 : size;
2209 int x2 = clear & 0x2A ? 2 * size : size;
2210 int y1 = clear & 0x03 ? 0 : (clear & 0xC ? size : 2 * size);
2211 int y2 = clear & 0x30 ? 3 * size : (clear & 0xC ? 2 * size : size);
2212 GL_Scissor(x1, y1, x2 - x1, y2 - y1);
2213 GL_Clear(GL_DEPTH_BUFFER_BIT);
2215 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2217 else if(r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE)
2219 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
2220 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2222 GL_Clear(GL_DEPTH_BUFFER_BIT);
2227 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
2231 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2232 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2233 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2234 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2237 R_Shadow_RenderMode_Reset();
2238 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2241 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2245 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2246 // only draw light where this geometry was already rendered AND the
2247 // stencil is 128 (values other than this mean shadow)
2248 qglStencilFunc(GL_EQUAL, 128, 255);CHECKGLERROR
2250 r_shadow_rendermode = r_shadow_lightingrendermode;
2251 // do global setup needed for the chosen lighting mode
2252 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2254 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2259 if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
2260 r_shadow_usingshadowmap2d = true;
2261 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE)
2262 r_shadow_usingshadowmaprect = true;
2263 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
2264 r_shadow_usingshadowmapcube = true;
2266 R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
2270 static const unsigned short bboxelements[36] =
2280 static const float bboxpoints[8][3] =
2292 void R_Shadow_RenderMode_DrawDeferredLight(qboolean stenciltest, qboolean shadowmapping)
2295 float vertex3f[8*3];
2296 const matrix4x4_t *matrix = &rsurface.rtlight->matrix_lighttoworld;
2298 R_Shadow_RenderMode_Reset();
2299 r_shadow_rendermode = r_shadow_lightingrendermode;
2300 // do global setup needed for the chosen lighting mode
2302 R_EntityMatrix(&identitymatrix);
2303 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2306 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2307 // only draw light where this geometry was already rendered AND the
2308 // stencil is 128 (values other than this mean shadow)
2309 qglStencilFunc(GL_EQUAL, 128, 255);CHECKGLERROR
2311 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepasslightingfbo);CHECKGLERROR
2314 if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
2315 r_shadow_usingshadowmap2d = true;
2316 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE)
2317 r_shadow_usingshadowmaprect = true;
2318 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
2319 r_shadow_usingshadowmapcube = true;
2322 // render the lighting
2323 R_SetupShader_DeferredLight(rsurface.rtlight);
2324 for (i = 0;i < 8;i++)
2325 Matrix4x4_Transform(matrix, bboxpoints[i], vertex3f + i*3);
2327 R_Mesh_VertexPointer(vertex3f, 0, 0);
2328 R_Mesh_ColorPointer(NULL, 0, 0);
2329 GL_ColorMask(1,1,1,1);
2330 GL_DepthMask(false);
2331 GL_DepthRange(0, 1);
2332 GL_PolygonOffset(0, 0);
2334 qglDepthFunc(GL_GREATER);CHECKGLERROR
2335 GL_CullFace(r_refdef.view.cullface_back);
2336 R_Mesh_Draw(0, 8, 0, 12, NULL, bboxelements, 0, 0);
2340 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
2343 R_Shadow_RenderMode_Reset();
2344 GL_BlendFunc(GL_ONE, GL_ONE);
2345 GL_DepthRange(0, 1);
2346 GL_DepthTest(r_showshadowvolumes.integer < 2);
2347 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
2348 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2349 GL_CullFace(GL_NONE);
2350 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
2353 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
2356 R_Shadow_RenderMode_Reset();
2357 GL_BlendFunc(GL_ONE, GL_ONE);
2358 GL_DepthRange(0, 1);
2359 GL_DepthTest(r_showlighting.integer < 2);
2360 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2363 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2367 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2368 qglStencilFunc(GL_EQUAL, 128, 255);CHECKGLERROR
2370 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2373 void R_Shadow_RenderMode_End(void)
2376 R_Shadow_RenderMode_Reset();
2377 R_Shadow_RenderMode_ActiveLight(NULL);
2379 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2380 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2383 int bboxedges[12][2] =
2402 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2404 int i, ix1, iy1, ix2, iy2;
2405 float x1, y1, x2, y2;
2407 float vertex[20][3];
2416 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2417 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2418 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2419 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2421 if (!r_shadow_scissor.integer)
2424 // if view is inside the light box, just say yes it's visible
2425 if (BoxesOverlap(r_refdef.view.origin, r_refdef.view.origin, mins, maxs))
2428 x1 = y1 = x2 = y2 = 0;
2430 // transform all corners that are infront of the nearclip plane
2431 VectorNegate(r_refdef.view.frustum[4].normal, plane4f);
2432 plane4f[3] = r_refdef.view.frustum[4].dist;
2434 for (i = 0;i < 8;i++)
2436 Vector4Set(corner[i], (i & 1) ? maxs[0] : mins[0], (i & 2) ? maxs[1] : mins[1], (i & 4) ? maxs[2] : mins[2], 1);
2437 dist[i] = DotProduct4(corner[i], plane4f);
2438 sign[i] = dist[i] > 0;
2441 VectorCopy(corner[i], vertex[numvertices]);
2445 // if some points are behind the nearclip, add clipped edge points to make
2446 // sure that the scissor boundary is complete
2447 if (numvertices > 0 && numvertices < 8)
2449 // add clipped edge points
2450 for (i = 0;i < 12;i++)
2452 j = bboxedges[i][0];
2453 k = bboxedges[i][1];
2454 if (sign[j] != sign[k])
2456 f = dist[j] / (dist[j] - dist[k]);
2457 VectorLerp(corner[j], f, corner[k], vertex[numvertices]);
2463 // if we have no points to check, the light is behind the view plane
2467 // if we have some points to transform, check what screen area is covered
2468 x1 = y1 = x2 = y2 = 0;
2470 //Con_Printf("%i vertices to transform...\n", numvertices);
2471 for (i = 0;i < numvertices;i++)
2473 VectorCopy(vertex[i], v);
2474 R_Viewport_TransformToScreen(&r_refdef.view.viewport, v, v2);
2475 //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]);
2478 if (x1 > v2[0]) x1 = v2[0];
2479 if (x2 < v2[0]) x2 = v2[0];
2480 if (y1 > v2[1]) y1 = v2[1];
2481 if (y2 < v2[1]) y2 = v2[1];
2490 // now convert the scissor rectangle to integer screen coordinates
2491 ix1 = (int)(x1 - 1.0f);
2492 iy1 = vid.height - (int)(y2 - 1.0f);
2493 ix2 = (int)(x2 + 1.0f);
2494 iy2 = vid.height - (int)(y1 + 1.0f);
2495 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
2497 // clamp it to the screen
2498 if (ix1 < r_refdef.view.viewport.x) ix1 = r_refdef.view.viewport.x;
2499 if (iy1 < r_refdef.view.viewport.y) iy1 = r_refdef.view.viewport.y;
2500 if (ix2 > r_refdef.view.viewport.x + r_refdef.view.viewport.width) ix2 = r_refdef.view.viewport.x + r_refdef.view.viewport.width;
2501 if (iy2 > r_refdef.view.viewport.y + r_refdef.view.viewport.height) iy2 = r_refdef.view.viewport.y + r_refdef.view.viewport.height;
2503 // if it is inside out, it's not visible
2504 if (ix2 <= ix1 || iy2 <= iy1)
2507 // the light area is visible, set up the scissor rectangle
2508 r_shadow_lightscissor[0] = ix1;
2509 r_shadow_lightscissor[1] = iy1;
2510 r_shadow_lightscissor[2] = ix2 - ix1;
2511 r_shadow_lightscissor[3] = iy2 - iy1;
2513 r_refdef.stats.lights_scissored++;
2517 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, int numtriangles, const int *element3i, const float *diffusecolor, const float *ambientcolor)
2519 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
2520 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
2521 float *color4f = rsurface.array_color4f + 4 * firstvertex;
2522 float dist, dot, distintensity, shadeintensity, v[3], n[3];
2523 switch (r_shadow_rendermode)
2525 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2526 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2527 if (VectorLength2(diffusecolor) > 0)
2529 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2531 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2532 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2533 if ((dot = DotProduct(n, v)) < 0)
2535 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2536 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
2539 VectorCopy(ambientcolor, color4f);
2540 if (r_refdef.fogenabled)
2543 f = RSurf_FogVertex(vertex3f);
2544 VectorScale(color4f, f, color4f);
2551 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2553 VectorCopy(ambientcolor, color4f);
2554 if (r_refdef.fogenabled)
2557 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2558 f = RSurf_FogVertex(vertex3f);
2559 VectorScale(color4f, f, color4f);
2565 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2566 if (VectorLength2(diffusecolor) > 0)
2568 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2570 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2571 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2573 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2574 if ((dot = DotProduct(n, v)) < 0)
2576 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2577 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2578 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2579 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2583 color4f[0] = ambientcolor[0] * distintensity;
2584 color4f[1] = ambientcolor[1] * distintensity;
2585 color4f[2] = ambientcolor[2] * distintensity;
2587 if (r_refdef.fogenabled)
2590 f = RSurf_FogVertex(vertex3f);
2591 VectorScale(color4f, f, color4f);
2595 VectorClear(color4f);
2601 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2603 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2604 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2606 color4f[0] = ambientcolor[0] * distintensity;
2607 color4f[1] = ambientcolor[1] * distintensity;
2608 color4f[2] = ambientcolor[2] * distintensity;
2609 if (r_refdef.fogenabled)
2612 f = RSurf_FogVertex(vertex3f);
2613 VectorScale(color4f, f, color4f);
2617 VectorClear(color4f);
2622 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2623 if (VectorLength2(diffusecolor) > 0)
2625 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2627 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2628 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2630 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2631 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2632 if ((dot = DotProduct(n, v)) < 0)
2634 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2635 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2636 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2637 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2641 color4f[0] = ambientcolor[0] * distintensity;
2642 color4f[1] = ambientcolor[1] * distintensity;
2643 color4f[2] = ambientcolor[2] * distintensity;
2645 if (r_refdef.fogenabled)
2648 f = RSurf_FogVertex(vertex3f);
2649 VectorScale(color4f, f, color4f);
2653 VectorClear(color4f);
2659 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2661 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2662 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2664 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2665 color4f[0] = ambientcolor[0] * distintensity;
2666 color4f[1] = ambientcolor[1] * distintensity;
2667 color4f[2] = ambientcolor[2] * distintensity;
2668 if (r_refdef.fogenabled)
2671 f = RSurf_FogVertex(vertex3f);
2672 VectorScale(color4f, f, color4f);
2676 VectorClear(color4f);
2686 static void R_Shadow_RenderLighting_VisibleLighting(int firstvertex, int numvertices, int firsttriangle, int numtriangles, const int *element3i, const unsigned short *element3s, int element3i_bufferobject, int element3s_bufferobject)
2688 // used to display how many times a surface is lit for level design purposes
2689 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2692 static void R_Shadow_RenderLighting_Light_GLSL(int firstvertex, int numvertices, int firsttriangle, int numtriangles, const int *element3i, const unsigned short *element3s, int element3i_bufferobject, int element3s_bufferobject, const vec3_t lightcolor, float ambientscale, float diffusescale, float specularscale)
2694 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2695 R_SetupShader_Surface(lightcolor, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT);
2696 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2698 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2700 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2701 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2703 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
2707 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
2714 int newnumtriangles;
2718 int maxtriangles = 4096;
2719 static int newelements[4096*3];
2720 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, numtriangles, element3i, diffusecolor2, ambientcolor2);
2721 for (renders = 0;renders < 4;renders++)
2726 newnumtriangles = 0;
2728 // due to low fillrate on the cards this vertex lighting path is
2729 // designed for, we manually cull all triangles that do not
2730 // contain a lit vertex
2731 // this builds batches of triangles from multiple surfaces and
2732 // renders them at once
2733 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
2735 if (VectorLength2(rsurface.array_color4f + e[0] * 4) + VectorLength2(rsurface.array_color4f + e[1] * 4) + VectorLength2(rsurface.array_color4f + e[2] * 4) >= 0.01)
2737 if (newnumtriangles)
2739 newfirstvertex = min(newfirstvertex, e[0]);
2740 newlastvertex = max(newlastvertex, e[0]);
2744 newfirstvertex = e[0];
2745 newlastvertex = e[0];
2747 newfirstvertex = min(newfirstvertex, e[1]);
2748 newlastvertex = max(newlastvertex, e[1]);
2749 newfirstvertex = min(newfirstvertex, e[2]);
2750 newlastvertex = max(newlastvertex, e[2]);
2756 if (newnumtriangles >= maxtriangles)
2758 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
2759 newnumtriangles = 0;
2765 if (newnumtriangles >= 1)
2767 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
2770 // if we couldn't find any lit triangles, exit early
2773 // now reduce the intensity for the next overbright pass
2774 // we have to clamp to 0 here incase the drivers have improper
2775 // handling of negative colors
2776 // (some old drivers even have improper handling of >1 color)
2778 for (i = 0, c = rsurface.array_color4f + 4 * firstvertex;i < numvertices;i++, c += 4)
2780 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
2782 c[0] = max(0, c[0] - 1);
2783 c[1] = max(0, c[1] - 1);
2784 c[2] = max(0, c[2] - 1);
2796 static void R_Shadow_RenderLighting_Light_Vertex(int firstvertex, int numvertices, int numtriangles, const int *element3i, const vec3_t lightcolor, float ambientscale, float diffusescale)
2798 // OpenGL 1.1 path (anything)
2799 float ambientcolorbase[3], diffusecolorbase[3];
2800 float ambientcolorpants[3], diffusecolorpants[3];
2801 float ambientcolorshirt[3], diffusecolorshirt[3];
2802 const float *surfacecolor = rsurface.texture->dlightcolor;
2803 const float *surfacepants = rsurface.colormap_pantscolor;
2804 const float *surfaceshirt = rsurface.colormap_shirtcolor;
2805 rtexture_t *basetexture = rsurface.texture->basetexture;
2806 rtexture_t *pantstexture = rsurface.texture->pantstexture;
2807 rtexture_t *shirttexture = rsurface.texture->shirttexture;
2808 qboolean dopants = pantstexture && VectorLength2(surfacepants) >= (1.0f / 1048576.0f);
2809 qboolean doshirt = shirttexture && VectorLength2(surfaceshirt) >= (1.0f / 1048576.0f);
2810 ambientscale *= 2 * r_refdef.view.colorscale;
2811 diffusescale *= 2 * r_refdef.view.colorscale;
2812 ambientcolorbase[0] = lightcolor[0] * ambientscale * surfacecolor[0];ambientcolorbase[1] = lightcolor[1] * ambientscale * surfacecolor[1];ambientcolorbase[2] = lightcolor[2] * ambientscale * surfacecolor[2];
2813 diffusecolorbase[0] = lightcolor[0] * diffusescale * surfacecolor[0];diffusecolorbase[1] = lightcolor[1] * diffusescale * surfacecolor[1];diffusecolorbase[2] = lightcolor[2] * diffusescale * surfacecolor[2];
2814 ambientcolorpants[0] = ambientcolorbase[0] * surfacepants[0];ambientcolorpants[1] = ambientcolorbase[1] * surfacepants[1];ambientcolorpants[2] = ambientcolorbase[2] * surfacepants[2];
2815 diffusecolorpants[0] = diffusecolorbase[0] * surfacepants[0];diffusecolorpants[1] = diffusecolorbase[1] * surfacepants[1];diffusecolorpants[2] = diffusecolorbase[2] * surfacepants[2];
2816 ambientcolorshirt[0] = ambientcolorbase[0] * surfaceshirt[0];ambientcolorshirt[1] = ambientcolorbase[1] * surfaceshirt[1];ambientcolorshirt[2] = ambientcolorbase[2] * surfaceshirt[2];
2817 diffusecolorshirt[0] = diffusecolorbase[0] * surfaceshirt[0];diffusecolorshirt[1] = diffusecolorbase[1] * surfaceshirt[1];diffusecolorshirt[2] = diffusecolorbase[2] * surfaceshirt[2];
2818 R_Mesh_TexBind(0, basetexture);
2819 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
2820 R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
2821 R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
2822 switch(r_shadow_rendermode)
2824 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2825 R_Mesh_TexBind(1, r_shadow_attenuation3dtexture);
2826 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
2827 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
2828 R_Mesh_TexCoordPointer(1, 3, rsurface.vertex3f, rsurface.vertex3f_bufferobject, rsurface.vertex3f_bufferoffset);
2830 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2831 R_Mesh_TexBind(2, r_shadow_attenuation2dtexture);
2832 R_Mesh_TexMatrix(2, &rsurface.entitytoattenuationz);
2833 R_Mesh_TexCombine(2, GL_MODULATE, GL_MODULATE, 1, 1);
2834 R_Mesh_TexCoordPointer(2, 3, rsurface.vertex3f, rsurface.vertex3f_bufferobject, rsurface.vertex3f_bufferoffset);
2836 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2837 R_Mesh_TexBind(1, r_shadow_attenuation2dtexture);
2838 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
2839 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
2840 R_Mesh_TexCoordPointer(1, 3, rsurface.vertex3f, rsurface.vertex3f_bufferobject, rsurface.vertex3f_bufferoffset);
2842 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2847 //R_Mesh_TexBind(0, basetexture);
2848 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorbase, ambientcolorbase);
2851 R_Mesh_TexBind(0, pantstexture);
2852 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorpants, ambientcolorpants);
2856 R_Mesh_TexBind(0, shirttexture);
2857 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorshirt, ambientcolorshirt);
2861 extern cvar_t gl_lightmaps;
2862 void R_Shadow_RenderLighting(int firstvertex, int numvertices, int firsttriangle, int numtriangles, const int *element3i, const unsigned short *element3s, int element3i_bufferobject, int element3s_bufferobject)
2864 float ambientscale, diffusescale, specularscale;
2866 float lightcolor[3];
2867 VectorCopy(rsurface.rtlight->currentcolor, lightcolor);
2868 ambientscale = rsurface.rtlight->ambientscale;
2869 diffusescale = rsurface.rtlight->diffusescale;
2870 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
2871 if (!r_shadow_usenormalmap.integer)
2873 ambientscale += 1.0f * diffusescale;
2877 if ((ambientscale + diffusescale) * VectorLength2(lightcolor) + specularscale * VectorLength2(lightcolor) < (1.0f / 1048576.0f))
2879 negated = (lightcolor[0] + lightcolor[1] + lightcolor[2] < 0) && vid.support.ext_blend_subtract;
2882 VectorNegate(lightcolor, lightcolor);
2883 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
2885 RSurf_SetupDepthAndCulling();
2886 switch (r_shadow_rendermode)
2888 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2889 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2890 R_Shadow_RenderLighting_VisibleLighting(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2892 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2893 R_Shadow_RenderLighting_Light_GLSL(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolor, ambientscale, diffusescale, specularscale);
2895 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2896 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2897 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2898 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2899 R_Shadow_RenderLighting_Light_Vertex(firstvertex, numvertices, numtriangles, element3i + firsttriangle * 3, lightcolor, ambientscale, diffusescale);
2902 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2906 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
2909 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)
2911 matrix4x4_t tempmatrix = *matrix;
2912 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
2914 // if this light has been compiled before, free the associated data
2915 R_RTLight_Uncompile(rtlight);
2917 // clear it completely to avoid any lingering data
2918 memset(rtlight, 0, sizeof(*rtlight));
2920 // copy the properties
2921 rtlight->matrix_lighttoworld = tempmatrix;
2922 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
2923 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
2924 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
2925 VectorCopy(color, rtlight->color);
2926 rtlight->cubemapname[0] = 0;
2927 if (cubemapname && cubemapname[0])
2928 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
2929 rtlight->shadow = shadow;
2930 rtlight->corona = corona;
2931 rtlight->style = style;
2932 rtlight->isstatic = isstatic;
2933 rtlight->coronasizescale = coronasizescale;
2934 rtlight->ambientscale = ambientscale;
2935 rtlight->diffusescale = diffusescale;
2936 rtlight->specularscale = specularscale;
2937 rtlight->flags = flags;
2939 // compute derived data
2940 //rtlight->cullradius = rtlight->radius;
2941 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2942 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2943 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2944 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2945 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2946 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2947 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2950 // compiles rtlight geometry
2951 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2952 void R_RTLight_Compile(rtlight_t *rtlight)
2955 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
2956 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
2957 entity_render_t *ent = r_refdef.scene.worldentity;
2958 dp_model_t *model = r_refdef.scene.worldmodel;
2959 unsigned char *data;
2962 // compile the light
2963 rtlight->compiled = true;
2964 rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
2965 rtlight->static_numleafs = 0;
2966 rtlight->static_numleafpvsbytes = 0;
2967 rtlight->static_leaflist = NULL;
2968 rtlight->static_leafpvs = NULL;
2969 rtlight->static_numsurfaces = 0;
2970 rtlight->static_surfacelist = NULL;
2971 rtlight->static_shadowmap_receivers = 0x3F;
2972 rtlight->static_shadowmap_casters = 0x3F;
2973 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2974 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2975 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2976 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2977 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2978 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2980 if (model && model->GetLightInfo)
2982 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
2983 r_shadow_compilingrtlight = rtlight;
2984 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);
2985 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2986 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
2987 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
2988 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
2989 rtlight->static_numsurfaces = numsurfaces;
2990 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
2991 rtlight->static_numleafs = numleafs;
2992 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
2993 rtlight->static_numleafpvsbytes = numleafpvsbytes;
2994 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
2995 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
2996 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
2997 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
2998 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
2999 if (rtlight->static_numsurfaces)
3000 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3001 if (rtlight->static_numleafs)
3002 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3003 if (rtlight->static_numleafpvsbytes)
3004 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3005 if (rtlight->static_numshadowtrispvsbytes)
3006 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3007 if (rtlight->static_numlighttrispvsbytes)
3008 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3009 switch (rtlight->shadowmode)
3011 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
3012 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
3013 case R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE:
3014 if (model->CompileShadowMap && rtlight->shadow)
3015 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3018 if (model->CompileShadowVolume && rtlight->shadow)
3019 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3022 // now we're done compiling the rtlight
3023 r_shadow_compilingrtlight = NULL;
3027 // use smallest available cullradius - box radius or light radius
3028 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3029 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3031 shadowzpasstris = 0;
3032 if (rtlight->static_meshchain_shadow_zpass)
3033 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
3034 shadowzpasstris += mesh->numtriangles;
3036 shadowzfailtris = 0;
3037 if (rtlight->static_meshchain_shadow_zfail)
3038 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
3039 shadowzfailtris += mesh->numtriangles;
3042 if (rtlight->static_numlighttrispvsbytes)
3043 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3044 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3048 if (rtlight->static_numlighttrispvsbytes)
3049 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3050 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3053 if (developer_extra.integer)
3054 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);
3057 void R_RTLight_Uncompile(rtlight_t *rtlight)
3059 if (rtlight->compiled)
3061 if (rtlight->static_meshchain_shadow_zpass)
3062 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
3063 rtlight->static_meshchain_shadow_zpass = NULL;
3064 if (rtlight->static_meshchain_shadow_zfail)
3065 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
3066 rtlight->static_meshchain_shadow_zfail = NULL;
3067 if (rtlight->static_meshchain_shadow_shadowmap)
3068 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
3069 rtlight->static_meshchain_shadow_shadowmap = NULL;
3070 // these allocations are grouped
3071 if (rtlight->static_surfacelist)
3072 Mem_Free(rtlight->static_surfacelist);
3073 rtlight->static_numleafs = 0;
3074 rtlight->static_numleafpvsbytes = 0;
3075 rtlight->static_leaflist = NULL;
3076 rtlight->static_leafpvs = NULL;
3077 rtlight->static_numsurfaces = 0;
3078 rtlight->static_surfacelist = NULL;
3079 rtlight->static_numshadowtrispvsbytes = 0;
3080 rtlight->static_shadowtrispvs = NULL;
3081 rtlight->static_numlighttrispvsbytes = 0;
3082 rtlight->static_lighttrispvs = NULL;
3083 rtlight->compiled = false;
3087 void R_Shadow_UncompileWorldLights(void)
3091 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3092 for (lightindex = 0;lightindex < range;lightindex++)
3094 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3097 R_RTLight_Uncompile(&light->rtlight);
3101 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3105 // reset the count of frustum planes
3106 // see rtlight->cached_frustumplanes definition for how much this array
3108 rtlight->cached_numfrustumplanes = 0;
3110 // haven't implemented a culling path for ortho rendering
3111 if (!r_refdef.view.useperspective)
3113 // check if the light is on screen and copy the 4 planes if it is
3114 for (i = 0;i < 4;i++)
3115 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3118 for (i = 0;i < 4;i++)
3119 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3124 // generate a deformed frustum that includes the light origin, this is
3125 // used to cull shadow casting surfaces that can not possibly cast a
3126 // shadow onto the visible light-receiving surfaces, which can be a
3129 // if the light origin is onscreen the result will be 4 planes exactly
3130 // if the light origin is offscreen on only one axis the result will
3131 // be exactly 5 planes (split-side case)
3132 // if the light origin is offscreen on two axes the result will be
3133 // exactly 4 planes (stretched corner case)
3134 for (i = 0;i < 4;i++)
3136 // quickly reject standard frustum planes that put the light
3137 // origin outside the frustum
3138 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3141 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3143 // if all the standard frustum planes were accepted, the light is onscreen
3144 // otherwise we need to generate some more planes below...
3145 if (rtlight->cached_numfrustumplanes < 4)
3147 // at least one of the stock frustum planes failed, so we need to
3148 // create one or two custom planes to enclose the light origin
3149 for (i = 0;i < 4;i++)
3151 // create a plane using the view origin and light origin, and a
3152 // single point from the frustum corner set
3153 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3154 VectorNormalize(plane.normal);
3155 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3156 // see if this plane is backwards and flip it if so
3157 for (j = 0;j < 4;j++)
3158 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3162 VectorNegate(plane.normal, plane.normal);
3164 // flipped plane, test again to see if it is now valid
3165 for (j = 0;j < 4;j++)
3166 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3168 // if the plane is still not valid, then it is dividing the
3169 // frustum and has to be rejected
3173 // we have created a valid plane, compute extra info
3174 PlaneClassify(&plane);
3176 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3178 // if we've found 5 frustum planes then we have constructed a
3179 // proper split-side case and do not need to keep searching for
3180 // planes to enclose the light origin
3181 if (rtlight->cached_numfrustumplanes == 5)
3189 for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
3191 plane = rtlight->cached_frustumplanes[i];
3192 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));
3197 // now add the light-space box planes if the light box is rotated, as any
3198 // caster outside the oriented light box is irrelevant (even if it passed
3199 // the worldspace light box, which is axial)
3200 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3202 for (i = 0;i < 6;i++)
3206 v[i >> 1] = (i & 1) ? -1 : 1;
3207 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3208 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3209 plane.dist = VectorNormalizeLength(plane.normal);
3210 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3211 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3217 // add the world-space reduced box planes
3218 for (i = 0;i < 6;i++)
3220 VectorClear(plane.normal);
3221 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3222 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
3223 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3232 // reduce all plane distances to tightly fit the rtlight cull box, which
3234 VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3235 VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3236 VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3237 VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3238 VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3239 VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3240 VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3241 VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3242 oldnum = rtlight->cached_numfrustumplanes;
3243 rtlight->cached_numfrustumplanes = 0;
3244 for (j = 0;j < oldnum;j++)
3246 // find the nearest point on the box to this plane
3247 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
3248 for (i = 1;i < 8;i++)
3250 dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
3251 if (bestdist > dist)
3254 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);
3255 // if the nearest point is near or behind the plane, we want this
3256 // plane, otherwise the plane is useless as it won't cull anything
3257 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
3259 PlaneClassify(&rtlight->cached_frustumplanes[j]);
3260 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
3267 void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
3271 RSurf_ActiveWorldEntity();
3273 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3276 GL_CullFace(GL_NONE);
3277 mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3278 for (;mesh;mesh = mesh->next)
3280 if (!mesh->sidetotals[r_shadow_shadowmapside])
3282 r_refdef.stats.lights_shadowtriangles += mesh->sidetotals[r_shadow_shadowmapside];
3283 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
3284 R_Mesh_Draw(0, mesh->numverts, mesh->sideoffsets[r_shadow_shadowmapside], mesh->sidetotals[r_shadow_shadowmapside], mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3288 else if (r_refdef.scene.worldentity->model)
3289 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);
3291 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3294 void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3296 qboolean zpass = false;
3299 int surfacelistindex;
3300 msurface_t *surface;
3302 RSurf_ActiveWorldEntity();
3304 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3307 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
3309 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
3310 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
3312 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
3313 for (;mesh;mesh = mesh->next)
3315 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
3316 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
3317 GL_LockArrays(0, mesh->numverts);
3318 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
3320 // increment stencil if frontface is infront of depthbuffer
3321 GL_CullFace(r_refdef.view.cullface_back);
3322 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
3323 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3324 // decrement stencil if backface is infront of depthbuffer
3325 GL_CullFace(r_refdef.view.cullface_front);
3326 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
3328 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
3330 // decrement stencil if backface is behind depthbuffer
3331 GL_CullFace(r_refdef.view.cullface_front);
3332 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
3333 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3334 // increment stencil if frontface is behind depthbuffer
3335 GL_CullFace(r_refdef.view.cullface_back);
3336 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
3338 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3339 GL_LockArrays(0, 0);
3343 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh)
3345 // use the shadow trispvs calculated earlier by GetLightInfo to cull world triangles on this dynamic light
3346 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
3347 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
3349 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
3350 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
3351 if (CHECKPVSBIT(trispvs, t))
3352 shadowmarklist[numshadowmark++] = t;
3354 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);
3356 else if (numsurfaces)
3357 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);
3359 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3362 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3364 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3365 vec_t relativeshadowradius;
3366 RSurf_ActiveModelEntity(ent, false, false, false);
3367 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3368 // we need to re-init the shader for each entity because the matrix changed
3369 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3370 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3371 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3372 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3373 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3374 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3375 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3376 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D)
3378 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
3381 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3382 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3385 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3387 // set up properties for rendering light onto this entity
3388 RSurf_ActiveModelEntity(ent, true, true, false);
3389 GL_AlphaTest(false);
3390 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3391 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3392 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3393 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3396 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
3398 if (!r_refdef.scene.worldmodel->DrawLight)
3401 // set up properties for rendering light onto this entity
3402 RSurf_ActiveWorldEntity();
3403 GL_AlphaTest(false);
3404 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3405 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3406 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3407 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3409 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
3411 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3414 void R_Shadow_DrawEntityLight(entity_render_t *ent)
3416 dp_model_t *model = ent->model;
3417 if (!model->DrawLight)
3420 R_Shadow_SetupEntityLight(ent);
3422 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3424 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3427 void R_Shadow_PrepareLight(rtlight_t *rtlight)
3431 int numleafs, numsurfaces;
3432 int *leaflist, *surfacelist;
3433 unsigned char *leafpvs, *shadowtrispvs, *lighttrispvs, *surfacesides;
3434 int numlightentities;
3435 int numlightentities_noselfshadow;
3436 int numshadowentities;
3437 int numshadowentities_noselfshadow;
3438 static entity_render_t *lightentities[MAX_EDICTS];
3439 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3440 static entity_render_t *shadowentities[MAX_EDICTS];
3441 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3443 rtlight->draw = false;
3445 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3446 // skip lights that are basically invisible (color 0 0 0)
3447 if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
3450 // loading is done before visibility checks because loading should happen
3451 // all at once at the start of a level, not when it stalls gameplay.
3452 // (especially important to benchmarks)
3454 if (rtlight->isstatic && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
3456 if (rtlight->compiled)
3457 R_RTLight_Uncompile(rtlight);
3458 R_RTLight_Compile(rtlight);
3462 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
3464 // look up the light style value at this time
3465 f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3466 VectorScale(rtlight->color, f, rtlight->currentcolor);
3468 if (rtlight->selected)
3470 f = 2 + sin(realtime * M_PI * 4.0);
3471 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3475 // if lightstyle is currently off, don't draw the light
3476 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3479 // if the light box is offscreen, skip it
3480 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3483 VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
3484 VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
3486 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3488 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3490 // compiled light, world available and can receive realtime lighting
3491 // retrieve leaf information
3492 numleafs = rtlight->static_numleafs;
3493 leaflist = rtlight->static_leaflist;
3494 leafpvs = rtlight->static_leafpvs;
3495 numsurfaces = rtlight->static_numsurfaces;
3496 surfacelist = rtlight->static_surfacelist;
3497 surfacesides = NULL;
3498 shadowtrispvs = rtlight->static_shadowtrispvs;
3499 lighttrispvs = rtlight->static_lighttrispvs;
3501 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3503 // dynamic light, world available and can receive realtime lighting
3504 // calculate lit surfaces and leafs
3505 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);
3506 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3507 leaflist = r_shadow_buffer_leaflist;
3508 leafpvs = r_shadow_buffer_leafpvs;
3509 surfacelist = r_shadow_buffer_surfacelist;
3510 surfacesides = r_shadow_buffer_surfacesides;
3511 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3512 lighttrispvs = r_shadow_buffer_lighttrispvs;
3513 // if the reduced leaf bounds are offscreen, skip it
3514 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3525 surfacesides = NULL;
3526 shadowtrispvs = NULL;
3527 lighttrispvs = NULL;
3529 // check if light is illuminating any visible leafs
3532 for (i = 0;i < numleafs;i++)
3533 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3539 // make a list of lit entities and shadow casting entities
3540 numlightentities = 0;
3541 numlightentities_noselfshadow = 0;
3542 numshadowentities = 0;
3543 numshadowentities_noselfshadow = 0;
3545 // add dynamic entities that are lit by the light
3546 for (i = 0;i < r_refdef.scene.numentities;i++)
3549 entity_render_t *ent = r_refdef.scene.entities[i];
3551 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3553 // skip the object entirely if it is not within the valid
3554 // shadow-casting region (which includes the lit region)
3555 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
3557 if (!(model = ent->model))
3559 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
3561 // this entity wants to receive light, is visible, and is
3562 // inside the light box
3563 // TODO: check if the surfaces in the model can receive light
3564 // so now check if it's in a leaf seen by the light
3565 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))
3567 if (ent->flags & RENDER_NOSELFSHADOW)
3568 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
3570 lightentities[numlightentities++] = ent;
3571 // since it is lit, it probably also casts a shadow...
3572 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3573 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3574 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3576 // note: exterior models without the RENDER_NOSELFSHADOW
3577 // flag still create a RENDER_NOSELFSHADOW shadow but
3578 // are lit normally, this means that they are
3579 // self-shadowing but do not shadow other
3580 // RENDER_NOSELFSHADOW entities such as the gun
3581 // (very weird, but keeps the player shadow off the gun)
3582 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3583 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3585 shadowentities[numshadowentities++] = ent;
3588 else if (ent->flags & RENDER_SHADOW)
3590 // this entity is not receiving light, but may still need to
3592 // TODO: check if the surfaces in the model can cast shadow
3593 // now check if it is in a leaf seen by the light
3594 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))
3596 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3597 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3598 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3600 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3601 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3603 shadowentities[numshadowentities++] = ent;
3608 // return if there's nothing at all to light
3609 if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
3612 // count this light in the r_speeds
3613 r_refdef.stats.lights++;
3615 // flag it as worth drawing later
3616 rtlight->draw = true;
3618 // cache all the animated entities that cast a shadow but are not visible
3619 for (i = 0;i < numshadowentities;i++)
3620 if (!shadowentities[i]->animcache_vertex3f)
3621 R_AnimCache_GetEntity(shadowentities[i], false, false);
3622 for (i = 0;i < numshadowentities_noselfshadow;i++)
3623 if (!shadowentities_noselfshadow[i]->animcache_vertex3f)
3624 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
3626 // allocate some temporary memory for rendering this light later in the frame
3627 // reusable buffers need to be copied, static data can be used as-is
3628 rtlight->cached_numlightentities = numlightentities;
3629 rtlight->cached_numlightentities_noselfshadow = numlightentities_noselfshadow;
3630 rtlight->cached_numshadowentities = numshadowentities;
3631 rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
3632 rtlight->cached_numsurfaces = numsurfaces;
3633 rtlight->cached_lightentities = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
3634 rtlight->cached_lightentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
3635 rtlight->cached_shadowentities = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
3636 rtlight->cached_shadowentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
3637 if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
3639 int numshadowtrispvsbytes = (((r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles) + 7) >> 3);
3640 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
3641 rtlight->cached_shadowtrispvs = (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
3642 rtlight->cached_lighttrispvs = (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
3643 rtlight->cached_surfacelist = (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
3647 // compiled light data
3648 rtlight->cached_shadowtrispvs = shadowtrispvs;
3649 rtlight->cached_lighttrispvs = lighttrispvs;
3650 rtlight->cached_surfacelist = surfacelist;
3654 void R_Shadow_DrawLight(rtlight_t *rtlight)
3658 unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
3659 int numlightentities;
3660 int numlightentities_noselfshadow;
3661 int numshadowentities;
3662 int numshadowentities_noselfshadow;
3663 entity_render_t **lightentities;
3664 entity_render_t **lightentities_noselfshadow;
3665 entity_render_t **shadowentities;
3666 entity_render_t **shadowentities_noselfshadow;
3668 static unsigned char entitysides[MAX_EDICTS];
3669 static unsigned char entitysides_noselfshadow[MAX_EDICTS];
3670 vec3_t nearestpoint;
3672 qboolean castshadows;
3675 // check if we cached this light this frame (meaning it is worth drawing)
3679 // if R_FrameData_Store ran out of space we skip anything dependent on it
3680 if (r_framedata_failed)
3683 numlightentities = rtlight->cached_numlightentities;
3684 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
3685 numshadowentities = rtlight->cached_numshadowentities;
3686 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
3687 numsurfaces = rtlight->cached_numsurfaces;
3688 lightentities = rtlight->cached_lightentities;
3689 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
3690 shadowentities = rtlight->cached_shadowentities;
3691 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
3692 shadowtrispvs = rtlight->cached_shadowtrispvs;
3693 lighttrispvs = rtlight->cached_lighttrispvs;
3694 surfacelist = rtlight->cached_surfacelist;
3696 // set up a scissor rectangle for this light
3697 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3700 // don't let sound skip if going slow
3701 if (r_refdef.scene.extraupdate)
3704 // make this the active rtlight for rendering purposes
3705 R_Shadow_RenderMode_ActiveLight(rtlight);
3707 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
3709 // optionally draw visible shape of the shadow volumes
3710 // for performance analysis by level designers
3711 R_Shadow_RenderMode_VisibleShadowVolumes();
3713 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
3714 for (i = 0;i < numshadowentities;i++)
3715 R_Shadow_DrawEntityShadow(shadowentities[i]);
3716 for (i = 0;i < numshadowentities_noselfshadow;i++)
3717 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3718 R_Shadow_RenderMode_VisibleLighting(false, false);
3721 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
3723 // optionally draw the illuminated areas
3724 // for performance analysis by level designers
3725 R_Shadow_RenderMode_VisibleLighting(false, false);
3727 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3728 for (i = 0;i < numlightentities;i++)
3729 R_Shadow_DrawEntityLight(lightentities[i]);
3730 for (i = 0;i < numlightentities_noselfshadow;i++)
3731 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3734 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
3736 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
3737 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
3738 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
3739 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
3741 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance/rtlight->radius));
3742 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
3743 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
3745 if (castshadows && (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE))
3751 int receivermask = 0;
3752 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
3753 Matrix4x4_Abs(&radiustolight);
3755 r_shadow_shadowmaplod = 0;
3756 for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
3757 if ((r_shadow_shadowmapmaxsize >> i) > lodlinear)
3758 r_shadow_shadowmaplod = i;
3760 if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
3761 size = max(1, r_shadow_shadowmapmaxsize >> r_shadow_shadowmaplod);
3763 size = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
3765 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
3767 surfacesides = NULL;
3770 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3772 castermask = rtlight->static_shadowmap_casters;
3773 receivermask = rtlight->static_shadowmap_receivers;
3777 surfacesides = r_shadow_buffer_surfacesides;
3778 for(i = 0;i < numsurfaces;i++)
3780 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
3781 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3782 castermask |= surfacesides[i];
3783 receivermask |= surfacesides[i];
3787 if (receivermask < 0x3F)
3789 for (i = 0;i < numlightentities;i++)
3790 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3791 if (receivermask < 0x3F)
3792 for(i = 0; i < numlightentities_noselfshadow;i++)
3793 receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3796 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
3800 for (i = 0;i < numshadowentities;i++)
3801 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3802 for (i = 0;i < numshadowentities_noselfshadow;i++)
3803 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3806 //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
3808 // render shadow casters into 6 sided depth texture
3809 for (side = 0;side < 6;side++) if (receivermask & (1 << side))
3811 R_Shadow_RenderMode_ShadowMap(side, receivermask, size);
3812 if (! (castermask & (1 << side))) continue;
3814 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
3815 for (i = 0;i < numshadowentities;i++) if (entitysides[i] & (1 << side))
3816 R_Shadow_DrawEntityShadow(shadowentities[i]);
3819 if (numlightentities_noselfshadow)
3821 // render lighting using the depth texture as shadowmap
3822 // draw lighting in the unmasked areas
3823 R_Shadow_RenderMode_Lighting(false, false, true);
3824 for (i = 0;i < numlightentities_noselfshadow;i++)
3825 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3828 // render shadow casters into 6 sided depth texture
3829 if (numshadowentities_noselfshadow)
3831 for (side = 0;side < 6;side++) if ((receivermask & castermask) & (1 << side))
3833 R_Shadow_RenderMode_ShadowMap(side, 0, size);
3834 for (i = 0;i < numshadowentities_noselfshadow;i++) if (entitysides_noselfshadow[i] & (1 << side))
3835 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3839 // render lighting using the depth texture as shadowmap
3840 // draw lighting in the unmasked areas
3841 R_Shadow_RenderMode_Lighting(false, false, true);
3842 // draw lighting in the unmasked areas
3844 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3845 for (i = 0;i < numlightentities;i++)
3846 R_Shadow_DrawEntityLight(lightentities[i]);
3848 else if (castshadows && vid.stencil)
3850 // draw stencil shadow volumes to mask off pixels that are in shadow
3851 // so that they won't receive lighting
3852 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
3853 R_Shadow_ClearStencil();
3856 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
3857 for (i = 0;i < numshadowentities;i++)
3858 R_Shadow_DrawEntityShadow(shadowentities[i]);
3860 // draw lighting in the unmasked areas
3861 R_Shadow_RenderMode_Lighting(true, false, false);
3862 for (i = 0;i < numlightentities_noselfshadow;i++)
3863 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3865 for (i = 0;i < numshadowentities_noselfshadow;i++)
3866 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3868 // draw lighting in the unmasked areas
3869 R_Shadow_RenderMode_Lighting(true, false, false);
3871 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3872 for (i = 0;i < numlightentities;i++)
3873 R_Shadow_DrawEntityLight(lightentities[i]);
3877 // draw lighting in the unmasked areas
3878 R_Shadow_RenderMode_Lighting(false, false, false);
3880 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3881 for (i = 0;i < numlightentities;i++)
3882 R_Shadow_DrawEntityLight(lightentities[i]);
3883 for (i = 0;i < numlightentities_noselfshadow;i++)
3884 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3887 if (r_shadow_usingdeferredprepass)
3889 // when rendering deferred lighting, we simply rasterize the box
3890 if (castshadows && (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE))
3891 R_Shadow_RenderMode_DrawDeferredLight(false, true);
3892 else if (castshadows && vid.stencil)
3893 R_Shadow_RenderMode_DrawDeferredLight(true, false);
3895 R_Shadow_RenderMode_DrawDeferredLight(false, false);
3899 static void R_Shadow_FreeDeferred(void)
3901 if (r_shadow_prepassgeometryfbo)
3902 qglDeleteFramebuffersEXT(1, &r_shadow_prepassgeometryfbo);CHECKGLERROR
3903 r_shadow_prepassgeometryfbo = 0;
3905 if (r_shadow_prepasslightingfbo)
3906 qglDeleteFramebuffersEXT(1, &r_shadow_prepasslightingfbo);CHECKGLERROR
3907 r_shadow_prepasslightingfbo = 0;
3909 if (r_shadow_prepassgeometrydepthtexture)
3910 R_FreeTexture(r_shadow_prepassgeometrydepthtexture);
3911 r_shadow_prepassgeometrydepthtexture = NULL;
3913 if (r_shadow_prepassgeometrynormalmaptexture)
3914 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
3915 r_shadow_prepassgeometrynormalmaptexture = NULL;
3917 if (r_shadow_prepasslightingdiffusetexture)
3918 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
3919 r_shadow_prepasslightingdiffusetexture = NULL;
3921 if (r_shadow_prepasslightingspeculartexture)
3922 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
3923 r_shadow_prepasslightingspeculartexture = NULL;
3926 void R_Shadow_DrawPrepass(void)
3934 entity_render_t *ent;
3936 GL_AlphaTest(false);
3937 R_Mesh_ColorPointer(NULL, 0, 0);
3938 R_Mesh_ResetTextureState();
3940 GL_ColorMask(1,1,1,1);
3941 GL_BlendFunc(GL_ONE, GL_ZERO);
3944 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepassgeometryfbo);CHECKGLERROR
3945 qglClearColor(0.5f,0.5f,0.5f,1.0f);CHECKGLERROR
3946 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);CHECKGLERROR
3948 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
3949 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
3950 if (r_timereport_active)
3951 R_TimeReport("prepassworld");
3953 for (i = 0;i < r_refdef.scene.numentities;i++)
3955 if (!r_refdef.viewcache.entityvisible[i])
3957 ent = r_refdef.scene.entities[i];
3958 if (ent->model && ent->model->DrawPrepass != NULL)
3959 ent->model->DrawPrepass(ent);
3962 if (r_timereport_active)
3963 R_TimeReport("prepassmodels");
3965 GL_DepthMask(false);
3966 GL_ColorMask(1,1,1,1);
3969 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepasslightingfbo);CHECKGLERROR
3970 qglClearColor(0.0f,0.0f,0.0f,0.0f);CHECKGLERROR
3971 GL_Clear(GL_COLOR_BUFFER_BIT);CHECKGLERROR
3972 if (r_refdef.fogenabled)
3973 qglClearColor(r_refdef.fogcolor[0],r_refdef.fogcolor[1],r_refdef.fogcolor[2],0);CHECKGLERROR
3975 R_Shadow_RenderMode_Begin();
3977 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3978 if (r_shadow_debuglight.integer >= 0)
3980 lightindex = r_shadow_debuglight.integer;
3981 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3982 if (light && (light->flags & flag))
3983 R_Shadow_DrawLight(&light->rtlight);
3987 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3988 for (lightindex = 0;lightindex < range;lightindex++)
3990 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3991 if (light && (light->flags & flag))
3992 R_Shadow_DrawLight(&light->rtlight);
3995 if (r_refdef.scene.rtdlight)
3996 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
3997 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
3999 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);CHECKGLERROR
4000 if (r_refdef.fogenabled)
4001 qglClearColor(r_refdef.fogcolor[0],r_refdef.fogcolor[1],r_refdef.fogcolor[2],0);CHECKGLERROR
4003 R_Shadow_RenderMode_End();
4005 if (r_timereport_active)
4006 R_TimeReport("prepasslights");
4009 void R_Shadow_DrawLightSprites(void);
4010 void R_Shadow_PrepareLights(void)
4020 if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4) ||
4021 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
4022 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0) ||
4023 r_shadow_shadowmaptexturetype != r_shadow_shadowmapping_texturetype.integer ||
4024 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
4025 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
4026 r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
4027 R_Shadow_FreeShadowMaps();
4029 switch (vid.renderpath)
4031 case RENDERPATH_GL20:
4032 case RENDERPATH_CGGL:
4033 if (!r_shadow_deferred.integer || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_STENCIL || !vid.support.ext_framebuffer_object || vid.maxdrawbuffers < 2)
4035 r_shadow_usingdeferredprepass = false;
4036 if (r_shadow_prepass_width)
4037 R_Shadow_FreeDeferred();
4038 r_shadow_prepass_width = r_shadow_prepass_height = 0;
4042 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
4044 R_Shadow_FreeDeferred();
4046 r_shadow_usingdeferredprepass = true;
4047 r_shadow_prepass_width = vid.width;
4048 r_shadow_prepass_height = vid.height;
4049 r_shadow_prepassgeometrydepthtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "prepassgeometrydepthmap", vid.width, vid.height, 24, false);
4050 r_shadow_prepassgeometrynormalmaptexture = R_LoadTexture2D(r_shadow_texturepool, "prepassgeometrynormalmap", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, NULL);
4051 r_shadow_prepasslightingdiffusetexture = R_LoadTexture2D(r_shadow_texturepool, "prepasslightingdiffuse", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, NULL);
4052 r_shadow_prepasslightingspeculartexture = R_LoadTexture2D(r_shadow_texturepool, "prepasslightingspecular", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, NULL);
4054 // set up the geometry pass fbo (depth + normalmap)
4055 qglGenFramebuffersEXT(1, &r_shadow_prepassgeometryfbo);CHECKGLERROR
4056 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepassgeometryfbo);CHECKGLERROR
4057 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_prepassgeometrydepthtexture), 0);CHECKGLERROR
4058 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_prepassgeometrynormalmaptexture), 0);CHECKGLERROR
4059 // render depth into one texture and normalmap into the other
4060 if (qglDrawBuffersARB)
4062 qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);CHECKGLERROR
4063 qglReadBuffer(GL_NONE);CHECKGLERROR
4065 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4066 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4068 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4069 Cvar_SetValueQuick(&r_shadow_deferred, 0);
4070 r_shadow_usingdeferredprepass = false;
4073 // set up the lighting pass fbo (diffuse + specular)
4074 qglGenFramebuffersEXT(1, &r_shadow_prepasslightingfbo);CHECKGLERROR
4075 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepasslightingfbo);CHECKGLERROR
4076 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_prepassgeometrydepthtexture), 0);CHECKGLERROR
4077 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_prepasslightingdiffusetexture), 0);CHECKGLERROR
4078 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_prepasslightingspeculartexture), 0);CHECKGLERROR
4079 // render diffuse into one texture and specular into another,
4080 // with depth and normalmap bound as textures,
4081 // with depth bound as attachment as well
4082 if (qglDrawBuffersARB)
4084 qglDrawBuffersARB(2, r_shadow_prepasslightingdrawbuffers);CHECKGLERROR
4085 qglReadBuffer(GL_NONE);CHECKGLERROR
4087 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4088 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4090 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4091 Cvar_SetValueQuick(&r_shadow_deferred, 0);
4092 r_shadow_usingdeferredprepass = false;
4096 case RENDERPATH_GL13:
4097 case RENDERPATH_GL11:
4098 r_shadow_usingdeferredprepass = false;
4102 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);
4104 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4105 if (r_shadow_debuglight.integer >= 0)
4107 lightindex = r_shadow_debuglight.integer;
4108 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4109 if (light && (light->flags & flag))
4110 R_Shadow_PrepareLight(&light->rtlight);
4114 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4115 for (lightindex = 0;lightindex < range;lightindex++)
4117 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4118 if (light && (light->flags & flag))
4119 R_Shadow_PrepareLight(&light->rtlight);
4122 if (r_refdef.scene.rtdlight)
4124 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4125 R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
4127 else if(gl_flashblend.integer)
4129 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4131 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
4132 f = (rtlight->style >= 0 ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4133 VectorScale(rtlight->color, f, rtlight->currentcolor);
4137 if (r_editlights.integer)
4138 R_Shadow_DrawLightSprites();
4141 void R_Shadow_DrawLights(void)
4149 R_Shadow_RenderMode_Begin();
4151 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4152 if (r_shadow_debuglight.integer >= 0)
4154 lightindex = r_shadow_debuglight.integer;
4155 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4156 if (light && (light->flags & flag))
4157 R_Shadow_DrawLight(&light->rtlight);
4161 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4162 for (lightindex = 0;lightindex < range;lightindex++)
4164 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4165 if (light && (light->flags & flag))
4166 R_Shadow_DrawLight(&light->rtlight);
4169 if (r_refdef.scene.rtdlight)
4170 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4171 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4173 R_Shadow_RenderMode_End();
4176 extern const float r_screenvertex3f[12];
4177 extern void R_SetupView(qboolean allowwaterclippingplane);
4178 extern void R_ResetViewRendering3D(void);
4179 extern void R_ResetViewRendering2D(void);
4180 extern cvar_t r_shadows;
4181 extern cvar_t r_shadows_darken;
4182 extern cvar_t r_shadows_drawafterrtlighting;
4183 extern cvar_t r_shadows_castfrombmodels;
4184 extern cvar_t r_shadows_throwdistance;
4185 extern cvar_t r_shadows_throwdirection;
4186 void R_DrawModelShadows(void)
4189 float relativethrowdistance;
4190 entity_render_t *ent;
4191 vec3_t relativelightorigin;
4192 vec3_t relativelightdirection;
4193 vec3_t relativeshadowmins, relativeshadowmaxs;
4194 vec3_t tmp, shadowdir;
4196 if (!r_refdef.scene.numentities || !vid.stencil)
4200 R_ResetViewRendering3D();
4201 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4202 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4203 R_Shadow_RenderMode_Begin();
4204 R_Shadow_RenderMode_ActiveLight(NULL);
4205 r_shadow_lightscissor[0] = r_refdef.view.x;
4206 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
4207 r_shadow_lightscissor[2] = r_refdef.view.width;
4208 r_shadow_lightscissor[3] = r_refdef.view.height;
4209 R_Shadow_RenderMode_StencilShadowVolumes(false);
4212 if (r_shadows.integer == 2)
4214 Math_atov(r_shadows_throwdirection.string, shadowdir);
4215 VectorNormalize(shadowdir);
4218 R_Shadow_ClearStencil();
4220 for (i = 0;i < r_refdef.scene.numentities;i++)
4222 ent = r_refdef.scene.entities[i];
4224 // cast shadows from anything of the map (submodels are optional)
4225 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4227 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4228 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
4229 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
4230 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
4231 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4234 if(ent->entitynumber != 0)
4236 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
4237 int entnum, entnum2, recursion;
4238 entnum = entnum2 = ent->entitynumber;
4239 for(recursion = 32; recursion > 0; --recursion)
4241 entnum2 = cl.entities[entnum].state_current.tagentity;
4242 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
4247 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
4249 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
4250 // transform into modelspace of OUR entity
4251 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
4252 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
4255 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4258 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4261 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
4262 RSurf_ActiveModelEntity(ent, false, false, false);
4263 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4264 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4268 // not really the right mode, but this will disable any silly stencil features
4269 R_Shadow_RenderMode_End();
4271 // set up ortho view for rendering this pass
4272 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4273 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4274 //GL_ScissorTest(true);
4275 //R_EntityMatrix(&identitymatrix);
4276 //R_Mesh_ResetTextureState();
4277 R_ResetViewRendering2D();
4278 R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
4279 R_Mesh_ColorPointer(NULL, 0, 0);
4280 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
4282 // set up a darkening blend on shadowed areas
4283 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4284 //GL_DepthRange(0, 1);
4285 //GL_DepthTest(false);
4286 //GL_DepthMask(false);
4287 //GL_PolygonOffset(0, 0);CHECKGLERROR
4288 GL_Color(0, 0, 0, r_shadows_darken.value);
4289 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4290 //qglDepthFunc(GL_ALWAYS);CHECKGLERROR
4291 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
4292 qglStencilMask(255);CHECKGLERROR
4293 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
4294 qglStencilFunc(GL_NOTEQUAL, 128, 255);CHECKGLERROR
4296 // apply the blend to the shadowed areas
4297 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
4299 // restore the viewport
4300 R_SetViewport(&r_refdef.view.viewport);
4302 // restore other state to normal
4303 //R_Shadow_RenderMode_End();
4306 void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4309 vec3_t centerorigin;
4311 // if it's too close, skip it
4312 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
4314 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4317 if (usequery && r_numqueries + 2 <= r_maxqueries)
4319 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4320 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4321 // 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
4322 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4325 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use qglDepthFunc instead
4326 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
4327 qglDepthFunc(GL_ALWAYS);
4328 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4329 R_Mesh_VertexPointer(vertex3f, 0, 0);
4330 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
4331 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4332 qglDepthFunc(GL_LEQUAL);
4333 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
4334 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4335 R_Mesh_VertexPointer(vertex3f, 0, 0);
4336 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
4337 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4340 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4343 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
4345 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4348 GLint allpixels = 0, visiblepixels = 0;
4349 // now we have to check the query result
4350 if (rtlight->corona_queryindex_visiblepixels)
4353 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
4354 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
4356 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
4357 if (visiblepixels < 1 || allpixels < 1)
4359 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
4360 cscale *= rtlight->corona_visibility;
4364 // FIXME: these traces should scan all render entities instead of cl.world
4365 if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
4368 VectorScale(rtlight->currentcolor, cscale, color);
4369 if (VectorLength(color) > (1.0f / 256.0f))
4372 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
4375 VectorNegate(color, color);
4376 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
4378 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4379 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);
4380 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4382 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
4386 void R_Shadow_DrawCoronas(void)
4394 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4396 if (r_waterstate.renderingscene)
4398 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4399 R_EntityMatrix(&identitymatrix);
4401 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4403 // check occlusion of coronas
4404 // use GL_ARB_occlusion_query if available
4405 // otherwise use raytraces
4407 usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
4410 GL_ColorMask(0,0,0,0);
4411 if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
4412 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
4415 r_maxqueries = (range + r_refdef.scene.numlights) * 4;
4416 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
4418 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
4421 RSurf_ActiveWorldEntity();
4422 GL_BlendFunc(GL_ONE, GL_ZERO);
4423 GL_CullFace(GL_NONE);
4424 GL_DepthMask(false);
4425 GL_DepthRange(0, 1);
4426 GL_PolygonOffset(0, 0);
4428 R_Mesh_ColorPointer(NULL, 0, 0);
4429 R_Mesh_ResetTextureState();
4430 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
4432 for (lightindex = 0;lightindex < range;lightindex++)
4434 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4437 rtlight = &light->rtlight;
4438 rtlight->corona_visibility = 0;
4439 rtlight->corona_queryindex_visiblepixels = 0;
4440 rtlight->corona_queryindex_allpixels = 0;
4441 if (!(rtlight->flags & flag))
4443 if (rtlight->corona <= 0)
4445 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4447 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4449 for (i = 0;i < r_refdef.scene.numlights;i++)
4451 rtlight = r_refdef.scene.lights[i];
4452 rtlight->corona_visibility = 0;
4453 rtlight->corona_queryindex_visiblepixels = 0;
4454 rtlight->corona_queryindex_allpixels = 0;
4455 if (!(rtlight->flags & flag))
4457 if (rtlight->corona <= 0)
4459 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4462 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4464 // now draw the coronas using the query data for intensity info
4465 for (lightindex = 0;lightindex < range;lightindex++)
4467 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4470 rtlight = &light->rtlight;
4471 if (rtlight->corona_visibility <= 0)
4473 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4475 for (i = 0;i < r_refdef.scene.numlights;i++)
4477 rtlight = r_refdef.scene.lights[i];
4478 if (rtlight->corona_visibility <= 0)
4480 if (gl_flashblend.integer)
4481 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4483 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4489 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
4490 typedef struct suffixinfo_s
4493 qboolean flipx, flipy, flipdiagonal;
4496 static suffixinfo_t suffix[3][6] =
4499 {"px", false, false, false},
4500 {"nx", false, false, false},
4501 {"py", false, false, false},
4502 {"ny", false, false, false},
4503 {"pz", false, false, false},
4504 {"nz", false, false, false}
4507 {"posx", false, false, false},
4508 {"negx", false, false, false},
4509 {"posy", false, false, false},
4510 {"negy", false, false, false},
4511 {"posz", false, false, false},
4512 {"negz", false, false, false}
4515 {"rt", true, false, true},
4516 {"lf", false, true, true},
4517 {"ft", true, true, false},
4518 {"bk", false, false, false},
4519 {"up", true, false, true},
4520 {"dn", true, false, true}
4524 static int componentorder[4] = {0, 1, 2, 3};
4526 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
4528 int i, j, cubemapsize;
4529 unsigned char *cubemappixels, *image_buffer;
4530 rtexture_t *cubemaptexture;
4532 // must start 0 so the first loadimagepixels has no requested width/height
4534 cubemappixels = NULL;
4535 cubemaptexture = NULL;
4536 // keep trying different suffix groups (posx, px, rt) until one loads
4537 for (j = 0;j < 3 && !cubemappixels;j++)
4539 // load the 6 images in the suffix group
4540 for (i = 0;i < 6;i++)
4542 // generate an image name based on the base and and suffix
4543 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
4545 if ((image_buffer = loadimagepixelsbgra(name, false, false)))
4547 // an image loaded, make sure width and height are equal
4548 if (image_width == image_height && (!cubemappixels || image_width == cubemapsize))
4550 // if this is the first image to load successfully, allocate the cubemap memory
4551 if (!cubemappixels && image_width >= 1)
4553 cubemapsize = image_width;
4554 // note this clears to black, so unavailable sides are black
4555 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
4557 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
4559 Image_CopyMux(cubemappixels+i*cubemapsize*cubemapsize*4, image_buffer, cubemapsize, cubemapsize, suffix[j][i].flipx, suffix[j][i].flipy, suffix[j][i].flipdiagonal, 4, 4, componentorder);
4562 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
4564 Mem_Free(image_buffer);
4568 // if a cubemap loaded, upload it
4571 if (developer_loading.integer)
4572 Con_Printf("loading cubemap \"%s\"\n", basename);
4574 if (!r_shadow_filters_texturepool)
4575 r_shadow_filters_texturepool = R_AllocTexturePool();
4576 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_BGRA, (gl_texturecompression_lightcubemaps.integer ? TEXF_COMPRESS : 0) | TEXF_FORCELINEAR, NULL);
4577 Mem_Free(cubemappixels);
4581 Con_DPrintf("failed to load cubemap \"%s\"\n", basename);
4582 if (developer_loading.integer)
4584 Con_Printf("(tried tried images ");
4585 for (j = 0;j < 3;j++)
4586 for (i = 0;i < 6;i++)
4587 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
4588 Con_Print(" and was unable to find any of them).\n");
4591 return cubemaptexture;
4594 rtexture_t *R_Shadow_Cubemap(const char *basename)
4597 for (i = 0;i < numcubemaps;i++)
4598 if (!strcasecmp(cubemaps[i].basename, basename))
4599 return cubemaps[i].texture ? cubemaps[i].texture : r_texture_whitecube;
4600 if (i >= MAX_CUBEMAPS)
4601 return r_texture_whitecube;
4603 strlcpy(cubemaps[i].basename, basename, sizeof(cubemaps[i].basename));
4604 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
4605 return cubemaps[i].texture;
4608 void R_Shadow_FreeCubemaps(void)
4611 for (i = 0;i < numcubemaps;i++)
4613 if (developer_loading.integer)
4614 Con_Printf("unloading cubemap \"%s\"\n", cubemaps[i].basename);
4615 if (cubemaps[i].texture)
4616 R_FreeTexture(cubemaps[i].texture);
4620 R_FreeTexturePool(&r_shadow_filters_texturepool);
4623 dlight_t *R_Shadow_NewWorldLight(void)
4625 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4628 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)
4631 // validate parameters
4632 if (style < 0 || style >= MAX_LIGHTSTYLES)
4634 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
4640 // copy to light properties
4641 VectorCopy(origin, light->origin);
4642 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4643 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4644 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4646 light->color[0] = max(color[0], 0);
4647 light->color[1] = max(color[1], 0);
4648 light->color[2] = max(color[2], 0);
4650 light->color[0] = color[0];
4651 light->color[1] = color[1];
4652 light->color[2] = color[2];
4653 light->radius = max(radius, 0);
4654 light->style = style;
4655 light->shadow = shadowenable;
4656 light->corona = corona;
4657 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4658 light->coronasizescale = coronasizescale;
4659 light->ambientscale = ambientscale;
4660 light->diffusescale = diffusescale;
4661 light->specularscale = specularscale;
4662 light->flags = flags;
4664 // update renderable light data
4665 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4666 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);
4669 void R_Shadow_FreeWorldLight(dlight_t *light)
4671 if (r_shadow_selectedlight == light)
4672 r_shadow_selectedlight = NULL;
4673 R_RTLight_Uncompile(&light->rtlight);
4674 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4677 void R_Shadow_ClearWorldLights(void)
4681 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4682 for (lightindex = 0;lightindex < range;lightindex++)
4684 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4686 R_Shadow_FreeWorldLight(light);
4688 r_shadow_selectedlight = NULL;
4689 R_Shadow_FreeCubemaps();
4692 void R_Shadow_SelectLight(dlight_t *light)
4694 if (r_shadow_selectedlight)
4695 r_shadow_selectedlight->selected = false;
4696 r_shadow_selectedlight = light;
4697 if (r_shadow_selectedlight)
4698 r_shadow_selectedlight->selected = true;
4701 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4703 // this is never batched (there can be only one)
4705 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
4706 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4707 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4710 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4715 skinframe_t *skinframe;
4718 // this is never batched (due to the ent parameter changing every time)
4719 // so numsurfaces == 1 and surfacelist[0] == lightnumber
4720 const dlight_t *light = (dlight_t *)ent;
4723 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
4726 VectorScale(light->color, intensity, spritecolor);
4727 if (VectorLength(spritecolor) < 0.1732f)
4728 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
4729 if (VectorLength(spritecolor) > 1.0f)
4730 VectorNormalize(spritecolor);
4732 // draw light sprite
4733 if (light->cubemapname[0] && !light->shadow)
4734 skinframe = r_editlights_sprcubemapnoshadowlight;
4735 else if (light->cubemapname[0])
4736 skinframe = r_editlights_sprcubemaplight;
4737 else if (!light->shadow)
4738 skinframe = r_editlights_sprnoshadowlight;
4740 skinframe = r_editlights_sprlight;
4742 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);
4743 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4745 // draw selection sprite if light is selected
4746 if (light->selected)
4748 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4749 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4750 // VorteX todo: add normalmode/realtime mode light overlay sprites?
4754 void R_Shadow_DrawLightSprites(void)
4758 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4759 for (lightindex = 0;lightindex < range;lightindex++)
4761 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4763 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
4765 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
4768 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
4773 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
4774 if (lightindex >= range)
4776 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4779 rtlight = &light->rtlight;
4780 //if (!(rtlight->flags & flag))
4782 VectorCopy(rtlight->shadoworigin, origin);
4783 *radius = rtlight->radius;
4784 VectorCopy(rtlight->color, color);
4788 void R_Shadow_SelectLightInView(void)
4790 float bestrating, rating, temp[3];
4794 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4797 for (lightindex = 0;lightindex < range;lightindex++)
4799 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4802 VectorSubtract(light->origin, r_refdef.view.origin, temp);
4803 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
4806 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
4807 if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1.0f)
4809 bestrating = rating;
4814 R_Shadow_SelectLight(best);
4817 void R_Shadow_LoadWorldLights(void)
4819 int n, a, style, shadow, flags;
4820 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
4821 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
4822 if (cl.worldmodel == NULL)
4824 Con_Print("No map loaded.\n");
4827 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4828 strlcat (name, ".rtlights", sizeof (name));
4829 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4839 for (;COM_Parse(t, true) && strcmp(
4840 if (COM_Parse(t, true))
4842 if (com_token[0] == '!')
4845 origin[0] = atof(com_token+1);
4848 origin[0] = atof(com_token);
4853 while (*s && *s != '\n' && *s != '\r')
4859 // check for modifier flags
4866 #if _MSC_VER >= 1400
4867 #define sscanf sscanf_s
4869 cubemapname[sizeof(cubemapname)-1] = 0;
4870 #if MAX_QPATH != 128
4871 #error update this code if MAX_QPATH changes
4873 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
4874 #if _MSC_VER >= 1400
4875 , sizeof(cubemapname)
4877 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
4880 flags = LIGHTFLAG_REALTIMEMODE;
4888 coronasizescale = 0.25f;
4890 VectorClear(angles);
4893 if (a < 9 || !strcmp(cubemapname, "\"\""))
4895 // remove quotes on cubemapname
4896 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
4899 namelen = strlen(cubemapname) - 2;
4900 memmove(cubemapname, cubemapname + 1, namelen);
4901 cubemapname[namelen] = '\0';
4905 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);
4908 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4916 Con_Printf("invalid rtlights file \"%s\"\n", name);
4917 Mem_Free(lightsstring);
4921 void R_Shadow_SaveWorldLights(void)
4925 size_t bufchars, bufmaxchars;
4927 char name[MAX_QPATH];
4928 char line[MAX_INPUTLINE];
4929 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
4930 // I hate lines which are 3 times my screen size :( --blub
4933 if (cl.worldmodel == NULL)
4935 Con_Print("No map loaded.\n");
4938 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4939 strlcat (name, ".rtlights", sizeof (name));
4940 bufchars = bufmaxchars = 0;
4942 for (lightindex = 0;lightindex < range;lightindex++)
4944 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4947 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
4948 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);
4949 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
4950 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]);
4952 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);
4953 if (bufchars + strlen(line) > bufmaxchars)
4955 bufmaxchars = bufchars + strlen(line) + 2048;
4957 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
4961 memcpy(buf, oldbuf, bufchars);
4967 memcpy(buf + bufchars, line, strlen(line));
4968 bufchars += strlen(line);
4972 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
4977 void R_Shadow_LoadLightsFile(void)
4980 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
4981 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
4982 if (cl.worldmodel == NULL)
4984 Con_Print("No map loaded.\n");
4987 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4988 strlcat (name, ".lights", sizeof (name));
4989 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4997 while (*s && *s != '\n' && *s != '\r')
5003 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);
5007 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);
5010 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
5011 radius = bound(15, radius, 4096);
5012 VectorScale(color, (2.0f / (8388608.0f)), color);
5013 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5021 Con_Printf("invalid lights file \"%s\"\n", name);
5022 Mem_Free(lightsstring);
5026 // tyrlite/hmap2 light types in the delay field
5027 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
5029 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
5031 int entnum, style, islight, skin, pflags, effects, type, n;
5034 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
5035 char key[256], value[MAX_INPUTLINE];
5037 if (cl.worldmodel == NULL)
5039 Con_Print("No map loaded.\n");
5042 // try to load a .ent file first
5043 FS_StripExtension (cl.worldmodel->name, key, sizeof (key));
5044 strlcat (key, ".ent", sizeof (key));
5045 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
5046 // and if that is not found, fall back to the bsp file entity string
5048 data = cl.worldmodel->brush.entities;
5051 for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
5053 type = LIGHTTYPE_MINUSX;
5054 origin[0] = origin[1] = origin[2] = 0;
5055 originhack[0] = originhack[1] = originhack[2] = 0;
5056 angles[0] = angles[1] = angles[2] = 0;
5057 color[0] = color[1] = color[2] = 1;
5058 light[0] = light[1] = light[2] = 1;light[3] = 300;
5059 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
5069 if (!COM_ParseToken_Simple(&data, false, false))
5071 if (com_token[0] == '}')
5072 break; // end of entity
5073 if (com_token[0] == '_')
5074 strlcpy(key, com_token + 1, sizeof(key));
5076 strlcpy(key, com_token, sizeof(key));
5077 while (key[strlen(key)-1] == ' ') // remove trailing spaces
5078 key[strlen(key)-1] = 0;
5079 if (!COM_ParseToken_Simple(&data, false, false))
5081 strlcpy(value, com_token, sizeof(value));
5083 // now that we have the key pair worked out...
5084 if (!strcmp("light", key))
5086 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5090 light[0] = vec[0] * (1.0f / 256.0f);
5091 light[1] = vec[0] * (1.0f / 256.0f);
5092 light[2] = vec[0] * (1.0f / 256.0f);
5098 light[0] = vec[0] * (1.0f / 255.0f);
5099 light[1] = vec[1] * (1.0f / 255.0f);
5100 light[2] = vec[2] * (1.0f / 255.0f);
5104 else if (!strcmp("delay", key))
5106 else if (!strcmp("origin", key))
5107 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5108 else if (!strcmp("angle", key))
5109 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5110 else if (!strcmp("angles", key))
5111 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5112 else if (!strcmp("color", key))
5113 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5114 else if (!strcmp("wait", key))
5115 fadescale = atof(value);
5116 else if (!strcmp("classname", key))
5118 if (!strncmp(value, "light", 5))
5121 if (!strcmp(value, "light_fluoro"))
5126 overridecolor[0] = 1;
5127 overridecolor[1] = 1;
5128 overridecolor[2] = 1;
5130 if (!strcmp(value, "light_fluorospark"))
5135 overridecolor[0] = 1;
5136 overridecolor[1] = 1;
5137 overridecolor[2] = 1;
5139 if (!strcmp(value, "light_globe"))
5144 overridecolor[0] = 1;
5145 overridecolor[1] = 0.8;
5146 overridecolor[2] = 0.4;
5148 if (!strcmp(value, "light_flame_large_yellow"))
5153 overridecolor[0] = 1;
5154 overridecolor[1] = 0.5;
5155 overridecolor[2] = 0.1;
5157 if (!strcmp(value, "light_flame_small_yellow"))
5162 overridecolor[0] = 1;
5163 overridecolor[1] = 0.5;
5164 overridecolor[2] = 0.1;
5166 if (!strcmp(value, "light_torch_small_white"))
5171 overridecolor[0] = 1;
5172 overridecolor[1] = 0.5;
5173 overridecolor[2] = 0.1;
5175 if (!strcmp(value, "light_torch_small_walltorch"))
5180 overridecolor[0] = 1;
5181 overridecolor[1] = 0.5;
5182 overridecolor[2] = 0.1;
5186 else if (!strcmp("style", key))
5187 style = atoi(value);
5188 else if (!strcmp("skin", key))
5189 skin = (int)atof(value);
5190 else if (!strcmp("pflags", key))
5191 pflags = (int)atof(value);
5192 else if (!strcmp("effects", key))
5193 effects = (int)atof(value);
5194 else if (cl.worldmodel->type == mod_brushq3)
5196 if (!strcmp("scale", key))
5197 lightscale = atof(value);
5198 if (!strcmp("fade", key))
5199 fadescale = atof(value);
5204 if (lightscale <= 0)
5208 if (color[0] == color[1] && color[0] == color[2])
5210 color[0] *= overridecolor[0];
5211 color[1] *= overridecolor[1];
5212 color[2] *= overridecolor[2];
5214 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5215 color[0] = color[0] * light[0];
5216 color[1] = color[1] * light[1];
5217 color[2] = color[2] * light[2];
5220 case LIGHTTYPE_MINUSX:
5222 case LIGHTTYPE_RECIPX:
5224 VectorScale(color, (1.0f / 16.0f), color);
5226 case LIGHTTYPE_RECIPXX:
5228 VectorScale(color, (1.0f / 16.0f), color);
5231 case LIGHTTYPE_NONE:
5235 case LIGHTTYPE_MINUSXX:
5238 VectorAdd(origin, originhack, origin);
5240 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);
5243 Mem_Free(entfiledata);
5247 void R_Shadow_SetCursorLocationForView(void)
5250 vec3_t dest, endpos;
5252 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5253 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
5254 if (trace.fraction < 1)
5256 dist = trace.fraction * r_editlights_cursordistance.value;
5257 push = r_editlights_cursorpushback.value;
5261 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5262 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5266 VectorClear( endpos );
5268 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5269 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5270 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5273 void R_Shadow_UpdateWorldLightSelection(void)
5275 if (r_editlights.integer)
5277 R_Shadow_SetCursorLocationForView();
5278 R_Shadow_SelectLightInView();
5281 R_Shadow_SelectLight(NULL);
5284 void R_Shadow_EditLights_Clear_f(void)
5286 R_Shadow_ClearWorldLights();
5289 void R_Shadow_EditLights_Reload_f(void)
5293 strlcpy(r_shadow_mapname, cl.worldmodel->name, sizeof(r_shadow_mapname));
5294 R_Shadow_ClearWorldLights();
5295 R_Shadow_LoadWorldLights();
5296 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5298 R_Shadow_LoadLightsFile();
5299 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5300 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5304 void R_Shadow_EditLights_Save_f(void)
5308 R_Shadow_SaveWorldLights();
5311 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
5313 R_Shadow_ClearWorldLights();
5314 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5317 void R_Shadow_EditLights_ImportLightsFile_f(void)
5319 R_Shadow_ClearWorldLights();
5320 R_Shadow_LoadLightsFile();
5323 void R_Shadow_EditLights_Spawn_f(void)
5326 if (!r_editlights.integer)
5328 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5331 if (Cmd_Argc() != 1)
5333 Con_Print("r_editlights_spawn does not take parameters\n");
5336 color[0] = color[1] = color[2] = 1;
5337 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5340 void R_Shadow_EditLights_Edit_f(void)
5342 vec3_t origin, angles, color;
5343 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5344 int style, shadows, flags, normalmode, realtimemode;
5345 char cubemapname[MAX_INPUTLINE];
5346 if (!r_editlights.integer)
5348 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5351 if (!r_shadow_selectedlight)
5353 Con_Print("No selected light.\n");
5356 VectorCopy(r_shadow_selectedlight->origin, origin);
5357 VectorCopy(r_shadow_selectedlight->angles, angles);
5358 VectorCopy(r_shadow_selectedlight->color, color);
5359 radius = r_shadow_selectedlight->radius;
5360 style = r_shadow_selectedlight->style;
5361 if (r_shadow_selectedlight->cubemapname)
5362 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5365 shadows = r_shadow_selectedlight->shadow;
5366 corona = r_shadow_selectedlight->corona;
5367 coronasizescale = r_shadow_selectedlight->coronasizescale;
5368 ambientscale = r_shadow_selectedlight->ambientscale;
5369 diffusescale = r_shadow_selectedlight->diffusescale;
5370 specularscale = r_shadow_selectedlight->specularscale;
5371 flags = r_shadow_selectedlight->flags;
5372 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5373 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5374 if (!strcmp(Cmd_Argv(1), "origin"))
5376 if (Cmd_Argc() != 5)
5378 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5381 origin[0] = atof(Cmd_Argv(2));
5382 origin[1] = atof(Cmd_Argv(3));
5383 origin[2] = atof(Cmd_Argv(4));
5385 else if (!strcmp(Cmd_Argv(1), "originx"))
5387 if (Cmd_Argc() != 3)
5389 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5392 origin[0] = atof(Cmd_Argv(2));
5394 else if (!strcmp(Cmd_Argv(1), "originy"))
5396 if (Cmd_Argc() != 3)
5398 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5401 origin[1] = atof(Cmd_Argv(2));
5403 else if (!strcmp(Cmd_Argv(1), "originz"))
5405 if (Cmd_Argc() != 3)
5407 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5410 origin[2] = atof(Cmd_Argv(2));
5412 else if (!strcmp(Cmd_Argv(1), "move"))
5414 if (Cmd_Argc() != 5)
5416 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5419 origin[0] += atof(Cmd_Argv(2));
5420 origin[1] += atof(Cmd_Argv(3));
5421 origin[2] += atof(Cmd_Argv(4));
5423 else if (!strcmp(Cmd_Argv(1), "movex"))
5425 if (Cmd_Argc() != 3)
5427 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5430 origin[0] += atof(Cmd_Argv(2));
5432 else if (!strcmp(Cmd_Argv(1), "movey"))
5434 if (Cmd_Argc() != 3)
5436 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5439 origin[1] += atof(Cmd_Argv(2));
5441 else if (!strcmp(Cmd_Argv(1), "movez"))
5443 if (Cmd_Argc() != 3)
5445 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5448 origin[2] += atof(Cmd_Argv(2));
5450 else if (!strcmp(Cmd_Argv(1), "angles"))
5452 if (Cmd_Argc() != 5)
5454 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5457 angles[0] = atof(Cmd_Argv(2));
5458 angles[1] = atof(Cmd_Argv(3));
5459 angles[2] = atof(Cmd_Argv(4));
5461 else if (!strcmp(Cmd_Argv(1), "anglesx"))
5463 if (Cmd_Argc() != 3)
5465 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5468 angles[0] = atof(Cmd_Argv(2));
5470 else if (!strcmp(Cmd_Argv(1), "anglesy"))
5472 if (Cmd_Argc() != 3)
5474 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5477 angles[1] = atof(Cmd_Argv(2));
5479 else if (!strcmp(Cmd_Argv(1), "anglesz"))
5481 if (Cmd_Argc() != 3)
5483 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5486 angles[2] = atof(Cmd_Argv(2));
5488 else if (!strcmp(Cmd_Argv(1), "color"))
5490 if (Cmd_Argc() != 5)
5492 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
5495 color[0] = atof(Cmd_Argv(2));
5496 color[1] = atof(Cmd_Argv(3));
5497 color[2] = atof(Cmd_Argv(4));
5499 else if (!strcmp(Cmd_Argv(1), "radius"))
5501 if (Cmd_Argc() != 3)
5503 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5506 radius = atof(Cmd_Argv(2));
5508 else if (!strcmp(Cmd_Argv(1), "colorscale"))
5510 if (Cmd_Argc() == 3)
5512 double scale = atof(Cmd_Argv(2));
5519 if (Cmd_Argc() != 5)
5521 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
5524 color[0] *= atof(Cmd_Argv(2));
5525 color[1] *= atof(Cmd_Argv(3));
5526 color[2] *= atof(Cmd_Argv(4));
5529 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
5531 if (Cmd_Argc() != 3)
5533 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5536 radius *= atof(Cmd_Argv(2));
5538 else if (!strcmp(Cmd_Argv(1), "style"))
5540 if (Cmd_Argc() != 3)
5542 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5545 style = atoi(Cmd_Argv(2));
5547 else if (!strcmp(Cmd_Argv(1), "cubemap"))
5551 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5554 if (Cmd_Argc() == 3)
5555 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
5559 else if (!strcmp(Cmd_Argv(1), "shadows"))
5561 if (Cmd_Argc() != 3)
5563 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5566 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5568 else if (!strcmp(Cmd_Argv(1), "corona"))
5570 if (Cmd_Argc() != 3)
5572 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5575 corona = atof(Cmd_Argv(2));
5577 else if (!strcmp(Cmd_Argv(1), "coronasize"))
5579 if (Cmd_Argc() != 3)
5581 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5584 coronasizescale = atof(Cmd_Argv(2));
5586 else if (!strcmp(Cmd_Argv(1), "ambient"))
5588 if (Cmd_Argc() != 3)
5590 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5593 ambientscale = atof(Cmd_Argv(2));
5595 else if (!strcmp(Cmd_Argv(1), "diffuse"))
5597 if (Cmd_Argc() != 3)
5599 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5602 diffusescale = atof(Cmd_Argv(2));
5604 else if (!strcmp(Cmd_Argv(1), "specular"))
5606 if (Cmd_Argc() != 3)
5608 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5611 specularscale = atof(Cmd_Argv(2));
5613 else if (!strcmp(Cmd_Argv(1), "normalmode"))
5615 if (Cmd_Argc() != 3)
5617 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5620 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5622 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
5624 if (Cmd_Argc() != 3)
5626 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5629 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5633 Con_Print("usage: r_editlights_edit [property] [value]\n");
5634 Con_Print("Selected light's properties:\n");
5635 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5636 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5637 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5638 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
5639 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
5640 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
5641 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5642 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
5643 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
5644 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
5645 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
5646 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
5647 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5648 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5651 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5652 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5655 void R_Shadow_EditLights_EditAll_f(void)
5661 if (!r_editlights.integer)
5663 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5667 // EditLights doesn't seem to have a "remove" command or something so:
5668 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5669 for (lightindex = 0;lightindex < range;lightindex++)
5671 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5674 R_Shadow_SelectLight(light);
5675 R_Shadow_EditLights_Edit_f();
5679 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
5681 int lightnumber, lightcount;
5682 size_t lightindex, range;
5686 if (!r_editlights.integer)
5688 x = vid_conwidth.value - 240;
5690 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
5693 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5694 for (lightindex = 0;lightindex < range;lightindex++)
5696 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5699 if (light == r_shadow_selectedlight)
5700 lightnumber = lightindex;
5703 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;
5704 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;
5706 if (r_shadow_selectedlight == NULL)
5708 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;
5709 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;
5710 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;
5711 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;
5712 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;
5713 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;
5714 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;
5715 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;
5716 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;
5717 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;
5718 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;
5719 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;
5720 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;
5721 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;
5722 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;
5725 void R_Shadow_EditLights_ToggleShadow_f(void)
5727 if (!r_editlights.integer)
5729 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5732 if (!r_shadow_selectedlight)
5734 Con_Print("No selected light.\n");
5737 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);
5740 void R_Shadow_EditLights_ToggleCorona_f(void)
5742 if (!r_editlights.integer)
5744 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5747 if (!r_shadow_selectedlight)
5749 Con_Print("No selected light.\n");
5752 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);
5755 void R_Shadow_EditLights_Remove_f(void)
5757 if (!r_editlights.integer)
5759 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
5762 if (!r_shadow_selectedlight)
5764 Con_Print("No selected light.\n");
5767 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
5768 r_shadow_selectedlight = NULL;
5771 void R_Shadow_EditLights_Help_f(void)
5774 "Documentation on r_editlights system:\n"
5776 "r_editlights : enable/disable editing mode\n"
5777 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
5778 "r_editlights_cursorpushback : push back cursor this far from surface\n"
5779 "r_editlights_cursorpushoff : push cursor off surface this far\n"
5780 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
5781 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
5783 "r_editlights_help : this help\n"
5784 "r_editlights_clear : remove all lights\n"
5785 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
5786 "r_editlights_save : save to .rtlights file\n"
5787 "r_editlights_spawn : create a light with default settings\n"
5788 "r_editlights_edit command : edit selected light - more documentation below\n"
5789 "r_editlights_remove : remove selected light\n"
5790 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
5791 "r_editlights_importlightentitiesfrommap : reload light entities\n"
5792 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
5794 "origin x y z : set light location\n"
5795 "originx x: set x component of light location\n"
5796 "originy y: set y component of light location\n"
5797 "originz z: set z component of light location\n"
5798 "move x y z : adjust light location\n"
5799 "movex x: adjust x component of light location\n"
5800 "movey y: adjust y component of light location\n"
5801 "movez z: adjust z component of light location\n"
5802 "angles x y z : set light angles\n"
5803 "anglesx x: set x component of light angles\n"
5804 "anglesy y: set y component of light angles\n"
5805 "anglesz z: set z component of light angles\n"
5806 "color r g b : set color of light (can be brighter than 1 1 1)\n"
5807 "radius radius : set radius (size) of light\n"
5808 "colorscale grey : multiply color of light (1 does nothing)\n"
5809 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
5810 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
5811 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
5812 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
5813 "cubemap basename : set filter cubemap of light (not yet supported)\n"
5814 "shadows 1/0 : turn on/off shadows\n"
5815 "corona n : set corona intensity\n"
5816 "coronasize n : set corona size (0-1)\n"
5817 "ambient n : set ambient intensity (0-1)\n"
5818 "diffuse n : set diffuse intensity (0-1)\n"
5819 "specular n : set specular intensity (0-1)\n"
5820 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
5821 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
5822 "<nothing> : print light properties to console\n"
5826 void R_Shadow_EditLights_CopyInfo_f(void)
5828 if (!r_editlights.integer)
5830 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
5833 if (!r_shadow_selectedlight)
5835 Con_Print("No selected light.\n");
5838 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
5839 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
5840 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
5841 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
5842 if (r_shadow_selectedlight->cubemapname)
5843 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
5845 r_shadow_bufferlight.cubemapname[0] = 0;
5846 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
5847 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
5848 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
5849 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
5850 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
5851 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
5852 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
5855 void R_Shadow_EditLights_PasteInfo_f(void)
5857 if (!r_editlights.integer)
5859 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
5862 if (!r_shadow_selectedlight)
5864 Con_Print("No selected light.\n");
5867 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);
5870 void R_Shadow_EditLights_Init(void)
5872 Cvar_RegisterVariable(&r_editlights);
5873 Cvar_RegisterVariable(&r_editlights_cursordistance);
5874 Cvar_RegisterVariable(&r_editlights_cursorpushback);
5875 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
5876 Cvar_RegisterVariable(&r_editlights_cursorgrid);
5877 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
5878 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
5879 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
5880 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)");
5881 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
5882 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
5883 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
5884 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)");
5885 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
5886 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
5887 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
5888 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
5889 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
5890 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
5891 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)");
5897 =============================================================================
5901 =============================================================================
5904 void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, int dynamic)
5906 VectorClear(diffusecolor);
5907 VectorClear(diffusenormal);
5909 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
5911 ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_refdef.scene.ambient;
5912 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
5915 VectorSet(ambientcolor, 1, 1, 1);
5922 for (i = 0;i < r_refdef.scene.numlights;i++)
5924 light = r_refdef.scene.lights[i];
5925 Matrix4x4_Transform(&light->matrix_worldtolight, p, v);
5926 f = 1 - VectorLength2(v);
5927 if (f > 0 && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
5928 VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);