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 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
1335 // increment stencil if frontface is infront of depthbuffer
1336 GL_CullFace(r_refdef.view.cullface_front);
1337 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1338 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1339 // decrement stencil if backface is infront of depthbuffer
1340 GL_CullFace(r_refdef.view.cullface_back);
1341 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1343 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
1345 // decrement stencil if backface is behind depthbuffer
1346 GL_CullFace(r_refdef.view.cullface_front);
1347 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1348 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1349 // increment stencil if frontface is behind depthbuffer
1350 GL_CullFace(r_refdef.view.cullface_back);
1351 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1353 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1358 int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias)
1360 // p1, p2, p3 are in the cubemap's local coordinate system
1361 // bias = border/(size - border)
1364 float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1365 dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2),
1366 dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3);
1367 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1369 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1370 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1371 | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1372 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1374 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1375 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1376 | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1378 dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1379 dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2),
1380 dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3);
1381 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1383 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1384 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1385 | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1386 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1388 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1389 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1390 | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1392 dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1393 dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2),
1394 dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3);
1395 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1397 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1398 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1399 | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1400 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1402 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1403 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1404 | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1409 int R_Shadow_CalcBBoxSideMask(const vec3_t mins, const vec3_t maxs, const matrix4x4_t *worldtolight, const matrix4x4_t *radiustolight, float bias)
1411 vec3_t center, radius, lightcenter, lightradius, pmin, pmax;
1412 float dp1, dn1, ap1, an1, dp2, dn2, ap2, an2;
1415 VectorSubtract(maxs, mins, radius);
1416 VectorScale(radius, 0.5f, radius);
1417 VectorAdd(mins, radius, center);
1418 Matrix4x4_Transform(worldtolight, center, lightcenter);
1419 Matrix4x4_Transform3x3(radiustolight, radius, lightradius);
1420 VectorSubtract(lightcenter, lightradius, pmin);
1421 VectorAdd(lightcenter, lightradius, pmax);
1423 dp1 = pmax[0] + pmax[1], dn1 = pmax[0] - pmin[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1424 dp2 = pmin[0] + pmin[1], dn2 = pmin[0] - pmax[1], ap2 = fabs(dp2), an2 = fabs(dn2);
1425 if(ap1 > bias*an1 && ap2 > bias*an2)
1427 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1428 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1429 if(an1 > bias*ap1 && an2 > bias*ap2)
1431 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1432 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1434 dp1 = pmax[1] + pmax[2], dn1 = pmax[1] - pmin[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1435 dp2 = pmin[1] + pmin[2], dn2 = pmin[1] - pmax[2], ap2 = fabs(dp2), an2 = fabs(dn2);
1436 if(ap1 > bias*an1 && ap2 > bias*an2)
1438 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1439 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1440 if(an1 > bias*ap1 && an2 > bias*ap2)
1442 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1443 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1445 dp1 = pmax[2] + pmax[0], dn1 = pmax[2] - pmin[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1446 dp2 = pmin[2] + pmin[0], dn2 = pmin[2] - pmax[0], ap2 = fabs(dp2), an2 = fabs(dn2);
1447 if(ap1 > bias*an1 && ap2 > bias*an2)
1449 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1450 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1451 if(an1 > bias*ap1 && an2 > bias*ap2)
1453 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1454 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1459 #define R_Shadow_CalcEntitySideMask(ent, worldtolight, radiustolight, bias) R_Shadow_CalcBBoxSideMask((ent)->mins, (ent)->maxs, worldtolight, radiustolight, bias)
1461 int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
1463 // p is in the cubemap's local coordinate system
1464 // bias = border/(size - border)
1465 float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn);
1466 float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn);
1467 float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn);
1469 if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
1470 if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
1471 if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
1472 if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
1473 if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
1474 if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
1478 int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
1482 int sides = 0x3F, masks[6] = { 3<<4, 3<<4, 3<<0, 3<<0, 3<<2, 3<<2 };
1483 float scale = (size - 2*border)/size, len;
1484 float bias = border / (float)(size - border), dp, dn, ap, an;
1485 // check if cone enclosing side would cross frustum plane
1486 scale = 2 / (scale*scale + 2);
1487 for (i = 0;i < 5;i++)
1489 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) > -0.03125)
1491 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[i].normal, n);
1492 len = scale*VectorLength2(n);
1493 if(n[0]*n[0] > len) sides &= n[0] < 0 ? ~(1<<0) : ~(2 << 0);
1494 if(n[1]*n[1] > len) sides &= n[1] < 0 ? ~(1<<2) : ~(2 << 2);
1495 if(n[2]*n[2] > len) sides &= n[2] < 0 ? ~(1<<4) : ~(2 << 4);
1497 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[4]) >= r_refdef.farclip - r_refdef.nearclip + 0.03125)
1499 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[4].normal, n);
1500 len = scale*VectorLength(n);
1501 if(n[0]*n[0] > len) sides &= n[0] >= 0 ? ~(1<<0) : ~(2 << 0);
1502 if(n[1]*n[1] > len) sides &= n[1] >= 0 ? ~(1<<2) : ~(2 << 2);
1503 if(n[2]*n[2] > len) sides &= n[2] >= 0 ? ~(1<<4) : ~(2 << 4);
1505 // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results
1506 // check if frustum corners/origin cross plane sides
1507 for (i = 0;i < 5;i++)
1509 Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p);
1510 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn),
1511 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1512 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1513 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn),
1514 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1515 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1516 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn),
1517 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1518 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1520 return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5];
1523 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)
1531 int mask, surfacemask = 0;
1532 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1534 bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
1535 tend = firsttriangle + numtris;
1536 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1538 // surface box entirely inside light box, no box cull
1539 if (projectdirection)
1541 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1543 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1544 TriangleNormal(v[0], v[1], v[2], normal);
1545 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1547 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1548 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1549 surfacemask |= mask;
1552 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;
1553 shadowsides[numshadowsides] = mask;
1554 shadowsideslist[numshadowsides++] = t;
1561 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1563 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1564 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]))
1566 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1567 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1568 surfacemask |= mask;
1571 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;
1572 shadowsides[numshadowsides] = mask;
1573 shadowsideslist[numshadowsides++] = t;
1581 // surface box not entirely inside light box, cull each triangle
1582 if (projectdirection)
1584 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1586 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1587 TriangleNormal(v[0], v[1], v[2], normal);
1588 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1589 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1591 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1592 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1593 surfacemask |= mask;
1596 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;
1597 shadowsides[numshadowsides] = mask;
1598 shadowsideslist[numshadowsides++] = t;
1605 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1607 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1608 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1609 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1611 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1612 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1613 surfacemask |= mask;
1616 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;
1617 shadowsides[numshadowsides] = mask;
1618 shadowsideslist[numshadowsides++] = t;
1627 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)
1629 int i, j, outtriangles = 0;
1630 int *outelement3i[6];
1631 if (!numverts || !numsidetris || !r_shadow_compilingrtlight)
1633 outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5];
1634 // make sure shadowelements is big enough for this mesh
1635 if (maxshadowtriangles < outtriangles)
1636 R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1);
1638 // compute the offset and size of the separate index lists for each cubemap side
1640 for (i = 0;i < 6;i++)
1642 outelement3i[i] = shadowelements + outtriangles * 3;
1643 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles;
1644 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i];
1645 outtriangles += sidetotals[i];
1648 // gather up the (sparse) triangles into separate index lists for each cubemap side
1649 for (i = 0;i < numsidetris;i++)
1651 const int *element = elements + sidetris[i] * 3;
1652 for (j = 0;j < 6;j++)
1654 if (sides[i] & (1 << j))
1656 outelement3i[j][0] = element[0];
1657 outelement3i[j][1] = element[1];
1658 outelement3i[j][2] = element[2];
1659 outelement3i[j] += 3;
1664 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, outtriangles, shadowelements);
1667 static void R_Shadow_MakeTextures_MakeCorona(void)
1671 unsigned char pixels[32][32][4];
1672 for (y = 0;y < 32;y++)
1674 dy = (y - 15.5f) * (1.0f / 16.0f);
1675 for (x = 0;x < 32;x++)
1677 dx = (x - 15.5f) * (1.0f / 16.0f);
1678 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1679 a = bound(0, a, 255);
1680 pixels[y][x][0] = a;
1681 pixels[y][x][1] = a;
1682 pixels[y][x][2] = a;
1683 pixels[y][x][3] = 255;
1686 r_shadow_lightcorona = R_SkinFrame_LoadInternalBGRA("lightcorona", TEXF_FORCELINEAR, &pixels[0][0][0], 32, 32);
1689 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1691 float dist = sqrt(x*x+y*y+z*z);
1692 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1693 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1694 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1697 static void R_Shadow_MakeTextures(void)
1700 float intensity, dist;
1702 R_Shadow_FreeShadowMaps();
1703 R_FreeTexturePool(&r_shadow_texturepool);
1704 r_shadow_texturepool = R_AllocTexturePool();
1705 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1706 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1707 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1708 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1709 for (x = 0;x <= ATTENTABLESIZE;x++)
1711 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1712 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1713 r_shadow_attentable[x] = bound(0, intensity, 1);
1715 // 1D gradient texture
1716 for (x = 0;x < ATTEN1DSIZE;x++)
1717 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1718 r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, NULL);
1719 // 2D circle texture
1720 for (y = 0;y < ATTEN2DSIZE;y++)
1721 for (x = 0;x < ATTEN2DSIZE;x++)
1722 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);
1723 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, NULL);
1724 // 3D sphere texture
1725 if (r_shadow_texture3d.integer && vid.support.ext_texture_3d)
1727 for (z = 0;z < ATTEN3DSIZE;z++)
1728 for (y = 0;y < ATTEN3DSIZE;y++)
1729 for (x = 0;x < ATTEN3DSIZE;x++)
1730 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));
1731 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, NULL);
1734 r_shadow_attenuation3dtexture = NULL;
1737 R_Shadow_MakeTextures_MakeCorona();
1739 // Editor light sprites
1740 r_editlights_sprcursor = R_SkinFrame_LoadInternal8bit("gfx/editlights/cursor", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1757 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1758 r_editlights_sprlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/light", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1775 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1776 r_editlights_sprnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/noshadow", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1793 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1794 r_editlights_sprcubemaplight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemaplight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1811 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1812 r_editlights_sprcubemapnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemapnoshadowlight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1829 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1830 r_editlights_sprselection = R_SkinFrame_LoadInternal8bit("gfx/editlights/selection", TEXF_ALPHA | TEXF_CLAMP, (unsigned char *)
1847 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1850 void R_Shadow_ValidateCvars(void)
1852 if (r_shadow_texture3d.integer && !vid.support.ext_texture_3d)
1853 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1854 if (gl_ext_separatestencil.integer && !vid.support.ati_separate_stencil)
1855 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
1856 if (gl_ext_stenciltwoside.integer && !vid.support.ext_stencil_two_side)
1857 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1860 void R_Shadow_RenderMode_Begin(void)
1866 R_Shadow_ValidateCvars();
1868 if (!r_shadow_attenuation2dtexture
1869 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1870 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1871 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1872 R_Shadow_MakeTextures();
1875 R_Mesh_ColorPointer(NULL, 0, 0);
1876 R_Mesh_ResetTextureState();
1877 GL_BlendFunc(GL_ONE, GL_ZERO);
1878 GL_DepthRange(0, 1);
1879 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1881 GL_DepthMask(false);
1882 GL_Color(0, 0, 0, 1);
1883 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1885 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1887 if (gl_ext_separatestencil.integer && vid.support.ati_separate_stencil)
1889 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
1890 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
1892 else if (gl_ext_stenciltwoside.integer && vid.support.ext_stencil_two_side)
1894 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
1895 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
1899 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
1900 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
1903 switch(vid.renderpath)
1905 case RENDERPATH_GL20:
1906 case RENDERPATH_CGGL:
1907 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1909 case RENDERPATH_GL13:
1910 case RENDERPATH_GL11:
1911 if (r_textureunits.integer >= 2 && vid.texunits >= 2 && r_shadow_texture3d.integer && r_shadow_attenuation3dtexture)
1912 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN;
1913 else if (r_textureunits.integer >= 3 && vid.texunits >= 3)
1914 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN;
1915 else if (r_textureunits.integer >= 2 && vid.texunits >= 2)
1916 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN;
1918 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1924 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
1925 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
1926 r_shadow_drawbuffer = drawbuffer;
1927 r_shadow_readbuffer = readbuffer;
1929 r_shadow_cullface_front = r_refdef.view.cullface_front;
1930 r_shadow_cullface_back = r_refdef.view.cullface_back;
1933 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
1935 rsurface.rtlight = rtlight;
1938 void R_Shadow_RenderMode_Reset(void)
1941 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE)
1943 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1945 if (vid.support.ext_framebuffer_object)
1947 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);CHECKGLERROR
1950 qglDrawBuffer(r_shadow_drawbuffer);CHECKGLERROR
1951 qglReadBuffer(r_shadow_readbuffer);CHECKGLERROR
1953 R_SetViewport(&r_refdef.view.viewport);
1954 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
1955 R_Mesh_ColorPointer(NULL, 0, 0);
1956 R_Mesh_ResetTextureState();
1957 GL_DepthRange(0, 1);
1959 GL_DepthMask(false);
1960 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1961 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1962 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
1963 qglStencilMask(~0);CHECKGLERROR
1964 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
1965 qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
1966 r_refdef.view.cullface_front = r_shadow_cullface_front;
1967 r_refdef.view.cullface_back = r_shadow_cullface_back;
1968 GL_CullFace(r_refdef.view.cullface_back);
1969 GL_Color(1, 1, 1, 1);
1970 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
1971 GL_BlendFunc(GL_ONE, GL_ZERO);
1972 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
1973 r_shadow_usingshadowmaprect = false;
1974 r_shadow_usingshadowmapcube = false;
1975 r_shadow_usingshadowmap2d = false;
1979 void R_Shadow_ClearStencil(void)
1982 GL_Clear(GL_STENCIL_BUFFER_BIT);
1983 r_refdef.stats.lights_clears++;
1986 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
1988 r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
1989 if (r_shadow_rendermode == mode)
1992 R_Shadow_RenderMode_Reset();
1993 GL_ColorMask(0, 0, 0, 0);
1994 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1995 R_SetupShader_DepthOrShadow();
1996 qglDepthFunc(GL_LESS);CHECKGLERROR
1997 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1998 r_shadow_rendermode = mode;
2003 case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
2004 GL_CullFace(GL_NONE);
2005 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
2006 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
2008 case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
2009 GL_CullFace(GL_NONE);
2010 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
2011 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
2013 case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
2014 GL_CullFace(GL_NONE);
2015 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
2016 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
2017 qglStencilMask(~0);CHECKGLERROR
2018 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
2019 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
2020 qglStencilMask(~0);CHECKGLERROR
2021 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
2023 case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
2024 GL_CullFace(GL_NONE);
2025 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
2026 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
2027 qglStencilMask(~0);CHECKGLERROR
2028 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
2029 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
2030 qglStencilMask(~0);CHECKGLERROR
2031 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
2036 static void R_Shadow_MakeVSDCT(void)
2038 // maps to a 2x3 texture rectangle with normalized coordinates
2043 // stores abs(dir.xy), offset.xy/2.5
2044 unsigned char data[4*6] =
2046 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
2047 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
2048 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
2049 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
2050 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
2051 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
2053 r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, NULL);
2056 void R_Shadow_RenderMode_ShadowMap(int side, int clear, int size)
2060 float nearclip, farclip, bias;
2061 r_viewport_t viewport;
2064 maxsize = r_shadow_shadowmapmaxsize;
2065 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
2067 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
2068 r_shadow_shadowmap_parameters[2] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
2069 r_shadow_shadowmap_parameters[3] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
2070 r_shadow_shadowmapside = side;
2071 r_shadow_shadowmapsize = size;
2072 if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
2074 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2075 r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2076 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
2077 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D) goto init_done;
2079 // complex unrolled cube approach (more flexible)
2080 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2081 R_Shadow_MakeVSDCT();
2082 if (!r_shadow_shadowmap2dtexture)
2085 int w = maxsize*2, h = vid.support.arb_texture_non_power_of_two ? maxsize*3 : maxsize*4;
2086 r_shadow_shadowmap2dtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "shadowmap", w, h, r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
2087 qglGenFramebuffersEXT(1, &r_shadow_fbo2d);CHECKGLERROR
2088 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbo2d);CHECKGLERROR
2089 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_shadowmap2dtexture), 0);CHECKGLERROR
2090 // render depth into the fbo, do not render color at all
2091 qglDrawBuffer(GL_NONE);CHECKGLERROR
2092 qglReadBuffer(GL_NONE);CHECKGLERROR
2093 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2094 if (status != GL_FRAMEBUFFER_COMPLETE_EXT && (r_shadow_shadowmapping.integer || r_shadow_deferred.integer))
2096 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2097 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2098 Cvar_SetValueQuick(&r_shadow_deferred, 0);
2103 if (r_shadow_shadowmap2dtexture) fbo = r_shadow_fbo2d;
2104 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
2105 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
2106 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
2108 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE)
2110 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2111 r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2112 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
2113 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE) goto init_done;
2115 // complex unrolled cube approach (more flexible)
2116 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2117 R_Shadow_MakeVSDCT();
2118 if (!r_shadow_shadowmaprectangletexture)
2121 r_shadow_shadowmaprectangletexture = R_LoadTextureShadowMapRectangle(r_shadow_texturepool, "shadowmap", maxsize*2, maxsize*3, r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
2122 qglGenFramebuffersEXT(1, &r_shadow_fborectangle);CHECKGLERROR
2123 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fborectangle);CHECKGLERROR
2124 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, R_GetTexture(r_shadow_shadowmaprectangletexture), 0);CHECKGLERROR
2125 // render depth into the fbo, do not render color at all
2126 qglDrawBuffer(GL_NONE);CHECKGLERROR
2127 qglReadBuffer(GL_NONE);CHECKGLERROR
2128 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2129 if (status != GL_FRAMEBUFFER_COMPLETE_EXT && (r_shadow_shadowmapping.integer || r_shadow_deferred.integer))
2131 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2132 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2133 Cvar_SetValueQuick(&r_shadow_deferred, 0);
2138 if(r_shadow_shadowmaprectangletexture) fbo = r_shadow_fborectangle;
2139 r_shadow_shadowmap_texturescale[0] = 1.0f;
2140 r_shadow_shadowmap_texturescale[1] = 1.0f;
2141 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE;
2143 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
2145 r_shadow_shadowmap_parameters[0] = 1.0f;
2146 r_shadow_shadowmap_parameters[1] = 1.0f;
2147 R_Viewport_InitCubeSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, nearclip, farclip, NULL);
2148 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE) goto init_done;
2150 // simple cube approach
2151 if (!r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod])
2154 r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod] = R_LoadTextureShadowMapCube(r_shadow_texturepool, "shadowmapcube", size, r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
2155 qglGenFramebuffersEXT(1, &r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR
2156 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR
2157 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
2158 // render depth into the fbo, do not render color at all
2159 qglDrawBuffer(GL_NONE);CHECKGLERROR
2160 qglReadBuffer(GL_NONE);CHECKGLERROR
2161 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2162 if (status != GL_FRAMEBUFFER_COMPLETE_EXT && (r_shadow_shadowmapping.integer || r_shadow_deferred.integer))
2164 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2165 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2166 Cvar_SetValueQuick(&r_shadow_deferred, 0);
2171 if (r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]) fbo = r_shadow_fbocubeside[r_shadow_shadowmaplod];
2172 r_shadow_shadowmap_texturescale[0] = 0.0f;
2173 r_shadow_shadowmap_texturescale[1] = 0.0f;
2174 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE;
2177 R_Shadow_RenderMode_Reset();
2180 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);CHECKGLERROR
2181 R_SetupShader_DepthOrShadow();
2185 R_SetupShader_ShowDepth();
2186 qglClearColor(1,1,1,1);CHECKGLERROR
2189 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
2196 R_SetViewport(&viewport);
2197 if(r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE)
2199 int flipped = (side & 1) ^ (side >> 2);
2200 r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
2201 r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
2202 GL_CullFace(r_refdef.view.cullface_back);
2203 if ((clear & ((2 << side) - 1)) == (1 << side)) // only clear if the side is the first in the mask
2205 // get tightest scissor rectangle that encloses all viewports in the clear mask
2206 int x1 = clear & 0x15 ? 0 : size;
2207 int x2 = clear & 0x2A ? 2 * size : size;
2208 int y1 = clear & 0x03 ? 0 : (clear & 0xC ? size : 2 * size);
2209 int y2 = clear & 0x30 ? 3 * size : (clear & 0xC ? 2 * size : size);
2210 GL_Scissor(x1, y1, x2 - x1, y2 - y1);
2211 GL_Clear(GL_DEPTH_BUFFER_BIT);
2213 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2215 else if(r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE)
2217 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
2218 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2220 GL_Clear(GL_DEPTH_BUFFER_BIT);
2225 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
2229 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2230 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2231 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2232 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2235 R_Shadow_RenderMode_Reset();
2236 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2239 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2243 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2244 // only draw light where this geometry was already rendered AND the
2245 // stencil is 128 (values other than this mean shadow)
2246 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
2248 r_shadow_rendermode = r_shadow_lightingrendermode;
2249 // do global setup needed for the chosen lighting mode
2250 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2252 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2257 if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
2258 r_shadow_usingshadowmap2d = true;
2259 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE)
2260 r_shadow_usingshadowmaprect = true;
2261 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
2262 r_shadow_usingshadowmapcube = true;
2264 R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
2268 static const unsigned short bboxelements[36] =
2278 static const float bboxpoints[8][3] =
2290 void R_Shadow_RenderMode_DrawDeferredLight(qboolean stenciltest, qboolean shadowmapping)
2293 float vertex3f[8*3];
2294 const matrix4x4_t *matrix = &rsurface.rtlight->matrix_lighttoworld;
2296 R_Shadow_RenderMode_Reset();
2297 r_shadow_rendermode = r_shadow_lightingrendermode;
2298 // do global setup needed for the chosen lighting mode
2300 R_EntityMatrix(&identitymatrix);
2301 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2304 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2305 // only draw light where this geometry was already rendered AND the
2306 // stencil is 128 (values other than this mean shadow)
2307 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
2309 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepasslightingfbo);CHECKGLERROR
2312 if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
2313 r_shadow_usingshadowmap2d = true;
2314 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE)
2315 r_shadow_usingshadowmaprect = true;
2316 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
2317 r_shadow_usingshadowmapcube = true;
2320 // render the lighting
2321 R_SetupShader_DeferredLight(rsurface.rtlight);
2322 for (i = 0;i < 8;i++)
2323 Matrix4x4_Transform(matrix, bboxpoints[i], vertex3f + i*3);
2325 R_Mesh_VertexPointer(vertex3f, 0, 0);
2326 R_Mesh_ColorPointer(NULL, 0, 0);
2327 GL_ColorMask(1,1,1,1);
2328 GL_DepthMask(false);
2329 GL_DepthRange(0, 1);
2330 GL_PolygonOffset(0, 0);
2332 qglDepthFunc(GL_GREATER);CHECKGLERROR
2333 GL_CullFace(r_refdef.view.cullface_back);
2334 R_Mesh_Draw(0, 8, 0, 12, NULL, bboxelements, 0, 0);
2338 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
2341 R_Shadow_RenderMode_Reset();
2342 GL_BlendFunc(GL_ONE, GL_ONE);
2343 GL_DepthRange(0, 1);
2344 GL_DepthTest(r_showshadowvolumes.integer < 2);
2345 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
2346 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2347 GL_CullFace(GL_NONE);
2348 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
2351 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
2354 R_Shadow_RenderMode_Reset();
2355 GL_BlendFunc(GL_ONE, GL_ONE);
2356 GL_DepthRange(0, 1);
2357 GL_DepthTest(r_showlighting.integer < 2);
2358 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2361 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2365 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2366 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
2368 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2371 void R_Shadow_RenderMode_End(void)
2374 R_Shadow_RenderMode_Reset();
2375 R_Shadow_RenderMode_ActiveLight(NULL);
2377 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2378 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2381 int bboxedges[12][2] =
2400 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2402 int i, ix1, iy1, ix2, iy2;
2403 float x1, y1, x2, y2;
2405 float vertex[20][3];
2414 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2415 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2416 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2417 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2419 if (!r_shadow_scissor.integer)
2422 // if view is inside the light box, just say yes it's visible
2423 if (BoxesOverlap(r_refdef.view.origin, r_refdef.view.origin, mins, maxs))
2426 x1 = y1 = x2 = y2 = 0;
2428 // transform all corners that are infront of the nearclip plane
2429 VectorNegate(r_refdef.view.frustum[4].normal, plane4f);
2430 plane4f[3] = r_refdef.view.frustum[4].dist;
2432 for (i = 0;i < 8;i++)
2434 Vector4Set(corner[i], (i & 1) ? maxs[0] : mins[0], (i & 2) ? maxs[1] : mins[1], (i & 4) ? maxs[2] : mins[2], 1);
2435 dist[i] = DotProduct4(corner[i], plane4f);
2436 sign[i] = dist[i] > 0;
2439 VectorCopy(corner[i], vertex[numvertices]);
2443 // if some points are behind the nearclip, add clipped edge points to make
2444 // sure that the scissor boundary is complete
2445 if (numvertices > 0 && numvertices < 8)
2447 // add clipped edge points
2448 for (i = 0;i < 12;i++)
2450 j = bboxedges[i][0];
2451 k = bboxedges[i][1];
2452 if (sign[j] != sign[k])
2454 f = dist[j] / (dist[j] - dist[k]);
2455 VectorLerp(corner[j], f, corner[k], vertex[numvertices]);
2461 // if we have no points to check, the light is behind the view plane
2465 // if we have some points to transform, check what screen area is covered
2466 x1 = y1 = x2 = y2 = 0;
2468 //Con_Printf("%i vertices to transform...\n", numvertices);
2469 for (i = 0;i < numvertices;i++)
2471 VectorCopy(vertex[i], v);
2472 R_Viewport_TransformToScreen(&r_refdef.view.viewport, v, v2);
2473 //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]);
2476 if (x1 > v2[0]) x1 = v2[0];
2477 if (x2 < v2[0]) x2 = v2[0];
2478 if (y1 > v2[1]) y1 = v2[1];
2479 if (y2 < v2[1]) y2 = v2[1];
2488 // now convert the scissor rectangle to integer screen coordinates
2489 ix1 = (int)(x1 - 1.0f);
2490 iy1 = vid.height - (int)(y2 - 1.0f);
2491 ix2 = (int)(x2 + 1.0f);
2492 iy2 = vid.height - (int)(y1 + 1.0f);
2493 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
2495 // clamp it to the screen
2496 if (ix1 < r_refdef.view.viewport.x) ix1 = r_refdef.view.viewport.x;
2497 if (iy1 < r_refdef.view.viewport.y) iy1 = r_refdef.view.viewport.y;
2498 if (ix2 > r_refdef.view.viewport.x + r_refdef.view.viewport.width) ix2 = r_refdef.view.viewport.x + r_refdef.view.viewport.width;
2499 if (iy2 > r_refdef.view.viewport.y + r_refdef.view.viewport.height) iy2 = r_refdef.view.viewport.y + r_refdef.view.viewport.height;
2501 // if it is inside out, it's not visible
2502 if (ix2 <= ix1 || iy2 <= iy1)
2505 // the light area is visible, set up the scissor rectangle
2506 r_shadow_lightscissor[0] = ix1;
2507 r_shadow_lightscissor[1] = iy1;
2508 r_shadow_lightscissor[2] = ix2 - ix1;
2509 r_shadow_lightscissor[3] = iy2 - iy1;
2511 r_refdef.stats.lights_scissored++;
2515 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, int numtriangles, const int *element3i, const float *diffusecolor, const float *ambientcolor)
2517 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
2518 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
2519 float *color4f = rsurface.array_color4f + 4 * firstvertex;
2520 float dist, dot, distintensity, shadeintensity, v[3], n[3];
2521 switch (r_shadow_rendermode)
2523 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2524 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2525 if (VectorLength2(diffusecolor) > 0)
2527 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2529 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2530 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2531 if ((dot = DotProduct(n, v)) < 0)
2533 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2534 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
2537 VectorCopy(ambientcolor, color4f);
2538 if (r_refdef.fogenabled)
2541 f = RSurf_FogVertex(vertex3f);
2542 VectorScale(color4f, f, color4f);
2549 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2551 VectorCopy(ambientcolor, color4f);
2552 if (r_refdef.fogenabled)
2555 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2556 f = RSurf_FogVertex(vertex3f);
2557 VectorScale(color4f, f, color4f);
2563 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2564 if (VectorLength2(diffusecolor) > 0)
2566 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2568 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2569 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2571 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2572 if ((dot = DotProduct(n, v)) < 0)
2574 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2575 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2576 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2577 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2581 color4f[0] = ambientcolor[0] * distintensity;
2582 color4f[1] = ambientcolor[1] * distintensity;
2583 color4f[2] = ambientcolor[2] * distintensity;
2585 if (r_refdef.fogenabled)
2588 f = RSurf_FogVertex(vertex3f);
2589 VectorScale(color4f, f, color4f);
2593 VectorClear(color4f);
2599 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2601 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2602 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2604 color4f[0] = ambientcolor[0] * distintensity;
2605 color4f[1] = ambientcolor[1] * distintensity;
2606 color4f[2] = ambientcolor[2] * distintensity;
2607 if (r_refdef.fogenabled)
2610 f = RSurf_FogVertex(vertex3f);
2611 VectorScale(color4f, f, color4f);
2615 VectorClear(color4f);
2620 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2621 if (VectorLength2(diffusecolor) > 0)
2623 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2625 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2626 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2628 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2629 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2630 if ((dot = DotProduct(n, v)) < 0)
2632 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2633 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2634 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2635 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2639 color4f[0] = ambientcolor[0] * distintensity;
2640 color4f[1] = ambientcolor[1] * distintensity;
2641 color4f[2] = ambientcolor[2] * distintensity;
2643 if (r_refdef.fogenabled)
2646 f = RSurf_FogVertex(vertex3f);
2647 VectorScale(color4f, f, color4f);
2651 VectorClear(color4f);
2657 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2659 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2660 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2662 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2663 color4f[0] = ambientcolor[0] * distintensity;
2664 color4f[1] = ambientcolor[1] * distintensity;
2665 color4f[2] = ambientcolor[2] * distintensity;
2666 if (r_refdef.fogenabled)
2669 f = RSurf_FogVertex(vertex3f);
2670 VectorScale(color4f, f, color4f);
2674 VectorClear(color4f);
2684 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)
2686 // used to display how many times a surface is lit for level design purposes
2687 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2690 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)
2692 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2693 R_SetupShader_Surface(lightcolor, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT);
2694 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2696 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2698 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2699 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2701 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
2705 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
2712 int newnumtriangles;
2716 int maxtriangles = 4096;
2717 static int newelements[4096*3];
2718 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, numtriangles, element3i, diffusecolor2, ambientcolor2);
2719 for (renders = 0;renders < 64;renders++)
2724 newnumtriangles = 0;
2726 // due to low fillrate on the cards this vertex lighting path is
2727 // designed for, we manually cull all triangles that do not
2728 // contain a lit vertex
2729 // this builds batches of triangles from multiple surfaces and
2730 // renders them at once
2731 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
2733 if (VectorLength2(rsurface.array_color4f + e[0] * 4) + VectorLength2(rsurface.array_color4f + e[1] * 4) + VectorLength2(rsurface.array_color4f + e[2] * 4) >= 0.01)
2735 if (newnumtriangles)
2737 newfirstvertex = min(newfirstvertex, e[0]);
2738 newlastvertex = max(newlastvertex, e[0]);
2742 newfirstvertex = e[0];
2743 newlastvertex = e[0];
2745 newfirstvertex = min(newfirstvertex, e[1]);
2746 newlastvertex = max(newlastvertex, e[1]);
2747 newfirstvertex = min(newfirstvertex, e[2]);
2748 newlastvertex = max(newlastvertex, e[2]);
2754 if (newnumtriangles >= maxtriangles)
2756 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
2757 newnumtriangles = 0;
2763 if (newnumtriangles >= 1)
2765 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
2768 // if we couldn't find any lit triangles, exit early
2771 // now reduce the intensity for the next overbright pass
2772 // we have to clamp to 0 here incase the drivers have improper
2773 // handling of negative colors
2774 // (some old drivers even have improper handling of >1 color)
2776 for (i = 0, c = rsurface.array_color4f + 4 * firstvertex;i < numvertices;i++, c += 4)
2778 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
2780 c[0] = max(0, c[0] - 1);
2781 c[1] = max(0, c[1] - 1);
2782 c[2] = max(0, c[2] - 1);
2794 static void R_Shadow_RenderLighting_Light_Vertex(int firstvertex, int numvertices, int numtriangles, const int *element3i, const vec3_t lightcolor, float ambientscale, float diffusescale)
2796 // OpenGL 1.1 path (anything)
2797 float ambientcolorbase[3], diffusecolorbase[3];
2798 float ambientcolorpants[3], diffusecolorpants[3];
2799 float ambientcolorshirt[3], diffusecolorshirt[3];
2800 const float *surfacecolor = rsurface.texture->dlightcolor;
2801 const float *surfacepants = rsurface.colormap_pantscolor;
2802 const float *surfaceshirt = rsurface.colormap_shirtcolor;
2803 rtexture_t *basetexture = rsurface.texture->basetexture;
2804 rtexture_t *pantstexture = rsurface.texture->pantstexture;
2805 rtexture_t *shirttexture = rsurface.texture->shirttexture;
2806 qboolean dopants = pantstexture && VectorLength2(surfacepants) >= (1.0f / 1048576.0f);
2807 qboolean doshirt = shirttexture && VectorLength2(surfaceshirt) >= (1.0f / 1048576.0f);
2808 ambientscale *= 2 * r_refdef.view.colorscale;
2809 diffusescale *= 2 * r_refdef.view.colorscale;
2810 ambientcolorbase[0] = lightcolor[0] * ambientscale * surfacecolor[0];ambientcolorbase[1] = lightcolor[1] * ambientscale * surfacecolor[1];ambientcolorbase[2] = lightcolor[2] * ambientscale * surfacecolor[2];
2811 diffusecolorbase[0] = lightcolor[0] * diffusescale * surfacecolor[0];diffusecolorbase[1] = lightcolor[1] * diffusescale * surfacecolor[1];diffusecolorbase[2] = lightcolor[2] * diffusescale * surfacecolor[2];
2812 ambientcolorpants[0] = ambientcolorbase[0] * surfacepants[0];ambientcolorpants[1] = ambientcolorbase[1] * surfacepants[1];ambientcolorpants[2] = ambientcolorbase[2] * surfacepants[2];
2813 diffusecolorpants[0] = diffusecolorbase[0] * surfacepants[0];diffusecolorpants[1] = diffusecolorbase[1] * surfacepants[1];diffusecolorpants[2] = diffusecolorbase[2] * surfacepants[2];
2814 ambientcolorshirt[0] = ambientcolorbase[0] * surfaceshirt[0];ambientcolorshirt[1] = ambientcolorbase[1] * surfaceshirt[1];ambientcolorshirt[2] = ambientcolorbase[2] * surfaceshirt[2];
2815 diffusecolorshirt[0] = diffusecolorbase[0] * surfaceshirt[0];diffusecolorshirt[1] = diffusecolorbase[1] * surfaceshirt[1];diffusecolorshirt[2] = diffusecolorbase[2] * surfaceshirt[2];
2816 R_Mesh_TexBind(0, basetexture);
2817 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
2818 R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
2819 R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
2820 switch(r_shadow_rendermode)
2822 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2823 R_Mesh_TexBind(1, r_shadow_attenuation3dtexture);
2824 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
2825 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
2826 R_Mesh_TexCoordPointer(1, 3, rsurface.vertex3f, rsurface.vertex3f_bufferobject, rsurface.vertex3f_bufferoffset);
2828 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2829 R_Mesh_TexBind(2, r_shadow_attenuation2dtexture);
2830 R_Mesh_TexMatrix(2, &rsurface.entitytoattenuationz);
2831 R_Mesh_TexCombine(2, GL_MODULATE, GL_MODULATE, 1, 1);
2832 R_Mesh_TexCoordPointer(2, 3, rsurface.vertex3f, rsurface.vertex3f_bufferobject, rsurface.vertex3f_bufferoffset);
2834 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2835 R_Mesh_TexBind(1, r_shadow_attenuation2dtexture);
2836 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
2837 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
2838 R_Mesh_TexCoordPointer(1, 3, rsurface.vertex3f, rsurface.vertex3f_bufferobject, rsurface.vertex3f_bufferoffset);
2840 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2845 //R_Mesh_TexBind(0, basetexture);
2846 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorbase, ambientcolorbase);
2849 R_Mesh_TexBind(0, pantstexture);
2850 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorpants, ambientcolorpants);
2854 R_Mesh_TexBind(0, shirttexture);
2855 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorshirt, ambientcolorshirt);
2859 extern cvar_t gl_lightmaps;
2860 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)
2862 float ambientscale, diffusescale, specularscale;
2864 float lightcolor[3];
2865 VectorCopy(rsurface.rtlight->currentcolor, lightcolor);
2866 ambientscale = rsurface.rtlight->ambientscale;
2867 diffusescale = rsurface.rtlight->diffusescale;
2868 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
2869 if (!r_shadow_usenormalmap.integer)
2871 ambientscale += 1.0f * diffusescale;
2875 if ((ambientscale + diffusescale) * VectorLength2(lightcolor) + specularscale * VectorLength2(lightcolor) < (1.0f / 1048576.0f))
2877 negated = (lightcolor[0] + lightcolor[1] + lightcolor[2] < 0) && vid.support.ext_blend_subtract;
2880 VectorNegate(lightcolor, lightcolor);
2881 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
2883 RSurf_SetupDepthAndCulling();
2884 switch (r_shadow_rendermode)
2886 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2887 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2888 R_Shadow_RenderLighting_VisibleLighting(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2890 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2891 R_Shadow_RenderLighting_Light_GLSL(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolor, ambientscale, diffusescale, specularscale);
2893 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2894 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2895 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2896 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2897 R_Shadow_RenderLighting_Light_Vertex(firstvertex, numvertices, numtriangles, element3i + firsttriangle * 3, lightcolor, ambientscale, diffusescale);
2900 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2904 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
2907 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)
2909 matrix4x4_t tempmatrix = *matrix;
2910 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
2912 // if this light has been compiled before, free the associated data
2913 R_RTLight_Uncompile(rtlight);
2915 // clear it completely to avoid any lingering data
2916 memset(rtlight, 0, sizeof(*rtlight));
2918 // copy the properties
2919 rtlight->matrix_lighttoworld = tempmatrix;
2920 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
2921 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
2922 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
2923 VectorCopy(color, rtlight->color);
2924 rtlight->cubemapname[0] = 0;
2925 if (cubemapname && cubemapname[0])
2926 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
2927 rtlight->shadow = shadow;
2928 rtlight->corona = corona;
2929 rtlight->style = style;
2930 rtlight->isstatic = isstatic;
2931 rtlight->coronasizescale = coronasizescale;
2932 rtlight->ambientscale = ambientscale;
2933 rtlight->diffusescale = diffusescale;
2934 rtlight->specularscale = specularscale;
2935 rtlight->flags = flags;
2937 // compute derived data
2938 //rtlight->cullradius = rtlight->radius;
2939 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2940 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2941 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2942 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2943 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2944 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2945 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2948 // compiles rtlight geometry
2949 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2950 void R_RTLight_Compile(rtlight_t *rtlight)
2953 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
2954 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
2955 entity_render_t *ent = r_refdef.scene.worldentity;
2956 dp_model_t *model = r_refdef.scene.worldmodel;
2957 unsigned char *data;
2960 // compile the light
2961 rtlight->compiled = true;
2962 rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
2963 rtlight->static_numleafs = 0;
2964 rtlight->static_numleafpvsbytes = 0;
2965 rtlight->static_leaflist = NULL;
2966 rtlight->static_leafpvs = NULL;
2967 rtlight->static_numsurfaces = 0;
2968 rtlight->static_surfacelist = NULL;
2969 rtlight->static_shadowmap_receivers = 0x3F;
2970 rtlight->static_shadowmap_casters = 0x3F;
2971 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2972 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2973 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2974 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2975 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2976 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2978 if (model && model->GetLightInfo)
2980 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
2981 r_shadow_compilingrtlight = rtlight;
2982 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);
2983 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2984 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
2985 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
2986 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
2987 rtlight->static_numsurfaces = numsurfaces;
2988 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
2989 rtlight->static_numleafs = numleafs;
2990 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
2991 rtlight->static_numleafpvsbytes = numleafpvsbytes;
2992 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
2993 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
2994 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
2995 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
2996 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
2997 if (rtlight->static_numsurfaces)
2998 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
2999 if (rtlight->static_numleafs)
3000 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3001 if (rtlight->static_numleafpvsbytes)
3002 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3003 if (rtlight->static_numshadowtrispvsbytes)
3004 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3005 if (rtlight->static_numlighttrispvsbytes)
3006 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3007 switch (rtlight->shadowmode)
3009 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
3010 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
3011 case R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE:
3012 if (model->CompileShadowMap && rtlight->shadow)
3013 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3016 if (model->CompileShadowVolume && rtlight->shadow)
3017 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3020 // now we're done compiling the rtlight
3021 r_shadow_compilingrtlight = NULL;
3025 // use smallest available cullradius - box radius or light radius
3026 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3027 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3029 shadowzpasstris = 0;
3030 if (rtlight->static_meshchain_shadow_zpass)
3031 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
3032 shadowzpasstris += mesh->numtriangles;
3034 shadowzfailtris = 0;
3035 if (rtlight->static_meshchain_shadow_zfail)
3036 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
3037 shadowzfailtris += mesh->numtriangles;
3040 if (rtlight->static_numlighttrispvsbytes)
3041 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3042 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3046 if (rtlight->static_numlighttrispvsbytes)
3047 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3048 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3051 if (developer_extra.integer)
3052 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);
3055 void R_RTLight_Uncompile(rtlight_t *rtlight)
3057 if (rtlight->compiled)
3059 if (rtlight->static_meshchain_shadow_zpass)
3060 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
3061 rtlight->static_meshchain_shadow_zpass = NULL;
3062 if (rtlight->static_meshchain_shadow_zfail)
3063 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
3064 rtlight->static_meshchain_shadow_zfail = NULL;
3065 if (rtlight->static_meshchain_shadow_shadowmap)
3066 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
3067 rtlight->static_meshchain_shadow_shadowmap = NULL;
3068 // these allocations are grouped
3069 if (rtlight->static_surfacelist)
3070 Mem_Free(rtlight->static_surfacelist);
3071 rtlight->static_numleafs = 0;
3072 rtlight->static_numleafpvsbytes = 0;
3073 rtlight->static_leaflist = NULL;
3074 rtlight->static_leafpvs = NULL;
3075 rtlight->static_numsurfaces = 0;
3076 rtlight->static_surfacelist = NULL;
3077 rtlight->static_numshadowtrispvsbytes = 0;
3078 rtlight->static_shadowtrispvs = NULL;
3079 rtlight->static_numlighttrispvsbytes = 0;
3080 rtlight->static_lighttrispvs = NULL;
3081 rtlight->compiled = false;
3085 void R_Shadow_UncompileWorldLights(void)
3089 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3090 for (lightindex = 0;lightindex < range;lightindex++)
3092 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3095 R_RTLight_Uncompile(&light->rtlight);
3099 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3103 // reset the count of frustum planes
3104 // see rtlight->cached_frustumplanes definition for how much this array
3106 rtlight->cached_numfrustumplanes = 0;
3108 // haven't implemented a culling path for ortho rendering
3109 if (!r_refdef.view.useperspective)
3111 // check if the light is on screen and copy the 4 planes if it is
3112 for (i = 0;i < 4;i++)
3113 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3116 for (i = 0;i < 4;i++)
3117 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3122 // generate a deformed frustum that includes the light origin, this is
3123 // used to cull shadow casting surfaces that can not possibly cast a
3124 // shadow onto the visible light-receiving surfaces, which can be a
3127 // if the light origin is onscreen the result will be 4 planes exactly
3128 // if the light origin is offscreen on only one axis the result will
3129 // be exactly 5 planes (split-side case)
3130 // if the light origin is offscreen on two axes the result will be
3131 // exactly 4 planes (stretched corner case)
3132 for (i = 0;i < 4;i++)
3134 // quickly reject standard frustum planes that put the light
3135 // origin outside the frustum
3136 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3139 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3141 // if all the standard frustum planes were accepted, the light is onscreen
3142 // otherwise we need to generate some more planes below...
3143 if (rtlight->cached_numfrustumplanes < 4)
3145 // at least one of the stock frustum planes failed, so we need to
3146 // create one or two custom planes to enclose the light origin
3147 for (i = 0;i < 4;i++)
3149 // create a plane using the view origin and light origin, and a
3150 // single point from the frustum corner set
3151 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3152 VectorNormalize(plane.normal);
3153 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3154 // see if this plane is backwards and flip it if so
3155 for (j = 0;j < 4;j++)
3156 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3160 VectorNegate(plane.normal, plane.normal);
3162 // flipped plane, test again to see if it is now valid
3163 for (j = 0;j < 4;j++)
3164 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3166 // if the plane is still not valid, then it is dividing the
3167 // frustum and has to be rejected
3171 // we have created a valid plane, compute extra info
3172 PlaneClassify(&plane);
3174 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3176 // if we've found 5 frustum planes then we have constructed a
3177 // proper split-side case and do not need to keep searching for
3178 // planes to enclose the light origin
3179 if (rtlight->cached_numfrustumplanes == 5)
3187 for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
3189 plane = rtlight->cached_frustumplanes[i];
3190 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));
3195 // now add the light-space box planes if the light box is rotated, as any
3196 // caster outside the oriented light box is irrelevant (even if it passed
3197 // the worldspace light box, which is axial)
3198 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3200 for (i = 0;i < 6;i++)
3204 v[i >> 1] = (i & 1) ? -1 : 1;
3205 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3206 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3207 plane.dist = VectorNormalizeLength(plane.normal);
3208 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3209 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3215 // add the world-space reduced box planes
3216 for (i = 0;i < 6;i++)
3218 VectorClear(plane.normal);
3219 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3220 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
3221 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3230 // reduce all plane distances to tightly fit the rtlight cull box, which
3232 VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3233 VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3234 VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3235 VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3236 VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3237 VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3238 VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3239 VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3240 oldnum = rtlight->cached_numfrustumplanes;
3241 rtlight->cached_numfrustumplanes = 0;
3242 for (j = 0;j < oldnum;j++)
3244 // find the nearest point on the box to this plane
3245 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
3246 for (i = 1;i < 8;i++)
3248 dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
3249 if (bestdist > dist)
3252 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);
3253 // if the nearest point is near or behind the plane, we want this
3254 // plane, otherwise the plane is useless as it won't cull anything
3255 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
3257 PlaneClassify(&rtlight->cached_frustumplanes[j]);
3258 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
3265 void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
3269 RSurf_ActiveWorldEntity();
3271 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3274 GL_CullFace(GL_NONE);
3275 mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3276 for (;mesh;mesh = mesh->next)
3278 if (!mesh->sidetotals[r_shadow_shadowmapside])
3280 r_refdef.stats.lights_shadowtriangles += mesh->sidetotals[r_shadow_shadowmapside];
3281 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
3282 R_Mesh_Draw(0, mesh->numverts, mesh->sideoffsets[r_shadow_shadowmapside], mesh->sidetotals[r_shadow_shadowmapside], mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3286 else if (r_refdef.scene.worldentity->model)
3287 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);
3289 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3292 void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3294 qboolean zpass = false;
3297 int surfacelistindex;
3298 msurface_t *surface;
3300 RSurf_ActiveWorldEntity();
3302 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3305 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
3307 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
3308 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
3310 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
3311 for (;mesh;mesh = mesh->next)
3313 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
3314 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
3315 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
3317 // increment stencil if frontface is infront of depthbuffer
3318 GL_CullFace(r_refdef.view.cullface_back);
3319 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
3320 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3321 // decrement stencil if backface is infront of depthbuffer
3322 GL_CullFace(r_refdef.view.cullface_front);
3323 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
3325 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
3327 // decrement stencil if backface is behind depthbuffer
3328 GL_CullFace(r_refdef.view.cullface_front);
3329 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
3330 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3331 // increment stencil if frontface is behind depthbuffer
3332 GL_CullFace(r_refdef.view.cullface_back);
3333 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
3335 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3339 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh)
3341 // use the shadow trispvs calculated earlier by GetLightInfo to cull world triangles on this dynamic light
3342 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
3343 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
3345 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
3346 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
3347 if (CHECKPVSBIT(trispvs, t))
3348 shadowmarklist[numshadowmark++] = t;
3350 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);
3352 else if (numsurfaces)
3353 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);
3355 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3358 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3360 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3361 vec_t relativeshadowradius;
3362 RSurf_ActiveModelEntity(ent, false, false, false);
3363 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3364 // we need to re-init the shader for each entity because the matrix changed
3365 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3366 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3367 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3368 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3369 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3370 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3371 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3372 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D)
3374 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
3377 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3378 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3381 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3383 // set up properties for rendering light onto this entity
3384 RSurf_ActiveModelEntity(ent, true, true, false);
3385 GL_AlphaTest(false);
3386 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3387 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3388 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3389 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3392 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
3394 if (!r_refdef.scene.worldmodel->DrawLight)
3397 // set up properties for rendering light onto this entity
3398 RSurf_ActiveWorldEntity();
3399 GL_AlphaTest(false);
3400 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3401 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3402 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3403 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3405 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
3407 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3410 void R_Shadow_DrawEntityLight(entity_render_t *ent)
3412 dp_model_t *model = ent->model;
3413 if (!model->DrawLight)
3416 R_Shadow_SetupEntityLight(ent);
3418 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3420 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3423 void R_Shadow_PrepareLight(rtlight_t *rtlight)
3427 int numleafs, numsurfaces;
3428 int *leaflist, *surfacelist;
3429 unsigned char *leafpvs, *shadowtrispvs, *lighttrispvs, *surfacesides;
3430 int numlightentities;
3431 int numlightentities_noselfshadow;
3432 int numshadowentities;
3433 int numshadowentities_noselfshadow;
3434 static entity_render_t *lightentities[MAX_EDICTS];
3435 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3436 static entity_render_t *shadowentities[MAX_EDICTS];
3437 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3439 rtlight->draw = false;
3441 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3442 // skip lights that are basically invisible (color 0 0 0)
3443 if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
3446 // loading is done before visibility checks because loading should happen
3447 // all at once at the start of a level, not when it stalls gameplay.
3448 // (especially important to benchmarks)
3450 if (rtlight->isstatic && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
3452 if (rtlight->compiled)
3453 R_RTLight_Uncompile(rtlight);
3454 R_RTLight_Compile(rtlight);
3458 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
3460 // look up the light style value at this time
3461 f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3462 VectorScale(rtlight->color, f, rtlight->currentcolor);
3464 if (rtlight->selected)
3466 f = 2 + sin(realtime * M_PI * 4.0);
3467 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3471 // if lightstyle is currently off, don't draw the light
3472 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3475 // if the light box is offscreen, skip it
3476 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3479 VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
3480 VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
3482 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3484 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3486 // compiled light, world available and can receive realtime lighting
3487 // retrieve leaf information
3488 numleafs = rtlight->static_numleafs;
3489 leaflist = rtlight->static_leaflist;
3490 leafpvs = rtlight->static_leafpvs;
3491 numsurfaces = rtlight->static_numsurfaces;
3492 surfacelist = rtlight->static_surfacelist;
3493 surfacesides = NULL;
3494 shadowtrispvs = rtlight->static_shadowtrispvs;
3495 lighttrispvs = rtlight->static_lighttrispvs;
3497 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3499 // dynamic light, world available and can receive realtime lighting
3500 // calculate lit surfaces and leafs
3501 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);
3502 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3503 leaflist = r_shadow_buffer_leaflist;
3504 leafpvs = r_shadow_buffer_leafpvs;
3505 surfacelist = r_shadow_buffer_surfacelist;
3506 surfacesides = r_shadow_buffer_surfacesides;
3507 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3508 lighttrispvs = r_shadow_buffer_lighttrispvs;
3509 // if the reduced leaf bounds are offscreen, skip it
3510 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3521 surfacesides = NULL;
3522 shadowtrispvs = NULL;
3523 lighttrispvs = NULL;
3525 // check if light is illuminating any visible leafs
3528 for (i = 0;i < numleafs;i++)
3529 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3535 // make a list of lit entities and shadow casting entities
3536 numlightentities = 0;
3537 numlightentities_noselfshadow = 0;
3538 numshadowentities = 0;
3539 numshadowentities_noselfshadow = 0;
3541 // add dynamic entities that are lit by the light
3542 for (i = 0;i < r_refdef.scene.numentities;i++)
3545 entity_render_t *ent = r_refdef.scene.entities[i];
3547 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3549 // skip the object entirely if it is not within the valid
3550 // shadow-casting region (which includes the lit region)
3551 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
3553 if (!(model = ent->model))
3555 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
3557 // this entity wants to receive light, is visible, and is
3558 // inside the light box
3559 // TODO: check if the surfaces in the model can receive light
3560 // so now check if it's in a leaf seen by the light
3561 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))
3563 if (ent->flags & RENDER_NOSELFSHADOW)
3564 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
3566 lightentities[numlightentities++] = ent;
3567 // since it is lit, it probably also casts a shadow...
3568 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3569 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3570 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3572 // note: exterior models without the RENDER_NOSELFSHADOW
3573 // flag still create a RENDER_NOSELFSHADOW shadow but
3574 // are lit normally, this means that they are
3575 // self-shadowing but do not shadow other
3576 // RENDER_NOSELFSHADOW entities such as the gun
3577 // (very weird, but keeps the player shadow off the gun)
3578 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3579 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3581 shadowentities[numshadowentities++] = ent;
3584 else if (ent->flags & RENDER_SHADOW)
3586 // this entity is not receiving light, but may still need to
3588 // TODO: check if the surfaces in the model can cast shadow
3589 // now check if it is in a leaf seen by the light
3590 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))
3592 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3593 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3594 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3596 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3597 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3599 shadowentities[numshadowentities++] = ent;
3604 // return if there's nothing at all to light
3605 if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
3608 // count this light in the r_speeds
3609 r_refdef.stats.lights++;
3611 // flag it as worth drawing later
3612 rtlight->draw = true;
3614 // cache all the animated entities that cast a shadow but are not visible
3615 for (i = 0;i < numshadowentities;i++)
3616 if (!shadowentities[i]->animcache_vertex3f)
3617 R_AnimCache_GetEntity(shadowentities[i], false, false);
3618 for (i = 0;i < numshadowentities_noselfshadow;i++)
3619 if (!shadowentities_noselfshadow[i]->animcache_vertex3f)
3620 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
3622 // allocate some temporary memory for rendering this light later in the frame
3623 // reusable buffers need to be copied, static data can be used as-is
3624 rtlight->cached_numlightentities = numlightentities;
3625 rtlight->cached_numlightentities_noselfshadow = numlightentities_noselfshadow;
3626 rtlight->cached_numshadowentities = numshadowentities;
3627 rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
3628 rtlight->cached_numsurfaces = numsurfaces;
3629 rtlight->cached_lightentities = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
3630 rtlight->cached_lightentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
3631 rtlight->cached_shadowentities = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
3632 rtlight->cached_shadowentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
3633 if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
3635 int numshadowtrispvsbytes = (((r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles) + 7) >> 3);
3636 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
3637 rtlight->cached_shadowtrispvs = (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
3638 rtlight->cached_lighttrispvs = (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
3639 rtlight->cached_surfacelist = (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
3643 // compiled light data
3644 rtlight->cached_shadowtrispvs = shadowtrispvs;
3645 rtlight->cached_lighttrispvs = lighttrispvs;
3646 rtlight->cached_surfacelist = surfacelist;
3650 void R_Shadow_DrawLight(rtlight_t *rtlight)
3654 unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
3655 int numlightentities;
3656 int numlightentities_noselfshadow;
3657 int numshadowentities;
3658 int numshadowentities_noselfshadow;
3659 entity_render_t **lightentities;
3660 entity_render_t **lightentities_noselfshadow;
3661 entity_render_t **shadowentities;
3662 entity_render_t **shadowentities_noselfshadow;
3664 static unsigned char entitysides[MAX_EDICTS];
3665 static unsigned char entitysides_noselfshadow[MAX_EDICTS];
3666 vec3_t nearestpoint;
3668 qboolean castshadows;
3671 // check if we cached this light this frame (meaning it is worth drawing)
3675 // if R_FrameData_Store ran out of space we skip anything dependent on it
3676 if (r_framedata_failed)
3679 numlightentities = rtlight->cached_numlightentities;
3680 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
3681 numshadowentities = rtlight->cached_numshadowentities;
3682 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
3683 numsurfaces = rtlight->cached_numsurfaces;
3684 lightentities = rtlight->cached_lightentities;
3685 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
3686 shadowentities = rtlight->cached_shadowentities;
3687 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
3688 shadowtrispvs = rtlight->cached_shadowtrispvs;
3689 lighttrispvs = rtlight->cached_lighttrispvs;
3690 surfacelist = rtlight->cached_surfacelist;
3692 // set up a scissor rectangle for this light
3693 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3696 // don't let sound skip if going slow
3697 if (r_refdef.scene.extraupdate)
3700 // make this the active rtlight for rendering purposes
3701 R_Shadow_RenderMode_ActiveLight(rtlight);
3703 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
3705 // optionally draw visible shape of the shadow volumes
3706 // for performance analysis by level designers
3707 R_Shadow_RenderMode_VisibleShadowVolumes();
3709 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
3710 for (i = 0;i < numshadowentities;i++)
3711 R_Shadow_DrawEntityShadow(shadowentities[i]);
3712 for (i = 0;i < numshadowentities_noselfshadow;i++)
3713 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3714 R_Shadow_RenderMode_VisibleLighting(false, false);
3717 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
3719 // optionally draw the illuminated areas
3720 // for performance analysis by level designers
3721 R_Shadow_RenderMode_VisibleLighting(false, false);
3723 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3724 for (i = 0;i < numlightentities;i++)
3725 R_Shadow_DrawEntityLight(lightentities[i]);
3726 for (i = 0;i < numlightentities_noselfshadow;i++)
3727 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3730 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
3732 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
3733 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
3734 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
3735 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
3737 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance/rtlight->radius));
3738 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
3739 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
3741 if (castshadows && (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE))
3747 int receivermask = 0;
3748 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
3749 Matrix4x4_Abs(&radiustolight);
3751 r_shadow_shadowmaplod = 0;
3752 for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
3753 if ((r_shadow_shadowmapmaxsize >> i) > lodlinear)
3754 r_shadow_shadowmaplod = i;
3756 if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
3757 size = max(1, r_shadow_shadowmapmaxsize >> r_shadow_shadowmaplod);
3759 size = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
3761 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
3763 surfacesides = NULL;
3766 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3768 castermask = rtlight->static_shadowmap_casters;
3769 receivermask = rtlight->static_shadowmap_receivers;
3773 surfacesides = r_shadow_buffer_surfacesides;
3774 for(i = 0;i < numsurfaces;i++)
3776 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
3777 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3778 castermask |= surfacesides[i];
3779 receivermask |= surfacesides[i];
3783 if (receivermask < 0x3F)
3785 for (i = 0;i < numlightentities;i++)
3786 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3787 if (receivermask < 0x3F)
3788 for(i = 0; i < numlightentities_noselfshadow;i++)
3789 receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3792 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
3796 for (i = 0;i < numshadowentities;i++)
3797 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3798 for (i = 0;i < numshadowentities_noselfshadow;i++)
3799 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3802 //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
3804 // render shadow casters into 6 sided depth texture
3805 for (side = 0;side < 6;side++) if (receivermask & (1 << side))
3807 R_Shadow_RenderMode_ShadowMap(side, receivermask, size);
3808 if (! (castermask & (1 << side))) continue;
3810 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
3811 for (i = 0;i < numshadowentities;i++) if (entitysides[i] & (1 << side))
3812 R_Shadow_DrawEntityShadow(shadowentities[i]);
3815 if (numlightentities_noselfshadow)
3817 // render lighting using the depth texture as shadowmap
3818 // draw lighting in the unmasked areas
3819 R_Shadow_RenderMode_Lighting(false, false, true);
3820 for (i = 0;i < numlightentities_noselfshadow;i++)
3821 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3824 // render shadow casters into 6 sided depth texture
3825 if (numshadowentities_noselfshadow)
3827 for (side = 0;side < 6;side++) if ((receivermask & castermask) & (1 << side))
3829 R_Shadow_RenderMode_ShadowMap(side, 0, size);
3830 for (i = 0;i < numshadowentities_noselfshadow;i++) if (entitysides_noselfshadow[i] & (1 << side))
3831 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3835 // render lighting using the depth texture as shadowmap
3836 // draw lighting in the unmasked areas
3837 R_Shadow_RenderMode_Lighting(false, false, true);
3838 // draw lighting in the unmasked areas
3840 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3841 for (i = 0;i < numlightentities;i++)
3842 R_Shadow_DrawEntityLight(lightentities[i]);
3844 else if (castshadows && vid.stencil)
3846 // draw stencil shadow volumes to mask off pixels that are in shadow
3847 // so that they won't receive lighting
3848 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
3849 R_Shadow_ClearStencil();
3852 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
3853 for (i = 0;i < numshadowentities;i++)
3854 R_Shadow_DrawEntityShadow(shadowentities[i]);
3856 // draw lighting in the unmasked areas
3857 R_Shadow_RenderMode_Lighting(true, false, false);
3858 for (i = 0;i < numlightentities_noselfshadow;i++)
3859 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3861 for (i = 0;i < numshadowentities_noselfshadow;i++)
3862 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3864 // draw lighting in the unmasked areas
3865 R_Shadow_RenderMode_Lighting(true, false, false);
3867 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3868 for (i = 0;i < numlightentities;i++)
3869 R_Shadow_DrawEntityLight(lightentities[i]);
3873 // draw lighting in the unmasked areas
3874 R_Shadow_RenderMode_Lighting(false, false, false);
3876 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3877 for (i = 0;i < numlightentities;i++)
3878 R_Shadow_DrawEntityLight(lightentities[i]);
3879 for (i = 0;i < numlightentities_noselfshadow;i++)
3880 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3883 if (r_shadow_usingdeferredprepass)
3885 // when rendering deferred lighting, we simply rasterize the box
3886 if (castshadows && (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE))
3887 R_Shadow_RenderMode_DrawDeferredLight(false, true);
3888 else if (castshadows && vid.stencil)
3889 R_Shadow_RenderMode_DrawDeferredLight(true, false);
3891 R_Shadow_RenderMode_DrawDeferredLight(false, false);
3895 static void R_Shadow_FreeDeferred(void)
3897 if (r_shadow_prepassgeometryfbo)
3898 qglDeleteFramebuffersEXT(1, &r_shadow_prepassgeometryfbo);CHECKGLERROR
3899 r_shadow_prepassgeometryfbo = 0;
3901 if (r_shadow_prepasslightingfbo)
3902 qglDeleteFramebuffersEXT(1, &r_shadow_prepasslightingfbo);CHECKGLERROR
3903 r_shadow_prepasslightingfbo = 0;
3905 if (r_shadow_prepassgeometrydepthtexture)
3906 R_FreeTexture(r_shadow_prepassgeometrydepthtexture);
3907 r_shadow_prepassgeometrydepthtexture = NULL;
3909 if (r_shadow_prepassgeometrynormalmaptexture)
3910 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
3911 r_shadow_prepassgeometrynormalmaptexture = NULL;
3913 if (r_shadow_prepasslightingdiffusetexture)
3914 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
3915 r_shadow_prepasslightingdiffusetexture = NULL;
3917 if (r_shadow_prepasslightingspeculartexture)
3918 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
3919 r_shadow_prepasslightingspeculartexture = NULL;
3922 void R_Shadow_DrawPrepass(void)
3930 entity_render_t *ent;
3932 GL_AlphaTest(false);
3933 R_Mesh_ColorPointer(NULL, 0, 0);
3934 R_Mesh_ResetTextureState();
3936 GL_ColorMask(1,1,1,1);
3937 GL_BlendFunc(GL_ONE, GL_ZERO);
3940 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepassgeometryfbo);CHECKGLERROR
3941 qglClearColor(0.5f,0.5f,0.5f,1.0f);CHECKGLERROR
3942 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);CHECKGLERROR
3944 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
3945 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
3946 if (r_timereport_active)
3947 R_TimeReport("prepassworld");
3949 for (i = 0;i < r_refdef.scene.numentities;i++)
3951 if (!r_refdef.viewcache.entityvisible[i])
3953 ent = r_refdef.scene.entities[i];
3954 if (ent->model && ent->model->DrawPrepass != NULL)
3955 ent->model->DrawPrepass(ent);
3958 if (r_timereport_active)
3959 R_TimeReport("prepassmodels");
3961 GL_DepthMask(false);
3962 GL_ColorMask(1,1,1,1);
3965 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepasslightingfbo);CHECKGLERROR
3966 qglClearColor(0.0f,0.0f,0.0f,0.0f);CHECKGLERROR
3967 GL_Clear(GL_COLOR_BUFFER_BIT);CHECKGLERROR
3968 if (r_refdef.fogenabled)
3969 qglClearColor(r_refdef.fogcolor[0],r_refdef.fogcolor[1],r_refdef.fogcolor[2],0);CHECKGLERROR
3971 R_Shadow_RenderMode_Begin();
3973 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3974 if (r_shadow_debuglight.integer >= 0)
3976 lightindex = r_shadow_debuglight.integer;
3977 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3978 if (light && (light->flags & flag))
3979 R_Shadow_DrawLight(&light->rtlight);
3983 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3984 for (lightindex = 0;lightindex < range;lightindex++)
3986 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3987 if (light && (light->flags & flag))
3988 R_Shadow_DrawLight(&light->rtlight);
3991 if (r_refdef.scene.rtdlight)
3992 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
3993 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
3995 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);CHECKGLERROR
3996 if (r_refdef.fogenabled)
3997 qglClearColor(r_refdef.fogcolor[0],r_refdef.fogcolor[1],r_refdef.fogcolor[2],0);CHECKGLERROR
3999 R_Shadow_RenderMode_End();
4001 if (r_timereport_active)
4002 R_TimeReport("prepasslights");
4005 void R_Shadow_DrawLightSprites(void);
4006 void R_Shadow_PrepareLights(void)
4016 if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4) ||
4017 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
4018 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0) ||
4019 r_shadow_shadowmaptexturetype != r_shadow_shadowmapping_texturetype.integer ||
4020 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
4021 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
4022 r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
4023 R_Shadow_FreeShadowMaps();
4025 switch (vid.renderpath)
4027 case RENDERPATH_GL20:
4028 case RENDERPATH_CGGL:
4029 if (!r_shadow_deferred.integer || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_STENCIL || !vid.support.ext_framebuffer_object || !vid.support.arb_texture_rectangle || vid.maxdrawbuffers < 2)
4031 r_shadow_usingdeferredprepass = false;
4032 if (r_shadow_prepass_width)
4033 R_Shadow_FreeDeferred();
4034 r_shadow_prepass_width = r_shadow_prepass_height = 0;
4038 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
4040 R_Shadow_FreeDeferred();
4042 r_shadow_usingdeferredprepass = true;
4043 r_shadow_prepass_width = vid.width;
4044 r_shadow_prepass_height = vid.height;
4045 r_shadow_prepassgeometrydepthtexture = R_LoadTextureShadowMapRectangle(r_shadow_texturepool, "prepassgeometrydepthmap", vid.width, vid.height, 24, false);
4046 r_shadow_prepassgeometrynormalmaptexture = R_LoadTextureRectangle(r_shadow_texturepool, "prepassgeometrynormalmap", vid.width, vid.height, NULL, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, NULL);
4047 r_shadow_prepasslightingdiffusetexture = R_LoadTextureRectangle(r_shadow_texturepool, "prepasslightingdiffuse", vid.width, vid.height, NULL, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, NULL);
4048 r_shadow_prepasslightingspeculartexture = R_LoadTextureRectangle(r_shadow_texturepool, "prepasslightingspecular", vid.width, vid.height, NULL, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, NULL);
4050 // set up the geometry pass fbo (depth + normalmap)
4051 qglGenFramebuffersEXT(1, &r_shadow_prepassgeometryfbo);CHECKGLERROR
4052 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepassgeometryfbo);CHECKGLERROR
4053 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, R_GetTexture(r_shadow_prepassgeometrydepthtexture), 0);CHECKGLERROR
4054 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, R_GetTexture(r_shadow_prepassgeometrynormalmaptexture), 0);CHECKGLERROR
4055 // render depth into one texture and normalmap into the other
4056 qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);CHECKGLERROR
4057 qglReadBuffer(GL_NONE);CHECKGLERROR
4058 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4059 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4061 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4062 Cvar_SetValueQuick(&r_shadow_deferred, 0);
4063 r_shadow_usingdeferredprepass = false;
4066 // set up the lighting pass fbo (diffuse + specular)
4067 qglGenFramebuffersEXT(1, &r_shadow_prepasslightingfbo);CHECKGLERROR
4068 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepasslightingfbo);CHECKGLERROR
4069 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, R_GetTexture(r_shadow_prepassgeometrydepthtexture), 0);CHECKGLERROR
4070 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, R_GetTexture(r_shadow_prepasslightingdiffusetexture), 0);CHECKGLERROR
4071 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_RECTANGLE_ARB, R_GetTexture(r_shadow_prepasslightingspeculartexture), 0);CHECKGLERROR
4072 // render diffuse into one texture and specular into another,
4073 // with depth and normalmap bound as textures,
4074 // with depth bound as attachment as well
4075 qglDrawBuffersARB(2, r_shadow_prepasslightingdrawbuffers);CHECKGLERROR
4076 qglReadBuffer(GL_NONE);CHECKGLERROR
4077 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4078 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4080 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4081 Cvar_SetValueQuick(&r_shadow_deferred, 0);
4082 r_shadow_usingdeferredprepass = false;
4086 case RENDERPATH_GL13:
4087 case RENDERPATH_GL11:
4088 r_shadow_usingdeferredprepass = false;
4092 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);
4094 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4095 if (r_shadow_debuglight.integer >= 0)
4097 lightindex = r_shadow_debuglight.integer;
4098 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4099 if (light && (light->flags & flag))
4100 R_Shadow_PrepareLight(&light->rtlight);
4104 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4105 for (lightindex = 0;lightindex < range;lightindex++)
4107 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4108 if (light && (light->flags & flag))
4109 R_Shadow_PrepareLight(&light->rtlight);
4112 if (r_refdef.scene.rtdlight)
4114 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4115 R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
4117 else if(gl_flashblend.integer)
4119 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4121 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
4122 f = (rtlight->style >= 0 ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4123 VectorScale(rtlight->color, f, rtlight->currentcolor);
4127 if (r_editlights.integer)
4128 R_Shadow_DrawLightSprites();
4131 void R_Shadow_DrawLights(void)
4139 R_Shadow_RenderMode_Begin();
4141 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4142 if (r_shadow_debuglight.integer >= 0)
4144 lightindex = r_shadow_debuglight.integer;
4145 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4146 if (light && (light->flags & flag))
4147 R_Shadow_DrawLight(&light->rtlight);
4151 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4152 for (lightindex = 0;lightindex < range;lightindex++)
4154 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4155 if (light && (light->flags & flag))
4156 R_Shadow_DrawLight(&light->rtlight);
4159 if (r_refdef.scene.rtdlight)
4160 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4161 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4163 R_Shadow_RenderMode_End();
4166 extern const float r_screenvertex3f[12];
4167 extern void R_SetupView(qboolean allowwaterclippingplane);
4168 extern void R_ResetViewRendering3D(void);
4169 extern void R_ResetViewRendering2D(void);
4170 extern cvar_t r_shadows;
4171 extern cvar_t r_shadows_darken;
4172 extern cvar_t r_shadows_drawafterrtlighting;
4173 extern cvar_t r_shadows_castfrombmodels;
4174 extern cvar_t r_shadows_throwdistance;
4175 extern cvar_t r_shadows_throwdirection;
4176 void R_DrawModelShadows(void)
4179 float relativethrowdistance;
4180 entity_render_t *ent;
4181 vec3_t relativelightorigin;
4182 vec3_t relativelightdirection;
4183 vec3_t relativeshadowmins, relativeshadowmaxs;
4184 vec3_t tmp, shadowdir;
4186 if (!r_refdef.scene.numentities || !vid.stencil)
4190 R_ResetViewRendering3D();
4191 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4192 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4193 R_Shadow_RenderMode_Begin();
4194 R_Shadow_RenderMode_ActiveLight(NULL);
4195 r_shadow_lightscissor[0] = r_refdef.view.x;
4196 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
4197 r_shadow_lightscissor[2] = r_refdef.view.width;
4198 r_shadow_lightscissor[3] = r_refdef.view.height;
4199 R_Shadow_RenderMode_StencilShadowVolumes(false);
4202 if (r_shadows.integer == 2)
4204 Math_atov(r_shadows_throwdirection.string, shadowdir);
4205 VectorNormalize(shadowdir);
4208 R_Shadow_ClearStencil();
4210 for (i = 0;i < r_refdef.scene.numentities;i++)
4212 ent = r_refdef.scene.entities[i];
4214 // cast shadows from anything of the map (submodels are optional)
4215 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4217 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4218 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
4219 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
4220 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
4221 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4224 if(ent->entitynumber != 0)
4226 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
4227 int entnum, entnum2, recursion;
4228 entnum = entnum2 = ent->entitynumber;
4229 for(recursion = 32; recursion > 0; --recursion)
4231 entnum2 = cl.entities[entnum].state_current.tagentity;
4232 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
4237 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
4239 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
4240 // transform into modelspace of OUR entity
4241 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
4242 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
4245 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4248 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4251 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
4252 RSurf_ActiveModelEntity(ent, false, false, false);
4253 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4254 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4258 // not really the right mode, but this will disable any silly stencil features
4259 R_Shadow_RenderMode_End();
4261 // set up ortho view for rendering this pass
4262 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4263 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4264 //GL_ScissorTest(true);
4265 //R_EntityMatrix(&identitymatrix);
4266 //R_Mesh_ResetTextureState();
4267 R_ResetViewRendering2D();
4268 R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
4269 R_Mesh_ColorPointer(NULL, 0, 0);
4270 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
4272 // set up a darkening blend on shadowed areas
4273 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4274 //GL_DepthRange(0, 1);
4275 //GL_DepthTest(false);
4276 //GL_DepthMask(false);
4277 //GL_PolygonOffset(0, 0);CHECKGLERROR
4278 GL_Color(0, 0, 0, r_shadows_darken.value);
4279 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4280 //qglDepthFunc(GL_ALWAYS);CHECKGLERROR
4281 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
4282 qglStencilMask(~0);CHECKGLERROR
4283 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
4284 qglStencilFunc(GL_NOTEQUAL, 128, ~0);CHECKGLERROR
4286 // apply the blend to the shadowed areas
4287 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
4289 // restore the viewport
4290 R_SetViewport(&r_refdef.view.viewport);
4292 // restore other state to normal
4293 //R_Shadow_RenderMode_End();
4296 void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4299 vec3_t centerorigin;
4301 // if it's too close, skip it
4302 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
4304 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4307 if (usequery && r_numqueries + 2 <= r_maxqueries)
4309 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4310 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4311 // 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
4312 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4315 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use qglDepthFunc instead
4316 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
4317 qglDepthFunc(GL_ALWAYS);
4318 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4319 R_Mesh_VertexPointer(vertex3f, 0, 0);
4320 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
4321 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4322 qglDepthFunc(GL_LEQUAL);
4323 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
4324 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4325 R_Mesh_VertexPointer(vertex3f, 0, 0);
4326 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
4327 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4330 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4333 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
4335 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4338 GLint allpixels = 0, visiblepixels = 0;
4339 // now we have to check the query result
4340 if (rtlight->corona_queryindex_visiblepixels)
4343 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
4344 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
4346 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
4347 if (visiblepixels < 1 || allpixels < 1)
4349 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
4350 cscale *= rtlight->corona_visibility;
4354 // FIXME: these traces should scan all render entities instead of cl.world
4355 if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
4358 VectorScale(rtlight->currentcolor, cscale, color);
4359 if (VectorLength(color) > (1.0f / 256.0f))
4362 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
4365 VectorNegate(color, color);
4366 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
4368 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4369 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);
4370 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4372 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
4376 void R_Shadow_DrawCoronas(void)
4384 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4386 if (r_waterstate.renderingscene)
4388 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4389 R_EntityMatrix(&identitymatrix);
4391 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4393 // check occlusion of coronas
4394 // use GL_ARB_occlusion_query if available
4395 // otherwise use raytraces
4397 usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
4400 GL_ColorMask(0,0,0,0);
4401 if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
4402 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
4405 r_maxqueries = (range + r_refdef.scene.numlights) * 4;
4406 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
4408 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
4411 RSurf_ActiveWorldEntity();
4412 GL_BlendFunc(GL_ONE, GL_ZERO);
4413 GL_CullFace(GL_NONE);
4414 GL_DepthMask(false);
4415 GL_DepthRange(0, 1);
4416 GL_PolygonOffset(0, 0);
4418 R_Mesh_ColorPointer(NULL, 0, 0);
4419 R_Mesh_ResetTextureState();
4420 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
4422 for (lightindex = 0;lightindex < range;lightindex++)
4424 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4427 rtlight = &light->rtlight;
4428 rtlight->corona_visibility = 0;
4429 rtlight->corona_queryindex_visiblepixels = 0;
4430 rtlight->corona_queryindex_allpixels = 0;
4431 if (!(rtlight->flags & flag))
4433 if (rtlight->corona <= 0)
4435 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4437 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4439 for (i = 0;i < r_refdef.scene.numlights;i++)
4441 rtlight = r_refdef.scene.lights[i];
4442 rtlight->corona_visibility = 0;
4443 rtlight->corona_queryindex_visiblepixels = 0;
4444 rtlight->corona_queryindex_allpixels = 0;
4445 if (!(rtlight->flags & flag))
4447 if (rtlight->corona <= 0)
4449 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4452 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4454 // now draw the coronas using the query data for intensity info
4455 for (lightindex = 0;lightindex < range;lightindex++)
4457 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4460 rtlight = &light->rtlight;
4461 if (rtlight->corona_visibility <= 0)
4463 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4465 for (i = 0;i < r_refdef.scene.numlights;i++)
4467 rtlight = r_refdef.scene.lights[i];
4468 if (rtlight->corona_visibility <= 0)
4470 if (gl_flashblend.integer)
4471 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4473 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4479 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
4480 typedef struct suffixinfo_s
4483 qboolean flipx, flipy, flipdiagonal;
4486 static suffixinfo_t suffix[3][6] =
4489 {"px", false, false, false},
4490 {"nx", false, false, false},
4491 {"py", false, false, false},
4492 {"ny", false, false, false},
4493 {"pz", false, false, false},
4494 {"nz", false, false, false}
4497 {"posx", false, false, false},
4498 {"negx", false, false, false},
4499 {"posy", false, false, false},
4500 {"negy", false, false, false},
4501 {"posz", false, false, false},
4502 {"negz", false, false, false}
4505 {"rt", true, false, true},
4506 {"lf", false, true, true},
4507 {"ft", true, true, false},
4508 {"bk", false, false, false},
4509 {"up", true, false, true},
4510 {"dn", true, false, true}
4514 static int componentorder[4] = {0, 1, 2, 3};
4516 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
4518 int i, j, cubemapsize;
4519 unsigned char *cubemappixels, *image_buffer;
4520 rtexture_t *cubemaptexture;
4522 // must start 0 so the first loadimagepixels has no requested width/height
4524 cubemappixels = NULL;
4525 cubemaptexture = NULL;
4526 // keep trying different suffix groups (posx, px, rt) until one loads
4527 for (j = 0;j < 3 && !cubemappixels;j++)
4529 // load the 6 images in the suffix group
4530 for (i = 0;i < 6;i++)
4532 // generate an image name based on the base and and suffix
4533 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
4535 if ((image_buffer = loadimagepixelsbgra(name, false, false)))
4537 // an image loaded, make sure width and height are equal
4538 if (image_width == image_height && (!cubemappixels || image_width == cubemapsize))
4540 // if this is the first image to load successfully, allocate the cubemap memory
4541 if (!cubemappixels && image_width >= 1)
4543 cubemapsize = image_width;
4544 // note this clears to black, so unavailable sides are black
4545 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
4547 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
4549 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);
4552 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
4554 Mem_Free(image_buffer);
4558 // if a cubemap loaded, upload it
4561 if (developer_loading.integer)
4562 Con_Printf("loading cubemap \"%s\"\n", basename);
4564 if (!r_shadow_filters_texturepool)
4565 r_shadow_filters_texturepool = R_AllocTexturePool();
4566 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_BGRA, (gl_texturecompression_lightcubemaps.integer ? TEXF_COMPRESS : 0) | TEXF_FORCELINEAR, NULL);
4567 Mem_Free(cubemappixels);
4571 Con_DPrintf("failed to load cubemap \"%s\"\n", basename);
4572 if (developer_loading.integer)
4574 Con_Printf("(tried tried images ");
4575 for (j = 0;j < 3;j++)
4576 for (i = 0;i < 6;i++)
4577 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
4578 Con_Print(" and was unable to find any of them).\n");
4581 return cubemaptexture;
4584 rtexture_t *R_Shadow_Cubemap(const char *basename)
4587 for (i = 0;i < numcubemaps;i++)
4588 if (!strcasecmp(cubemaps[i].basename, basename))
4589 return cubemaps[i].texture ? cubemaps[i].texture : r_texture_whitecube;
4590 if (i >= MAX_CUBEMAPS)
4591 return r_texture_whitecube;
4593 strlcpy(cubemaps[i].basename, basename, sizeof(cubemaps[i].basename));
4594 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
4595 return cubemaps[i].texture;
4598 void R_Shadow_FreeCubemaps(void)
4601 for (i = 0;i < numcubemaps;i++)
4603 if (developer_loading.integer)
4604 Con_Printf("unloading cubemap \"%s\"\n", cubemaps[i].basename);
4605 if (cubemaps[i].texture)
4606 R_FreeTexture(cubemaps[i].texture);
4610 R_FreeTexturePool(&r_shadow_filters_texturepool);
4613 dlight_t *R_Shadow_NewWorldLight(void)
4615 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4618 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)
4621 // validate parameters
4622 if (style < 0 || style >= MAX_LIGHTSTYLES)
4624 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
4630 // copy to light properties
4631 VectorCopy(origin, light->origin);
4632 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4633 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4634 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4636 light->color[0] = max(color[0], 0);
4637 light->color[1] = max(color[1], 0);
4638 light->color[2] = max(color[2], 0);
4640 light->color[0] = color[0];
4641 light->color[1] = color[1];
4642 light->color[2] = color[2];
4643 light->radius = max(radius, 0);
4644 light->style = style;
4645 light->shadow = shadowenable;
4646 light->corona = corona;
4647 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4648 light->coronasizescale = coronasizescale;
4649 light->ambientscale = ambientscale;
4650 light->diffusescale = diffusescale;
4651 light->specularscale = specularscale;
4652 light->flags = flags;
4654 // update renderable light data
4655 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4656 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);
4659 void R_Shadow_FreeWorldLight(dlight_t *light)
4661 if (r_shadow_selectedlight == light)
4662 r_shadow_selectedlight = NULL;
4663 R_RTLight_Uncompile(&light->rtlight);
4664 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4667 void R_Shadow_ClearWorldLights(void)
4671 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4672 for (lightindex = 0;lightindex < range;lightindex++)
4674 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4676 R_Shadow_FreeWorldLight(light);
4678 r_shadow_selectedlight = NULL;
4679 R_Shadow_FreeCubemaps();
4682 void R_Shadow_SelectLight(dlight_t *light)
4684 if (r_shadow_selectedlight)
4685 r_shadow_selectedlight->selected = false;
4686 r_shadow_selectedlight = light;
4687 if (r_shadow_selectedlight)
4688 r_shadow_selectedlight->selected = true;
4691 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4693 // this is never batched (there can be only one)
4695 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
4696 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4697 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4700 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4705 skinframe_t *skinframe;
4708 // this is never batched (due to the ent parameter changing every time)
4709 // so numsurfaces == 1 and surfacelist[0] == lightnumber
4710 const dlight_t *light = (dlight_t *)ent;
4713 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
4716 VectorScale(light->color, intensity, spritecolor);
4717 if (VectorLength(spritecolor) < 0.1732f)
4718 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
4719 if (VectorLength(spritecolor) > 1.0f)
4720 VectorNormalize(spritecolor);
4722 // draw light sprite
4723 if (light->cubemapname[0] && !light->shadow)
4724 skinframe = r_editlights_sprcubemapnoshadowlight;
4725 else if (light->cubemapname[0])
4726 skinframe = r_editlights_sprcubemaplight;
4727 else if (!light->shadow)
4728 skinframe = r_editlights_sprnoshadowlight;
4730 skinframe = r_editlights_sprlight;
4732 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);
4733 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4735 // draw selection sprite if light is selected
4736 if (light->selected)
4738 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4739 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4740 // VorteX todo: add normalmode/realtime mode light overlay sprites?
4744 void R_Shadow_DrawLightSprites(void)
4748 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4749 for (lightindex = 0;lightindex < range;lightindex++)
4751 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4753 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
4755 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
4758 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
4763 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
4764 if (lightindex >= range)
4766 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4769 rtlight = &light->rtlight;
4770 //if (!(rtlight->flags & flag))
4772 VectorCopy(rtlight->shadoworigin, origin);
4773 *radius = rtlight->radius;
4774 VectorCopy(rtlight->color, color);
4778 void R_Shadow_SelectLightInView(void)
4780 float bestrating, rating, temp[3];
4784 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4787 for (lightindex = 0;lightindex < range;lightindex++)
4789 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4792 VectorSubtract(light->origin, r_refdef.view.origin, temp);
4793 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
4796 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
4797 if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1.0f)
4799 bestrating = rating;
4804 R_Shadow_SelectLight(best);
4807 void R_Shadow_LoadWorldLights(void)
4809 int n, a, style, shadow, flags;
4810 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
4811 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
4812 if (cl.worldmodel == NULL)
4814 Con_Print("No map loaded.\n");
4817 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4818 strlcat (name, ".rtlights", sizeof (name));
4819 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4829 for (;COM_Parse(t, true) && strcmp(
4830 if (COM_Parse(t, true))
4832 if (com_token[0] == '!')
4835 origin[0] = atof(com_token+1);
4838 origin[0] = atof(com_token);
4843 while (*s && *s != '\n' && *s != '\r')
4849 // check for modifier flags
4856 #if _MSC_VER >= 1400
4857 #define sscanf sscanf_s
4859 cubemapname[sizeof(cubemapname)-1] = 0;
4860 #if MAX_QPATH != 128
4861 #error update this code if MAX_QPATH changes
4863 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
4864 #if _MSC_VER >= 1400
4865 , sizeof(cubemapname)
4867 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
4870 flags = LIGHTFLAG_REALTIMEMODE;
4878 coronasizescale = 0.25f;
4880 VectorClear(angles);
4883 if (a < 9 || !strcmp(cubemapname, "\"\""))
4885 // remove quotes on cubemapname
4886 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
4889 namelen = strlen(cubemapname) - 2;
4890 memmove(cubemapname, cubemapname + 1, namelen);
4891 cubemapname[namelen] = '\0';
4895 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);
4898 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4906 Con_Printf("invalid rtlights file \"%s\"\n", name);
4907 Mem_Free(lightsstring);
4911 void R_Shadow_SaveWorldLights(void)
4915 size_t bufchars, bufmaxchars;
4917 char name[MAX_QPATH];
4918 char line[MAX_INPUTLINE];
4919 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
4920 // I hate lines which are 3 times my screen size :( --blub
4923 if (cl.worldmodel == NULL)
4925 Con_Print("No map loaded.\n");
4928 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4929 strlcat (name, ".rtlights", sizeof (name));
4930 bufchars = bufmaxchars = 0;
4932 for (lightindex = 0;lightindex < range;lightindex++)
4934 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4937 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
4938 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);
4939 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
4940 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]);
4942 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);
4943 if (bufchars + strlen(line) > bufmaxchars)
4945 bufmaxchars = bufchars + strlen(line) + 2048;
4947 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
4951 memcpy(buf, oldbuf, bufchars);
4957 memcpy(buf + bufchars, line, strlen(line));
4958 bufchars += strlen(line);
4962 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
4967 void R_Shadow_LoadLightsFile(void)
4970 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
4971 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
4972 if (cl.worldmodel == NULL)
4974 Con_Print("No map loaded.\n");
4977 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4978 strlcat (name, ".lights", sizeof (name));
4979 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4987 while (*s && *s != '\n' && *s != '\r')
4993 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);
4997 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);
5000 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
5001 radius = bound(15, radius, 4096);
5002 VectorScale(color, (2.0f / (8388608.0f)), color);
5003 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5011 Con_Printf("invalid lights file \"%s\"\n", name);
5012 Mem_Free(lightsstring);
5016 // tyrlite/hmap2 light types in the delay field
5017 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
5019 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
5021 int entnum, style, islight, skin, pflags, effects, type, n;
5024 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
5025 char key[256], value[MAX_INPUTLINE];
5027 if (cl.worldmodel == NULL)
5029 Con_Print("No map loaded.\n");
5032 // try to load a .ent file first
5033 FS_StripExtension (cl.worldmodel->name, key, sizeof (key));
5034 strlcat (key, ".ent", sizeof (key));
5035 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
5036 // and if that is not found, fall back to the bsp file entity string
5038 data = cl.worldmodel->brush.entities;
5041 for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
5043 type = LIGHTTYPE_MINUSX;
5044 origin[0] = origin[1] = origin[2] = 0;
5045 originhack[0] = originhack[1] = originhack[2] = 0;
5046 angles[0] = angles[1] = angles[2] = 0;
5047 color[0] = color[1] = color[2] = 1;
5048 light[0] = light[1] = light[2] = 1;light[3] = 300;
5049 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
5059 if (!COM_ParseToken_Simple(&data, false, false))
5061 if (com_token[0] == '}')
5062 break; // end of entity
5063 if (com_token[0] == '_')
5064 strlcpy(key, com_token + 1, sizeof(key));
5066 strlcpy(key, com_token, sizeof(key));
5067 while (key[strlen(key)-1] == ' ') // remove trailing spaces
5068 key[strlen(key)-1] = 0;
5069 if (!COM_ParseToken_Simple(&data, false, false))
5071 strlcpy(value, com_token, sizeof(value));
5073 // now that we have the key pair worked out...
5074 if (!strcmp("light", key))
5076 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5080 light[0] = vec[0] * (1.0f / 256.0f);
5081 light[1] = vec[0] * (1.0f / 256.0f);
5082 light[2] = vec[0] * (1.0f / 256.0f);
5088 light[0] = vec[0] * (1.0f / 255.0f);
5089 light[1] = vec[1] * (1.0f / 255.0f);
5090 light[2] = vec[2] * (1.0f / 255.0f);
5094 else if (!strcmp("delay", key))
5096 else if (!strcmp("origin", key))
5097 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5098 else if (!strcmp("angle", key))
5099 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5100 else if (!strcmp("angles", key))
5101 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5102 else if (!strcmp("color", key))
5103 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5104 else if (!strcmp("wait", key))
5105 fadescale = atof(value);
5106 else if (!strcmp("classname", key))
5108 if (!strncmp(value, "light", 5))
5111 if (!strcmp(value, "light_fluoro"))
5116 overridecolor[0] = 1;
5117 overridecolor[1] = 1;
5118 overridecolor[2] = 1;
5120 if (!strcmp(value, "light_fluorospark"))
5125 overridecolor[0] = 1;
5126 overridecolor[1] = 1;
5127 overridecolor[2] = 1;
5129 if (!strcmp(value, "light_globe"))
5134 overridecolor[0] = 1;
5135 overridecolor[1] = 0.8;
5136 overridecolor[2] = 0.4;
5138 if (!strcmp(value, "light_flame_large_yellow"))
5143 overridecolor[0] = 1;
5144 overridecolor[1] = 0.5;
5145 overridecolor[2] = 0.1;
5147 if (!strcmp(value, "light_flame_small_yellow"))
5152 overridecolor[0] = 1;
5153 overridecolor[1] = 0.5;
5154 overridecolor[2] = 0.1;
5156 if (!strcmp(value, "light_torch_small_white"))
5161 overridecolor[0] = 1;
5162 overridecolor[1] = 0.5;
5163 overridecolor[2] = 0.1;
5165 if (!strcmp(value, "light_torch_small_walltorch"))
5170 overridecolor[0] = 1;
5171 overridecolor[1] = 0.5;
5172 overridecolor[2] = 0.1;
5176 else if (!strcmp("style", key))
5177 style = atoi(value);
5178 else if (!strcmp("skin", key))
5179 skin = (int)atof(value);
5180 else if (!strcmp("pflags", key))
5181 pflags = (int)atof(value);
5182 else if (!strcmp("effects", key))
5183 effects = (int)atof(value);
5184 else if (cl.worldmodel->type == mod_brushq3)
5186 if (!strcmp("scale", key))
5187 lightscale = atof(value);
5188 if (!strcmp("fade", key))
5189 fadescale = atof(value);
5194 if (lightscale <= 0)
5198 if (color[0] == color[1] && color[0] == color[2])
5200 color[0] *= overridecolor[0];
5201 color[1] *= overridecolor[1];
5202 color[2] *= overridecolor[2];
5204 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5205 color[0] = color[0] * light[0];
5206 color[1] = color[1] * light[1];
5207 color[2] = color[2] * light[2];
5210 case LIGHTTYPE_MINUSX:
5212 case LIGHTTYPE_RECIPX:
5214 VectorScale(color, (1.0f / 16.0f), color);
5216 case LIGHTTYPE_RECIPXX:
5218 VectorScale(color, (1.0f / 16.0f), color);
5221 case LIGHTTYPE_NONE:
5225 case LIGHTTYPE_MINUSXX:
5228 VectorAdd(origin, originhack, origin);
5230 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);
5233 Mem_Free(entfiledata);
5237 void R_Shadow_SetCursorLocationForView(void)
5240 vec3_t dest, endpos;
5242 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5243 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
5244 if (trace.fraction < 1)
5246 dist = trace.fraction * r_editlights_cursordistance.value;
5247 push = r_editlights_cursorpushback.value;
5251 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5252 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5256 VectorClear( endpos );
5258 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5259 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5260 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5263 void R_Shadow_UpdateWorldLightSelection(void)
5265 if (r_editlights.integer)
5267 R_Shadow_SetCursorLocationForView();
5268 R_Shadow_SelectLightInView();
5271 R_Shadow_SelectLight(NULL);
5274 void R_Shadow_EditLights_Clear_f(void)
5276 R_Shadow_ClearWorldLights();
5279 void R_Shadow_EditLights_Reload_f(void)
5283 strlcpy(r_shadow_mapname, cl.worldmodel->name, sizeof(r_shadow_mapname));
5284 R_Shadow_ClearWorldLights();
5285 R_Shadow_LoadWorldLights();
5286 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5288 R_Shadow_LoadLightsFile();
5289 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5290 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5294 void R_Shadow_EditLights_Save_f(void)
5298 R_Shadow_SaveWorldLights();
5301 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
5303 R_Shadow_ClearWorldLights();
5304 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5307 void R_Shadow_EditLights_ImportLightsFile_f(void)
5309 R_Shadow_ClearWorldLights();
5310 R_Shadow_LoadLightsFile();
5313 void R_Shadow_EditLights_Spawn_f(void)
5316 if (!r_editlights.integer)
5318 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5321 if (Cmd_Argc() != 1)
5323 Con_Print("r_editlights_spawn does not take parameters\n");
5326 color[0] = color[1] = color[2] = 1;
5327 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5330 void R_Shadow_EditLights_Edit_f(void)
5332 vec3_t origin, angles, color;
5333 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5334 int style, shadows, flags, normalmode, realtimemode;
5335 char cubemapname[MAX_INPUTLINE];
5336 if (!r_editlights.integer)
5338 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5341 if (!r_shadow_selectedlight)
5343 Con_Print("No selected light.\n");
5346 VectorCopy(r_shadow_selectedlight->origin, origin);
5347 VectorCopy(r_shadow_selectedlight->angles, angles);
5348 VectorCopy(r_shadow_selectedlight->color, color);
5349 radius = r_shadow_selectedlight->radius;
5350 style = r_shadow_selectedlight->style;
5351 if (r_shadow_selectedlight->cubemapname)
5352 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5355 shadows = r_shadow_selectedlight->shadow;
5356 corona = r_shadow_selectedlight->corona;
5357 coronasizescale = r_shadow_selectedlight->coronasizescale;
5358 ambientscale = r_shadow_selectedlight->ambientscale;
5359 diffusescale = r_shadow_selectedlight->diffusescale;
5360 specularscale = r_shadow_selectedlight->specularscale;
5361 flags = r_shadow_selectedlight->flags;
5362 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5363 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5364 if (!strcmp(Cmd_Argv(1), "origin"))
5366 if (Cmd_Argc() != 5)
5368 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5371 origin[0] = atof(Cmd_Argv(2));
5372 origin[1] = atof(Cmd_Argv(3));
5373 origin[2] = atof(Cmd_Argv(4));
5375 else if (!strcmp(Cmd_Argv(1), "originx"))
5377 if (Cmd_Argc() != 3)
5379 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5382 origin[0] = atof(Cmd_Argv(2));
5384 else if (!strcmp(Cmd_Argv(1), "originy"))
5386 if (Cmd_Argc() != 3)
5388 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5391 origin[1] = atof(Cmd_Argv(2));
5393 else if (!strcmp(Cmd_Argv(1), "originz"))
5395 if (Cmd_Argc() != 3)
5397 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5400 origin[2] = atof(Cmd_Argv(2));
5402 else if (!strcmp(Cmd_Argv(1), "move"))
5404 if (Cmd_Argc() != 5)
5406 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5409 origin[0] += atof(Cmd_Argv(2));
5410 origin[1] += atof(Cmd_Argv(3));
5411 origin[2] += atof(Cmd_Argv(4));
5413 else if (!strcmp(Cmd_Argv(1), "movex"))
5415 if (Cmd_Argc() != 3)
5417 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5420 origin[0] += atof(Cmd_Argv(2));
5422 else if (!strcmp(Cmd_Argv(1), "movey"))
5424 if (Cmd_Argc() != 3)
5426 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5429 origin[1] += atof(Cmd_Argv(2));
5431 else if (!strcmp(Cmd_Argv(1), "movez"))
5433 if (Cmd_Argc() != 3)
5435 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5438 origin[2] += atof(Cmd_Argv(2));
5440 else if (!strcmp(Cmd_Argv(1), "angles"))
5442 if (Cmd_Argc() != 5)
5444 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5447 angles[0] = atof(Cmd_Argv(2));
5448 angles[1] = atof(Cmd_Argv(3));
5449 angles[2] = atof(Cmd_Argv(4));
5451 else if (!strcmp(Cmd_Argv(1), "anglesx"))
5453 if (Cmd_Argc() != 3)
5455 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5458 angles[0] = atof(Cmd_Argv(2));
5460 else if (!strcmp(Cmd_Argv(1), "anglesy"))
5462 if (Cmd_Argc() != 3)
5464 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5467 angles[1] = atof(Cmd_Argv(2));
5469 else if (!strcmp(Cmd_Argv(1), "anglesz"))
5471 if (Cmd_Argc() != 3)
5473 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5476 angles[2] = atof(Cmd_Argv(2));
5478 else if (!strcmp(Cmd_Argv(1), "color"))
5480 if (Cmd_Argc() != 5)
5482 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
5485 color[0] = atof(Cmd_Argv(2));
5486 color[1] = atof(Cmd_Argv(3));
5487 color[2] = atof(Cmd_Argv(4));
5489 else if (!strcmp(Cmd_Argv(1), "radius"))
5491 if (Cmd_Argc() != 3)
5493 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5496 radius = atof(Cmd_Argv(2));
5498 else if (!strcmp(Cmd_Argv(1), "colorscale"))
5500 if (Cmd_Argc() == 3)
5502 double scale = atof(Cmd_Argv(2));
5509 if (Cmd_Argc() != 5)
5511 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
5514 color[0] *= atof(Cmd_Argv(2));
5515 color[1] *= atof(Cmd_Argv(3));
5516 color[2] *= atof(Cmd_Argv(4));
5519 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
5521 if (Cmd_Argc() != 3)
5523 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5526 radius *= atof(Cmd_Argv(2));
5528 else if (!strcmp(Cmd_Argv(1), "style"))
5530 if (Cmd_Argc() != 3)
5532 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5535 style = atoi(Cmd_Argv(2));
5537 else if (!strcmp(Cmd_Argv(1), "cubemap"))
5541 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5544 if (Cmd_Argc() == 3)
5545 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
5549 else if (!strcmp(Cmd_Argv(1), "shadows"))
5551 if (Cmd_Argc() != 3)
5553 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5556 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5558 else if (!strcmp(Cmd_Argv(1), "corona"))
5560 if (Cmd_Argc() != 3)
5562 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5565 corona = atof(Cmd_Argv(2));
5567 else if (!strcmp(Cmd_Argv(1), "coronasize"))
5569 if (Cmd_Argc() != 3)
5571 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5574 coronasizescale = atof(Cmd_Argv(2));
5576 else if (!strcmp(Cmd_Argv(1), "ambient"))
5578 if (Cmd_Argc() != 3)
5580 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5583 ambientscale = atof(Cmd_Argv(2));
5585 else if (!strcmp(Cmd_Argv(1), "diffuse"))
5587 if (Cmd_Argc() != 3)
5589 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5592 diffusescale = atof(Cmd_Argv(2));
5594 else if (!strcmp(Cmd_Argv(1), "specular"))
5596 if (Cmd_Argc() != 3)
5598 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5601 specularscale = atof(Cmd_Argv(2));
5603 else if (!strcmp(Cmd_Argv(1), "normalmode"))
5605 if (Cmd_Argc() != 3)
5607 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5610 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5612 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
5614 if (Cmd_Argc() != 3)
5616 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5619 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5623 Con_Print("usage: r_editlights_edit [property] [value]\n");
5624 Con_Print("Selected light's properties:\n");
5625 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5626 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5627 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5628 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
5629 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
5630 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
5631 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5632 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
5633 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
5634 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
5635 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
5636 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
5637 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5638 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5641 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5642 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5645 void R_Shadow_EditLights_EditAll_f(void)
5651 if (!r_editlights.integer)
5653 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5657 // EditLights doesn't seem to have a "remove" command or something so:
5658 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5659 for (lightindex = 0;lightindex < range;lightindex++)
5661 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5664 R_Shadow_SelectLight(light);
5665 R_Shadow_EditLights_Edit_f();
5669 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
5671 int lightnumber, lightcount;
5672 size_t lightindex, range;
5676 if (!r_editlights.integer)
5678 x = vid_conwidth.value - 240;
5680 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
5683 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5684 for (lightindex = 0;lightindex < range;lightindex++)
5686 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5689 if (light == r_shadow_selectedlight)
5690 lightnumber = lightindex;
5693 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;
5694 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;
5696 if (r_shadow_selectedlight == NULL)
5698 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;
5699 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;
5700 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;
5701 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;
5702 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;
5703 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;
5704 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;
5705 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;
5706 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;
5707 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;
5708 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;
5709 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;
5710 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;
5711 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;
5712 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;
5715 void R_Shadow_EditLights_ToggleShadow_f(void)
5717 if (!r_editlights.integer)
5719 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5722 if (!r_shadow_selectedlight)
5724 Con_Print("No selected light.\n");
5727 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);
5730 void R_Shadow_EditLights_ToggleCorona_f(void)
5732 if (!r_editlights.integer)
5734 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5737 if (!r_shadow_selectedlight)
5739 Con_Print("No selected light.\n");
5742 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);
5745 void R_Shadow_EditLights_Remove_f(void)
5747 if (!r_editlights.integer)
5749 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
5752 if (!r_shadow_selectedlight)
5754 Con_Print("No selected light.\n");
5757 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
5758 r_shadow_selectedlight = NULL;
5761 void R_Shadow_EditLights_Help_f(void)
5764 "Documentation on r_editlights system:\n"
5766 "r_editlights : enable/disable editing mode\n"
5767 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
5768 "r_editlights_cursorpushback : push back cursor this far from surface\n"
5769 "r_editlights_cursorpushoff : push cursor off surface this far\n"
5770 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
5771 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
5773 "r_editlights_help : this help\n"
5774 "r_editlights_clear : remove all lights\n"
5775 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
5776 "r_editlights_save : save to .rtlights file\n"
5777 "r_editlights_spawn : create a light with default settings\n"
5778 "r_editlights_edit command : edit selected light - more documentation below\n"
5779 "r_editlights_remove : remove selected light\n"
5780 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
5781 "r_editlights_importlightentitiesfrommap : reload light entities\n"
5782 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
5784 "origin x y z : set light location\n"
5785 "originx x: set x component of light location\n"
5786 "originy y: set y component of light location\n"
5787 "originz z: set z component of light location\n"
5788 "move x y z : adjust light location\n"
5789 "movex x: adjust x component of light location\n"
5790 "movey y: adjust y component of light location\n"
5791 "movez z: adjust z component of light location\n"
5792 "angles x y z : set light angles\n"
5793 "anglesx x: set x component of light angles\n"
5794 "anglesy y: set y component of light angles\n"
5795 "anglesz z: set z component of light angles\n"
5796 "color r g b : set color of light (can be brighter than 1 1 1)\n"
5797 "radius radius : set radius (size) of light\n"
5798 "colorscale grey : multiply color of light (1 does nothing)\n"
5799 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
5800 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
5801 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
5802 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
5803 "cubemap basename : set filter cubemap of light (not yet supported)\n"
5804 "shadows 1/0 : turn on/off shadows\n"
5805 "corona n : set corona intensity\n"
5806 "coronasize n : set corona size (0-1)\n"
5807 "ambient n : set ambient intensity (0-1)\n"
5808 "diffuse n : set diffuse intensity (0-1)\n"
5809 "specular n : set specular intensity (0-1)\n"
5810 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
5811 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
5812 "<nothing> : print light properties to console\n"
5816 void R_Shadow_EditLights_CopyInfo_f(void)
5818 if (!r_editlights.integer)
5820 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
5823 if (!r_shadow_selectedlight)
5825 Con_Print("No selected light.\n");
5828 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
5829 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
5830 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
5831 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
5832 if (r_shadow_selectedlight->cubemapname)
5833 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
5835 r_shadow_bufferlight.cubemapname[0] = 0;
5836 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
5837 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
5838 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
5839 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
5840 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
5841 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
5842 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
5845 void R_Shadow_EditLights_PasteInfo_f(void)
5847 if (!r_editlights.integer)
5849 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
5852 if (!r_shadow_selectedlight)
5854 Con_Print("No selected light.\n");
5857 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);
5860 void R_Shadow_EditLights_Init(void)
5862 Cvar_RegisterVariable(&r_editlights);
5863 Cvar_RegisterVariable(&r_editlights_cursordistance);
5864 Cvar_RegisterVariable(&r_editlights_cursorpushback);
5865 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
5866 Cvar_RegisterVariable(&r_editlights_cursorgrid);
5867 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
5868 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
5869 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
5870 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)");
5871 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
5872 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
5873 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
5874 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)");
5875 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
5876 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
5877 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
5878 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
5879 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
5880 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
5881 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)");
5887 =============================================================================
5891 =============================================================================
5894 void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, int dynamic)
5896 VectorClear(diffusecolor);
5897 VectorClear(diffusenormal);
5899 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
5901 ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_refdef.scene.ambient;
5902 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
5905 VectorSet(ambientcolor, 1, 1, 1);
5912 for (i = 0;i < r_refdef.scene.numlights;i++)
5914 light = r_refdef.scene.lights[i];
5915 Matrix4x4_Transform(&light->matrix_worldtolight, p, v);
5916 f = 1 - VectorLength2(v);
5917 if (f > 0 && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
5918 VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);