3 Terminology: Stencil Shadow Volume (sometimes called Stencil Shadows)
4 An extrusion of the lit faces, beginning at the original geometry and ending
5 further from the light source than the original geometry (presumably at least
6 as far as the light's radius, if the light has a radius at all), capped at
7 both front and back to avoid any problems (extrusion from dark faces also
8 works but has a different set of problems)
10 This is normally rendered using Carmack's Reverse technique, in which
11 backfaces behind zbuffer (zfail) increment the stencil, and frontfaces behind
12 zbuffer (zfail) decrement the stencil, the result is a stencil value of zero
13 where shadows did not intersect the visible geometry, suitable as a stencil
14 mask for rendering lighting everywhere but shadow.
16 In our case to hopefully avoid the Creative Labs patent, we draw the backfaces
17 as decrement and the frontfaces as increment, and we redefine the DepthFunc to
18 GL_LESS (the patent uses GL_GEQUAL) which causes zfail when behind surfaces
19 and zpass when infront (the patent draws where zpass with a GL_GEQUAL test),
20 additionally we clear stencil to 128 to avoid the need for the unclamped
21 incr/decr extension (not related to patent).
24 This algorithm may be covered by Creative's patent (US Patent #6384822),
25 however that patent is quite specific about increment on backfaces and
26 decrement on frontfaces where zpass with GL_GEQUAL depth test, which is
27 opposite this implementation and partially opposite Carmack's Reverse paper
28 (which uses GL_LESS, but increments on backfaces and decrements on frontfaces).
32 Terminology: Stencil Light Volume (sometimes called Light Volumes)
33 Similar to a Stencil Shadow Volume, but inverted; rather than containing the
34 areas in shadow it contains the areas in light, this can only be built
35 quickly for certain limited cases (such as portal visibility from a point),
36 but is quite useful for some effects (sunlight coming from sky polygons is
37 one possible example, translucent occluders is another example).
41 Terminology: Optimized Stencil Shadow Volume
42 A Stencil Shadow Volume that has been processed sufficiently to ensure it has
43 no duplicate coverage of areas (no need to shadow an area twice), often this
44 greatly improves performance but is an operation too costly to use on moving
45 lights (however completely optimal Stencil Light Volumes can be constructed
50 Terminology: Per Pixel Lighting (sometimes abbreviated PPL)
51 Per pixel evaluation of lighting equations, at a bare minimum this involves
52 DOT3 shading of diffuse lighting (per pixel dotproduct of negated incidence
53 vector and surface normal, using a texture of the surface bumps, called a
54 NormalMap) if supported by hardware; in our case there is support for cards
55 which are incapable of DOT3, the quality is quite poor however. Additionally
56 it is desirable to have specular evaluation per pixel, per vertex
57 normalization of specular halfangle vectors causes noticable distortion but
58 is unavoidable on hardware without GL_ARB_fragment_program or
59 GL_ARB_fragment_shader.
63 Terminology: Normalization CubeMap
64 A cubemap containing normalized dot3-encoded (vectors of length 1 or less
65 encoded as RGB colors) for any possible direction, this technique allows per
66 pixel calculation of incidence vector for per pixel lighting purposes, which
67 would not otherwise be possible per pixel without GL_ARB_fragment_program or
68 GL_ARB_fragment_shader.
72 Terminology: 2D+1D Attenuation Texturing
73 A very crude approximation of light attenuation with distance which results
74 in cylindrical light shapes which fade vertically as a streak (some games
75 such as Doom3 allow this to be rotated to be less noticable in specific
76 cases), the technique is simply modulating lighting by two 2D textures (which
77 can be the same) on different axes of projection (XY and Z, typically), this
78 is the second best technique available without 3D Attenuation Texturing,
79 GL_ARB_fragment_program or GL_ARB_fragment_shader technology.
83 Terminology: 2D+1D Inverse Attenuation Texturing
84 A clever method described in papers on the Abducted engine, this has a squared
85 distance texture (bright on the outside, black in the middle), which is used
86 twice using GL_ADD blending, the result of this is used in an inverse modulate
87 (GL_ONE_MINUS_DST_ALPHA, GL_ZERO) to implement the equation
88 lighting*=(1-((X*X+Y*Y)+(Z*Z))) which is spherical (unlike 2D+1D attenuation
93 Terminology: 3D Attenuation Texturing
94 A slightly crude approximation of light attenuation with distance, its flaws
95 are limited radius and resolution (performance tradeoffs).
99 Terminology: 3D Attenuation-Normalization Texturing
100 A 3D Attenuation Texture merged with a Normalization CubeMap, by making the
101 vectors shorter the lighting becomes darker, a very effective optimization of
102 diffuse lighting if 3D Attenuation Textures are already used.
106 Terminology: Light Cubemap Filtering
107 A technique for modeling non-uniform light distribution according to
108 direction, for example a lantern may use a cubemap to describe the light
109 emission pattern of the cage around the lantern (as well as soot buildup
110 discoloring the light in certain areas), often also used for softened grate
111 shadows and light shining through a stained glass window (done crudely by
112 texturing the lighting with a cubemap), another good example would be a disco
113 light. This technique is used heavily in many games (Doom3 does not support
118 Terminology: Light Projection Filtering
119 A technique for modeling shadowing of light passing through translucent
120 surfaces, allowing stained glass windows and other effects to be done more
121 elegantly than possible with Light Cubemap Filtering by applying an occluder
122 texture to the lighting combined with a stencil light volume to limit the lit
123 area, this technique is used by Doom3 for spotlights and flashlights, among
124 other things, this can also be used more generally to render light passing
125 through multiple translucent occluders in a scene (using a light volume to
126 describe the area beyond the occluder, and thus mask off rendering of all
131 Terminology: Doom3 Lighting
132 A combination of Stencil Shadow Volume, Per Pixel Lighting, Normalization
133 CubeMap, 2D+1D Attenuation Texturing, and Light Projection Filtering, as
134 demonstrated by the game Doom3.
137 #include "quakedef.h"
138 #include "r_shadow.h"
139 #include "cl_collision.h"
143 extern void R_Shadow_EditLights_Init(void);
145 typedef enum r_shadow_rendermode_e
147 R_SHADOW_RENDERMODE_NONE,
148 R_SHADOW_RENDERMODE_ZPASS_STENCIL,
149 R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL,
150 R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE,
151 R_SHADOW_RENDERMODE_ZFAIL_STENCIL,
152 R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL,
153 R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE,
154 R_SHADOW_RENDERMODE_LIGHT_VERTEX,
155 R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN,
156 R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN,
157 R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN,
158 R_SHADOW_RENDERMODE_LIGHT_GLSL,
159 R_SHADOW_RENDERMODE_VISIBLEVOLUMES,
160 R_SHADOW_RENDERMODE_VISIBLELIGHTING,
161 R_SHADOW_RENDERMODE_SHADOWMAP2D,
162 R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE,
163 R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE,
165 r_shadow_rendermode_t;
167 typedef enum r_shadow_shadowmode_e
169 R_SHADOW_SHADOWMODE_STENCIL,
170 R_SHADOW_SHADOWMODE_SHADOWMAP2D,
171 R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE,
172 R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE
174 r_shadow_shadowmode_t;
176 r_shadow_rendermode_t r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
177 r_shadow_rendermode_t r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_NONE;
178 r_shadow_rendermode_t r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_NONE;
179 r_shadow_rendermode_t r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_NONE;
180 qboolean r_shadow_usingshadowmaprect;
181 qboolean r_shadow_usingshadowmap2d;
182 qboolean r_shadow_usingshadowmapcube;
183 int r_shadow_shadowmapside;
184 float r_shadow_shadowmap_texturescale[2];
185 float r_shadow_shadowmap_parameters[4];
187 int r_shadow_drawbuffer;
188 int r_shadow_readbuffer;
190 int r_shadow_cullface_front, r_shadow_cullface_back;
191 GLuint r_shadow_fborectangle;
192 GLuint r_shadow_fbocubeside[R_SHADOW_SHADOWMAP_NUMCUBEMAPS];
193 GLuint r_shadow_fbo2d;
194 r_shadow_shadowmode_t r_shadow_shadowmode;
195 int r_shadow_shadowmapfilterquality;
196 int r_shadow_shadowmaptexturetype;
197 int r_shadow_shadowmapdepthbits;
198 int r_shadow_shadowmapmaxsize;
199 qboolean r_shadow_shadowmapvsdct;
200 qboolean r_shadow_shadowmapsampler;
201 int r_shadow_shadowmappcf;
202 int r_shadow_shadowmapborder;
203 int r_shadow_lightscissor[4];
204 qboolean r_shadow_usingdeferredprepass;
206 int maxshadowtriangles;
209 int maxshadowvertices;
210 float *shadowvertex3f;
220 unsigned char *shadowsides;
221 int *shadowsideslist;
228 int r_shadow_buffer_numleafpvsbytes;
229 unsigned char *r_shadow_buffer_visitingleafpvs;
230 unsigned char *r_shadow_buffer_leafpvs;
231 int *r_shadow_buffer_leaflist;
233 int r_shadow_buffer_numsurfacepvsbytes;
234 unsigned char *r_shadow_buffer_surfacepvs;
235 int *r_shadow_buffer_surfacelist;
236 unsigned char *r_shadow_buffer_surfacesides;
238 int r_shadow_buffer_numshadowtrispvsbytes;
239 unsigned char *r_shadow_buffer_shadowtrispvs;
240 int r_shadow_buffer_numlighttrispvsbytes;
241 unsigned char *r_shadow_buffer_lighttrispvs;
243 rtexturepool_t *r_shadow_texturepool;
244 rtexture_t *r_shadow_attenuationgradienttexture;
245 rtexture_t *r_shadow_attenuation2dtexture;
246 rtexture_t *r_shadow_attenuation3dtexture;
247 skinframe_t *r_shadow_lightcorona;
248 rtexture_t *r_shadow_shadowmaprectangletexture;
249 rtexture_t *r_shadow_shadowmap2dtexture;
250 rtexture_t *r_shadow_shadowmapcubetexture[R_SHADOW_SHADOWMAP_NUMCUBEMAPS];
251 rtexture_t *r_shadow_shadowmapvsdcttexture;
252 int r_shadow_shadowmapsize; // changes for each light based on distance
253 int r_shadow_shadowmaplod; // changes for each light based on distance
255 GLuint r_shadow_prepassgeometryfbo;
256 GLuint r_shadow_prepasslightingfbo;
257 int r_shadow_prepass_width;
258 int r_shadow_prepass_height;
259 rtexture_t *r_shadow_prepassgeometrydepthtexture;
260 rtexture_t *r_shadow_prepassgeometrynormalmaptexture;
261 rtexture_t *r_shadow_prepasslightingdiffusetexture;
262 rtexture_t *r_shadow_prepasslightingspeculartexture;
264 // lights are reloaded when this changes
265 char r_shadow_mapname[MAX_QPATH];
267 // used only for light filters (cubemaps)
268 rtexturepool_t *r_shadow_filters_texturepool;
270 static const GLenum r_shadow_prepasslightingdrawbuffers[2] = {GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT};
272 cvar_t r_shadow_bumpscale_basetexture = {0, "r_shadow_bumpscale_basetexture", "0", "generate fake bumpmaps from diffuse textures at this bumpyness, try 4 to match tenebrae, higher values increase depth, requires r_restart to take effect"};
273 cvar_t r_shadow_bumpscale_bumpmap = {0, "r_shadow_bumpscale_bumpmap", "4", "what magnitude to interpret _bump.tga textures as, higher values increase depth, requires r_restart to take effect"};
274 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
275 cvar_t r_shadow_deferred = {CVAR_SAVE, "r_shadow_deferred", "0", "uses image-based lighting instead of geometry-based lighting, the method used renders a depth image and a normalmap image, renders lights into separate diffuse and specular images, and then combines this into the normal rendering, requires r_shadow_shadowmapping"};
276 cvar_t r_shadow_deferred_8bitrange = {CVAR_SAVE, "r_shadow_deferred_8bitrange", "2", "dynamic range of image-based lighting when using 32bit color (does not apply to fp)"};
277 //cvar_t r_shadow_deferred_fp = {CVAR_SAVE, "r_shadow_deferred_fp", "0", "use 16bit (1) or 32bit (2) floating point for accumulation of image-based lighting"};
278 cvar_t r_shadow_usenormalmap = {CVAR_SAVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"};
279 cvar_t r_shadow_gloss = {CVAR_SAVE, "r_shadow_gloss", "1", "0 disables gloss (specularity) rendering, 1 uses gloss if textures are found, 2 forces a flat metallic specular effect on everything without textures (similar to tenebrae)"};
280 cvar_t r_shadow_gloss2intensity = {0, "r_shadow_gloss2intensity", "0.125", "how bright the forced flat gloss should look if r_shadow_gloss is 2"};
281 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
282 cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
283 cvar_t r_shadow_gloss2exponent = {0, "r_shadow_gloss2exponent", "32", "same as r_shadow_glossexponent but for forced gloss (gloss 2) surfaces"};
284 cvar_t r_shadow_glossexact = {0, "r_shadow_glossexact", "0", "use exact reflection math for gloss (slightly slower, but should look a tad better)"};
285 cvar_t r_shadow_lightattenuationdividebias = {0, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"};
286 cvar_t r_shadow_lightattenuationlinearscale = {0, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"};
287 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
288 cvar_t r_shadow_lightradiusscale = {0, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
289 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "0", "how far to cast shadows"};
290 cvar_t r_shadow_frontsidecasting = {0, "r_shadow_frontsidecasting", "1", "whether to cast shadows from illuminated triangles (front side of model) or unlit triangles (back side of model)"};
291 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
292 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
293 cvar_t r_shadow_realtime_dlight_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
294 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
295 cvar_t r_shadow_realtime_world = {CVAR_SAVE, "r_shadow_realtime_world", "0", "enables rendering of full world lighting (whether loaded from the map, or a .rtlights file, or a .ent file, or a .lights file produced by hlight)"};
296 cvar_t r_shadow_realtime_world_lightmaps = {CVAR_SAVE, "r_shadow_realtime_world_lightmaps", "0", "brightness to render lightmaps when using full world lighting, try 0.5 for a tenebrae-like appearance"};
297 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
298 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
299 cvar_t r_shadow_realtime_world_compileshadow = {0, "r_shadow_realtime_world_compileshadow", "1", "enables compilation of shadows from world lights for higher performance rendering"};
300 cvar_t r_shadow_realtime_world_compilesvbsp = {0, "r_shadow_realtime_world_compilesvbsp", "1", "enables svbsp optimization during compilation (slower than compileportalculling but more exact)"};
301 cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "0", "enables portal-based culling optimization during compilation (overrides compilesvbsp)"};
302 cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1", "use scissor optimization of light rendering (restricts rendering to the portion of the screen affected by the light)"};
303 cvar_t r_shadow_shadowmapping = {CVAR_SAVE, "r_shadow_shadowmapping", "0", "enables use of shadowmapping (depth texture sampling) instead of stencil shadow volumes, requires gl_fbo 1"};
304 cvar_t r_shadow_shadowmapping_texturetype = {CVAR_SAVE, "r_shadow_shadowmapping_texturetype", "-1", "shadowmap texture types: -1 = auto-select, 0 = 2D, 1 = rectangle, 2 = cubemap"};
305 cvar_t r_shadow_shadowmapping_filterquality = {CVAR_SAVE, "r_shadow_shadowmapping_filterquality", "-1", "shadowmap filter modes: -1 = auto-select, 0 = no filtering, 1 = bilinear, 2 = bilinear 2x2 blur (fast), 3 = 3x3 blur (moderate), 4 = 4x4 blur (slow)"};
306 cvar_t r_shadow_shadowmapping_depthbits = {CVAR_SAVE, "r_shadow_shadowmapping_depthbits", "24", "requested minimum shadowmap texture depth bits"};
307 cvar_t r_shadow_shadowmapping_vsdct = {CVAR_SAVE, "r_shadow_shadowmapping_vsdct", "1", "enables use of virtual shadow depth cube texture"};
308 cvar_t r_shadow_shadowmapping_minsize = {CVAR_SAVE, "r_shadow_shadowmapping_minsize", "32", "shadowmap size limit"};
309 cvar_t r_shadow_shadowmapping_maxsize = {CVAR_SAVE, "r_shadow_shadowmapping_maxsize", "512", "shadowmap size limit"};
310 cvar_t r_shadow_shadowmapping_precision = {CVAR_SAVE, "r_shadow_shadowmapping_precision", "1", "makes shadowmaps have a maximum resolution of this number of pixels per light source radius unit such that, for example, at precision 0.5 a light with radius 200 will have a maximum resolution of 100 pixels"};
311 //cvar_t r_shadow_shadowmapping_lod_bias = {CVAR_SAVE, "r_shadow_shadowmapping_lod_bias", "16", "shadowmap size bias"};
312 //cvar_t r_shadow_shadowmapping_lod_scale = {CVAR_SAVE, "r_shadow_shadowmapping_lod_scale", "128", "shadowmap size scaling parameter"};
313 cvar_t r_shadow_shadowmapping_bordersize = {CVAR_SAVE, "r_shadow_shadowmapping_bordersize", "4", "shadowmap size bias for filtering"};
314 cvar_t r_shadow_shadowmapping_nearclip = {CVAR_SAVE, "r_shadow_shadowmapping_nearclip", "1", "shadowmap nearclip in world units"};
315 cvar_t r_shadow_shadowmapping_bias = {CVAR_SAVE, "r_shadow_shadowmapping_bias", "0.03", "shadowmap bias parameter (this is multiplied by nearclip * 1024 / lodsize)"};
316 cvar_t r_shadow_shadowmapping_polygonfactor = {CVAR_SAVE, "r_shadow_shadowmapping_polygonfactor", "2", "slope-dependent shadowmapping bias"};
317 cvar_t r_shadow_shadowmapping_polygonoffset = {CVAR_SAVE, "r_shadow_shadowmapping_polygonoffset", "0", "constant shadowmapping bias"};
318 cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
319 cvar_t r_shadow_polygonoffset = {0, "r_shadow_polygonoffset", "1", "how much to push shadow volumes into the distance when rendering, to reduce chances of zfighting artifacts (should not be less than 0)"};
320 cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "1", "use 3D voxel textures for spherical attenuation rather than cylindrical (does not affect OpenGL 2.0 render path)"};
321 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "1", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
322 cvar_t r_coronas_occlusionsizescale = {CVAR_SAVE, "r_coronas_occlusionsizescale", "0.1", "size of light source for corona occlusion checksm the proportion of hidden pixels controls corona intensity"};
323 cvar_t r_coronas_occlusionquery = {CVAR_SAVE, "r_coronas_occlusionquery", "1", "use GL_ARB_occlusion_query extension if supported (fades coronas according to visibility)"};
324 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
325 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
326 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
327 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
328 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
329 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
330 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
331 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
332 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
334 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
335 #define ATTENTABLESIZE 256
336 // 1D gradient, 2D circle and 3D sphere attenuation textures
337 #define ATTEN1DSIZE 32
338 #define ATTEN2DSIZE 64
339 #define ATTEN3DSIZE 32
341 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
342 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
343 static float r_shadow_attentable[ATTENTABLESIZE+1];
345 rtlight_t *r_shadow_compilingrtlight;
346 static memexpandablearray_t r_shadow_worldlightsarray;
347 dlight_t *r_shadow_selectedlight;
348 dlight_t r_shadow_bufferlight;
349 vec3_t r_editlights_cursorlocation;
351 extern int con_vislines;
353 typedef struct cubemapinfo_s
360 static int numcubemaps;
361 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
363 void R_Shadow_UncompileWorldLights(void);
364 void R_Shadow_ClearWorldLights(void);
365 void R_Shadow_SaveWorldLights(void);
366 void R_Shadow_LoadWorldLights(void);
367 void R_Shadow_LoadLightsFile(void);
368 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
369 void R_Shadow_EditLights_Reload_f(void);
370 void R_Shadow_ValidateCvars(void);
371 static void R_Shadow_MakeTextures(void);
373 #define EDLIGHTSPRSIZE 8
374 skinframe_t *r_editlights_sprcursor;
375 skinframe_t *r_editlights_sprlight;
376 skinframe_t *r_editlights_sprnoshadowlight;
377 skinframe_t *r_editlights_sprcubemaplight;
378 skinframe_t *r_editlights_sprcubemapnoshadowlight;
379 skinframe_t *r_editlights_sprselection;
381 void R_Shadow_SetShadowMode(void)
383 r_shadow_shadowmapmaxsize = bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4);
384 r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer != 0;
385 r_shadow_shadowmapfilterquality = r_shadow_shadowmapping_filterquality.integer;
386 r_shadow_shadowmaptexturetype = r_shadow_shadowmapping_texturetype.integer;
387 r_shadow_shadowmapdepthbits = r_shadow_shadowmapping_depthbits.integer;
388 r_shadow_shadowmapborder = bound(0, r_shadow_shadowmapping_bordersize.integer, 16);
389 r_shadow_shadowmaplod = -1;
390 r_shadow_shadowmapsize = 0;
391 r_shadow_shadowmapsampler = false;
392 r_shadow_shadowmappcf = 0;
393 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
394 switch(vid.renderpath)
396 case RENDERPATH_GL20:
397 case RENDERPATH_CGGL:
398 if ((r_shadow_shadowmapping.integer || r_shadow_deferred.integer) && vid.support.ext_framebuffer_object)
400 if(r_shadow_shadowmapfilterquality < 0)
402 if(strstr(gl_vendor, "NVIDIA"))
404 r_shadow_shadowmapsampler = vid.support.arb_shadow;
405 r_shadow_shadowmappcf = 1;
407 else if(vid.support.amd_texture_texture4 || vid.support.arb_texture_gather)
408 r_shadow_shadowmappcf = 1;
409 else if(strstr(gl_vendor, "ATI"))
410 r_shadow_shadowmappcf = 1;
412 r_shadow_shadowmapsampler = vid.support.arb_shadow;
416 switch (r_shadow_shadowmapfilterquality)
419 r_shadow_shadowmapsampler = vid.support.arb_shadow;
422 r_shadow_shadowmapsampler = vid.support.arb_shadow;
423 r_shadow_shadowmappcf = 1;
426 r_shadow_shadowmappcf = 1;
429 r_shadow_shadowmappcf = 2;
433 switch (r_shadow_shadowmaptexturetype)
436 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
439 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE;
442 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE;
445 if((vid.support.amd_texture_texture4 || vid.support.arb_texture_gather) && r_shadow_shadowmappcf && !r_shadow_shadowmapsampler)
446 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
447 else if(vid.support.arb_texture_rectangle)
448 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE;
450 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
455 case RENDERPATH_GL13:
457 case RENDERPATH_GL11:
462 void R_Shadow_FreeShadowMaps(void)
466 R_Shadow_SetShadowMode();
468 if (!vid.support.ext_framebuffer_object || !vid.support.arb_fragment_shader)
473 if (r_shadow_fborectangle)
474 qglDeleteFramebuffersEXT(1, &r_shadow_fborectangle);CHECKGLERROR
475 r_shadow_fborectangle = 0;
478 qglDeleteFramebuffersEXT(1, &r_shadow_fbo2d);CHECKGLERROR
480 for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
481 if (r_shadow_fbocubeside[i])
482 qglDeleteFramebuffersEXT(1, &r_shadow_fbocubeside[i]);CHECKGLERROR
483 memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
485 if (r_shadow_shadowmaprectangletexture)
486 R_FreeTexture(r_shadow_shadowmaprectangletexture);
487 r_shadow_shadowmaprectangletexture = NULL;
489 if (r_shadow_shadowmap2dtexture)
490 R_FreeTexture(r_shadow_shadowmap2dtexture);
491 r_shadow_shadowmap2dtexture = NULL;
493 for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
494 if (r_shadow_shadowmapcubetexture[i])
495 R_FreeTexture(r_shadow_shadowmapcubetexture[i]);
496 memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
498 if (r_shadow_shadowmapvsdcttexture)
499 R_FreeTexture(r_shadow_shadowmapvsdcttexture);
500 r_shadow_shadowmapvsdcttexture = NULL;
505 void r_shadow_start(void)
507 // allocate vertex processing arrays
509 r_shadow_attenuationgradienttexture = NULL;
510 r_shadow_attenuation2dtexture = NULL;
511 r_shadow_attenuation3dtexture = NULL;
512 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
513 r_shadow_shadowmaprectangletexture = NULL;
514 r_shadow_shadowmap2dtexture = NULL;
515 memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
516 r_shadow_shadowmapvsdcttexture = NULL;
517 r_shadow_shadowmapmaxsize = 0;
518 r_shadow_shadowmapsize = 0;
519 r_shadow_shadowmaplod = 0;
520 r_shadow_shadowmapfilterquality = -1;
521 r_shadow_shadowmaptexturetype = -1;
522 r_shadow_shadowmapdepthbits = 0;
523 r_shadow_shadowmapvsdct = false;
524 r_shadow_shadowmapsampler = false;
525 r_shadow_shadowmappcf = 0;
526 r_shadow_fborectangle = 0;
528 memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
530 R_Shadow_FreeShadowMaps();
532 r_shadow_texturepool = NULL;
533 r_shadow_filters_texturepool = NULL;
534 R_Shadow_ValidateCvars();
535 R_Shadow_MakeTextures();
536 maxshadowtriangles = 0;
537 shadowelements = NULL;
538 maxshadowvertices = 0;
539 shadowvertex3f = NULL;
547 shadowmarklist = NULL;
552 shadowsideslist = NULL;
553 r_shadow_buffer_numleafpvsbytes = 0;
554 r_shadow_buffer_visitingleafpvs = NULL;
555 r_shadow_buffer_leafpvs = NULL;
556 r_shadow_buffer_leaflist = NULL;
557 r_shadow_buffer_numsurfacepvsbytes = 0;
558 r_shadow_buffer_surfacepvs = NULL;
559 r_shadow_buffer_surfacelist = NULL;
560 r_shadow_buffer_surfacesides = NULL;
561 r_shadow_buffer_numshadowtrispvsbytes = 0;
562 r_shadow_buffer_shadowtrispvs = NULL;
563 r_shadow_buffer_numlighttrispvsbytes = 0;
564 r_shadow_buffer_lighttrispvs = NULL;
566 r_shadow_usingdeferredprepass = false;
567 r_shadow_prepass_width = r_shadow_prepass_height = 0;
570 static void R_Shadow_FreeDeferred(void);
571 void r_shadow_shutdown(void)
574 R_Shadow_UncompileWorldLights();
576 R_Shadow_FreeShadowMaps();
578 r_shadow_usingdeferredprepass = false;
579 if (r_shadow_prepass_width)
580 R_Shadow_FreeDeferred();
581 r_shadow_prepass_width = r_shadow_prepass_height = 0;
585 r_shadow_attenuationgradienttexture = NULL;
586 r_shadow_attenuation2dtexture = NULL;
587 r_shadow_attenuation3dtexture = NULL;
588 R_FreeTexturePool(&r_shadow_texturepool);
589 R_FreeTexturePool(&r_shadow_filters_texturepool);
590 maxshadowtriangles = 0;
592 Mem_Free(shadowelements);
593 shadowelements = NULL;
595 Mem_Free(shadowvertex3f);
596 shadowvertex3f = NULL;
599 Mem_Free(vertexupdate);
602 Mem_Free(vertexremap);
608 Mem_Free(shadowmark);
611 Mem_Free(shadowmarklist);
612 shadowmarklist = NULL;
617 Mem_Free(shadowsides);
620 Mem_Free(shadowsideslist);
621 shadowsideslist = NULL;
622 r_shadow_buffer_numleafpvsbytes = 0;
623 if (r_shadow_buffer_visitingleafpvs)
624 Mem_Free(r_shadow_buffer_visitingleafpvs);
625 r_shadow_buffer_visitingleafpvs = NULL;
626 if (r_shadow_buffer_leafpvs)
627 Mem_Free(r_shadow_buffer_leafpvs);
628 r_shadow_buffer_leafpvs = NULL;
629 if (r_shadow_buffer_leaflist)
630 Mem_Free(r_shadow_buffer_leaflist);
631 r_shadow_buffer_leaflist = NULL;
632 r_shadow_buffer_numsurfacepvsbytes = 0;
633 if (r_shadow_buffer_surfacepvs)
634 Mem_Free(r_shadow_buffer_surfacepvs);
635 r_shadow_buffer_surfacepvs = NULL;
636 if (r_shadow_buffer_surfacelist)
637 Mem_Free(r_shadow_buffer_surfacelist);
638 r_shadow_buffer_surfacelist = NULL;
639 if (r_shadow_buffer_surfacesides)
640 Mem_Free(r_shadow_buffer_surfacesides);
641 r_shadow_buffer_surfacesides = NULL;
642 r_shadow_buffer_numshadowtrispvsbytes = 0;
643 if (r_shadow_buffer_shadowtrispvs)
644 Mem_Free(r_shadow_buffer_shadowtrispvs);
645 r_shadow_buffer_numlighttrispvsbytes = 0;
646 if (r_shadow_buffer_lighttrispvs)
647 Mem_Free(r_shadow_buffer_lighttrispvs);
650 void r_shadow_newmap(void)
652 if (r_shadow_lightcorona) R_SkinFrame_MarkUsed(r_shadow_lightcorona);
653 if (r_editlights_sprcursor) R_SkinFrame_MarkUsed(r_editlights_sprcursor);
654 if (r_editlights_sprlight) R_SkinFrame_MarkUsed(r_editlights_sprlight);
655 if (r_editlights_sprnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprnoshadowlight);
656 if (r_editlights_sprcubemaplight) R_SkinFrame_MarkUsed(r_editlights_sprcubemaplight);
657 if (r_editlights_sprcubemapnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprcubemapnoshadowlight);
658 if (r_editlights_sprselection) R_SkinFrame_MarkUsed(r_editlights_sprselection);
659 if (cl.worldmodel && strncmp(cl.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
660 R_Shadow_EditLights_Reload_f();
663 void R_Shadow_Init(void)
665 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
666 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
667 Cvar_RegisterVariable(&r_shadow_usenormalmap);
668 Cvar_RegisterVariable(&r_shadow_debuglight);
669 Cvar_RegisterVariable(&r_shadow_deferred);
670 Cvar_RegisterVariable(&r_shadow_deferred_8bitrange);
671 // Cvar_RegisterVariable(&r_shadow_deferred_fp);
672 Cvar_RegisterVariable(&r_shadow_gloss);
673 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
674 Cvar_RegisterVariable(&r_shadow_glossintensity);
675 Cvar_RegisterVariable(&r_shadow_glossexponent);
676 Cvar_RegisterVariable(&r_shadow_gloss2exponent);
677 Cvar_RegisterVariable(&r_shadow_glossexact);
678 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
679 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
680 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
681 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
682 Cvar_RegisterVariable(&r_shadow_projectdistance);
683 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
684 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
685 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
686 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
687 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
688 Cvar_RegisterVariable(&r_shadow_realtime_world);
689 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
690 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
691 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
692 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
693 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
694 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
695 Cvar_RegisterVariable(&r_shadow_scissor);
696 Cvar_RegisterVariable(&r_shadow_shadowmapping);
697 Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
698 Cvar_RegisterVariable(&r_shadow_shadowmapping_texturetype);
699 Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
700 Cvar_RegisterVariable(&r_shadow_shadowmapping_depthbits);
701 Cvar_RegisterVariable(&r_shadow_shadowmapping_precision);
702 Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
703 Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
704 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
705 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
706 Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
707 Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
708 Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
709 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonfactor);
710 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonoffset);
711 Cvar_RegisterVariable(&r_shadow_polygonfactor);
712 Cvar_RegisterVariable(&r_shadow_polygonoffset);
713 Cvar_RegisterVariable(&r_shadow_texture3d);
714 Cvar_RegisterVariable(&r_coronas);
715 Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
716 Cvar_RegisterVariable(&r_coronas_occlusionquery);
717 Cvar_RegisterVariable(&gl_flashblend);
718 Cvar_RegisterVariable(&gl_ext_separatestencil);
719 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
720 if (gamemode == GAME_TENEBRAE)
722 Cvar_SetValue("r_shadow_gloss", 2);
723 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
725 R_Shadow_EditLights_Init();
726 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
727 maxshadowtriangles = 0;
728 shadowelements = NULL;
729 maxshadowvertices = 0;
730 shadowvertex3f = NULL;
738 shadowmarklist = NULL;
743 shadowsideslist = NULL;
744 r_shadow_buffer_numleafpvsbytes = 0;
745 r_shadow_buffer_visitingleafpvs = NULL;
746 r_shadow_buffer_leafpvs = NULL;
747 r_shadow_buffer_leaflist = NULL;
748 r_shadow_buffer_numsurfacepvsbytes = 0;
749 r_shadow_buffer_surfacepvs = NULL;
750 r_shadow_buffer_surfacelist = NULL;
751 r_shadow_buffer_surfacesides = NULL;
752 r_shadow_buffer_shadowtrispvs = NULL;
753 r_shadow_buffer_lighttrispvs = NULL;
754 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
757 matrix4x4_t matrix_attenuationxyz =
760 {0.5, 0.0, 0.0, 0.5},
761 {0.0, 0.5, 0.0, 0.5},
762 {0.0, 0.0, 0.5, 0.5},
767 matrix4x4_t matrix_attenuationz =
770 {0.0, 0.0, 0.5, 0.5},
771 {0.0, 0.0, 0.0, 0.5},
772 {0.0, 0.0, 0.0, 0.5},
777 void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles, int vertscale, int triscale)
779 numvertices = ((numvertices + 255) & ~255) * vertscale;
780 numtriangles = ((numtriangles + 255) & ~255) * triscale;
781 // make sure shadowelements is big enough for this volume
782 if (maxshadowtriangles < numtriangles)
784 maxshadowtriangles = numtriangles;
786 Mem_Free(shadowelements);
787 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[3]));
789 // make sure shadowvertex3f is big enough for this volume
790 if (maxshadowvertices < numvertices)
792 maxshadowvertices = numvertices;
794 Mem_Free(shadowvertex3f);
795 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[3]));
799 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
801 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
802 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
803 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
804 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
805 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
807 if (r_shadow_buffer_visitingleafpvs)
808 Mem_Free(r_shadow_buffer_visitingleafpvs);
809 if (r_shadow_buffer_leafpvs)
810 Mem_Free(r_shadow_buffer_leafpvs);
811 if (r_shadow_buffer_leaflist)
812 Mem_Free(r_shadow_buffer_leaflist);
813 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
814 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
815 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
816 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
818 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
820 if (r_shadow_buffer_surfacepvs)
821 Mem_Free(r_shadow_buffer_surfacepvs);
822 if (r_shadow_buffer_surfacelist)
823 Mem_Free(r_shadow_buffer_surfacelist);
824 if (r_shadow_buffer_surfacesides)
825 Mem_Free(r_shadow_buffer_surfacesides);
826 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
827 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
828 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
829 r_shadow_buffer_surfacesides = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
831 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
833 if (r_shadow_buffer_shadowtrispvs)
834 Mem_Free(r_shadow_buffer_shadowtrispvs);
835 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
836 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
838 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
840 if (r_shadow_buffer_lighttrispvs)
841 Mem_Free(r_shadow_buffer_lighttrispvs);
842 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
843 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
847 void R_Shadow_PrepareShadowMark(int numtris)
849 // make sure shadowmark is big enough for this volume
850 if (maxshadowmark < numtris)
852 maxshadowmark = numtris;
854 Mem_Free(shadowmark);
856 Mem_Free(shadowmarklist);
857 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
858 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
862 // if shadowmarkcount wrapped we clear the array and adjust accordingly
863 if (shadowmarkcount == 0)
866 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
871 void R_Shadow_PrepareShadowSides(int numtris)
873 if (maxshadowsides < numtris)
875 maxshadowsides = numtris;
877 Mem_Free(shadowsides);
879 Mem_Free(shadowsideslist);
880 shadowsides = (unsigned char *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsides));
881 shadowsideslist = (int *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsideslist));
886 static int R_Shadow_ConstructShadowVolume_ZFail(int innumvertices, int innumtris, const int *inelement3i, const int *inneighbor3i, const float *invertex3f, int *outnumvertices, int *outelement3i, float *outvertex3f, const float *projectorigin, const float *projectdirection, float projectdistance, int numshadowmarktris, const int *shadowmarktris)
889 int outtriangles = 0, outvertices = 0;
892 float ratio, direction[3], projectvector[3];
894 if (projectdirection)
895 VectorScale(projectdirection, projectdistance, projectvector);
897 VectorClear(projectvector);
899 // create the vertices
900 if (projectdirection)
902 for (i = 0;i < numshadowmarktris;i++)
904 element = inelement3i + shadowmarktris[i] * 3;
905 for (j = 0;j < 3;j++)
907 if (vertexupdate[element[j]] != vertexupdatenum)
909 vertexupdate[element[j]] = vertexupdatenum;
910 vertexremap[element[j]] = outvertices;
911 vertex = invertex3f + element[j] * 3;
912 // project one copy of the vertex according to projectvector
913 VectorCopy(vertex, outvertex3f);
914 VectorAdd(vertex, projectvector, (outvertex3f + 3));
923 for (i = 0;i < numshadowmarktris;i++)
925 element = inelement3i + shadowmarktris[i] * 3;
926 for (j = 0;j < 3;j++)
928 if (vertexupdate[element[j]] != vertexupdatenum)
930 vertexupdate[element[j]] = vertexupdatenum;
931 vertexremap[element[j]] = outvertices;
932 vertex = invertex3f + element[j] * 3;
933 // project one copy of the vertex to the sphere radius of the light
934 // (FIXME: would projecting it to the light box be better?)
935 VectorSubtract(vertex, projectorigin, direction);
936 ratio = projectdistance / VectorLength(direction);
937 VectorCopy(vertex, outvertex3f);
938 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
946 if (r_shadow_frontsidecasting.integer)
948 for (i = 0;i < numshadowmarktris;i++)
950 int remappedelement[3];
952 const int *neighbortriangle;
954 markindex = shadowmarktris[i] * 3;
955 element = inelement3i + markindex;
956 neighbortriangle = inneighbor3i + markindex;
957 // output the front and back triangles
958 outelement3i[0] = vertexremap[element[0]];
959 outelement3i[1] = vertexremap[element[1]];
960 outelement3i[2] = vertexremap[element[2]];
961 outelement3i[3] = vertexremap[element[2]] + 1;
962 outelement3i[4] = vertexremap[element[1]] + 1;
963 outelement3i[5] = vertexremap[element[0]] + 1;
967 // output the sides (facing outward from this triangle)
968 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
970 remappedelement[0] = vertexremap[element[0]];
971 remappedelement[1] = vertexremap[element[1]];
972 outelement3i[0] = remappedelement[1];
973 outelement3i[1] = remappedelement[0];
974 outelement3i[2] = remappedelement[0] + 1;
975 outelement3i[3] = remappedelement[1];
976 outelement3i[4] = remappedelement[0] + 1;
977 outelement3i[5] = remappedelement[1] + 1;
982 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
984 remappedelement[1] = vertexremap[element[1]];
985 remappedelement[2] = vertexremap[element[2]];
986 outelement3i[0] = remappedelement[2];
987 outelement3i[1] = remappedelement[1];
988 outelement3i[2] = remappedelement[1] + 1;
989 outelement3i[3] = remappedelement[2];
990 outelement3i[4] = remappedelement[1] + 1;
991 outelement3i[5] = remappedelement[2] + 1;
996 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
998 remappedelement[0] = vertexremap[element[0]];
999 remappedelement[2] = vertexremap[element[2]];
1000 outelement3i[0] = remappedelement[0];
1001 outelement3i[1] = remappedelement[2];
1002 outelement3i[2] = remappedelement[2] + 1;
1003 outelement3i[3] = remappedelement[0];
1004 outelement3i[4] = remappedelement[2] + 1;
1005 outelement3i[5] = remappedelement[0] + 1;
1014 for (i = 0;i < numshadowmarktris;i++)
1016 int remappedelement[3];
1018 const int *neighbortriangle;
1020 markindex = shadowmarktris[i] * 3;
1021 element = inelement3i + markindex;
1022 neighbortriangle = inneighbor3i + markindex;
1023 // output the front and back triangles
1024 outelement3i[0] = vertexremap[element[2]];
1025 outelement3i[1] = vertexremap[element[1]];
1026 outelement3i[2] = vertexremap[element[0]];
1027 outelement3i[3] = vertexremap[element[0]] + 1;
1028 outelement3i[4] = vertexremap[element[1]] + 1;
1029 outelement3i[5] = vertexremap[element[2]] + 1;
1033 // output the sides (facing outward from this triangle)
1034 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
1036 remappedelement[0] = vertexremap[element[0]];
1037 remappedelement[1] = vertexremap[element[1]];
1038 outelement3i[0] = remappedelement[0];
1039 outelement3i[1] = remappedelement[1];
1040 outelement3i[2] = remappedelement[1] + 1;
1041 outelement3i[3] = remappedelement[0];
1042 outelement3i[4] = remappedelement[1] + 1;
1043 outelement3i[5] = remappedelement[0] + 1;
1048 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1050 remappedelement[1] = vertexremap[element[1]];
1051 remappedelement[2] = vertexremap[element[2]];
1052 outelement3i[0] = remappedelement[1];
1053 outelement3i[1] = remappedelement[2];
1054 outelement3i[2] = remappedelement[2] + 1;
1055 outelement3i[3] = remappedelement[1];
1056 outelement3i[4] = remappedelement[2] + 1;
1057 outelement3i[5] = remappedelement[1] + 1;
1062 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1064 remappedelement[0] = vertexremap[element[0]];
1065 remappedelement[2] = vertexremap[element[2]];
1066 outelement3i[0] = remappedelement[2];
1067 outelement3i[1] = remappedelement[0];
1068 outelement3i[2] = remappedelement[0] + 1;
1069 outelement3i[3] = remappedelement[2];
1070 outelement3i[4] = remappedelement[0] + 1;
1071 outelement3i[5] = remappedelement[2] + 1;
1079 *outnumvertices = outvertices;
1080 return outtriangles;
1083 static int R_Shadow_ConstructShadowVolume_ZPass(int innumvertices, int innumtris, const int *inelement3i, const int *inneighbor3i, const float *invertex3f, int *outnumvertices, int *outelement3i, float *outvertex3f, const float *projectorigin, const float *projectdirection, float projectdistance, int numshadowmarktris, const int *shadowmarktris)
1086 int outtriangles = 0, outvertices = 0;
1088 const float *vertex;
1089 float ratio, direction[3], projectvector[3];
1092 if (projectdirection)
1093 VectorScale(projectdirection, projectdistance, projectvector);
1095 VectorClear(projectvector);
1097 for (i = 0;i < numshadowmarktris;i++)
1099 int remappedelement[3];
1101 const int *neighbortriangle;
1103 markindex = shadowmarktris[i] * 3;
1104 neighbortriangle = inneighbor3i + markindex;
1105 side[0] = shadowmark[neighbortriangle[0]] == shadowmarkcount;
1106 side[1] = shadowmark[neighbortriangle[1]] == shadowmarkcount;
1107 side[2] = shadowmark[neighbortriangle[2]] == shadowmarkcount;
1108 if (side[0] + side[1] + side[2] == 0)
1112 element = inelement3i + markindex;
1114 // create the vertices
1115 for (j = 0;j < 3;j++)
1117 if (side[j] + side[j+1] == 0)
1120 if (vertexupdate[k] != vertexupdatenum)
1122 vertexupdate[k] = vertexupdatenum;
1123 vertexremap[k] = outvertices;
1124 vertex = invertex3f + k * 3;
1125 VectorCopy(vertex, outvertex3f);
1126 if (projectdirection)
1128 // project one copy of the vertex according to projectvector
1129 VectorAdd(vertex, projectvector, (outvertex3f + 3));
1133 // project one copy of the vertex to the sphere radius of the light
1134 // (FIXME: would projecting it to the light box be better?)
1135 VectorSubtract(vertex, projectorigin, direction);
1136 ratio = projectdistance / VectorLength(direction);
1137 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1144 // output the sides (facing outward from this triangle)
1147 remappedelement[0] = vertexremap[element[0]];
1148 remappedelement[1] = vertexremap[element[1]];
1149 outelement3i[0] = remappedelement[1];
1150 outelement3i[1] = remappedelement[0];
1151 outelement3i[2] = remappedelement[0] + 1;
1152 outelement3i[3] = remappedelement[1];
1153 outelement3i[4] = remappedelement[0] + 1;
1154 outelement3i[5] = remappedelement[1] + 1;
1161 remappedelement[1] = vertexremap[element[1]];
1162 remappedelement[2] = vertexremap[element[2]];
1163 outelement3i[0] = remappedelement[2];
1164 outelement3i[1] = remappedelement[1];
1165 outelement3i[2] = remappedelement[1] + 1;
1166 outelement3i[3] = remappedelement[2];
1167 outelement3i[4] = remappedelement[1] + 1;
1168 outelement3i[5] = remappedelement[2] + 1;
1175 remappedelement[0] = vertexremap[element[0]];
1176 remappedelement[2] = vertexremap[element[2]];
1177 outelement3i[0] = remappedelement[0];
1178 outelement3i[1] = remappedelement[2];
1179 outelement3i[2] = remappedelement[2] + 1;
1180 outelement3i[3] = remappedelement[0];
1181 outelement3i[4] = remappedelement[2] + 1;
1182 outelement3i[5] = remappedelement[0] + 1;
1189 *outnumvertices = outvertices;
1190 return outtriangles;
1193 void R_Shadow_MarkVolumeFromBox(int firsttriangle, int numtris, const float *invertex3f, const int *elements, const vec3_t projectorigin, const vec3_t projectdirection, const vec3_t lightmins, const vec3_t lightmaxs, const vec3_t surfacemins, const vec3_t surfacemaxs)
1199 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1201 tend = firsttriangle + numtris;
1202 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1204 // surface box entirely inside light box, no box cull
1205 if (projectdirection)
1207 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1209 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
1210 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1211 shadowmarklist[numshadowmark++] = t;
1216 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1217 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
1218 shadowmarklist[numshadowmark++] = t;
1223 // surface box not entirely inside light box, cull each triangle
1224 if (projectdirection)
1226 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1228 v[0] = invertex3f + e[0] * 3;
1229 v[1] = invertex3f + e[1] * 3;
1230 v[2] = invertex3f + e[2] * 3;
1231 TriangleNormal(v[0], v[1], v[2], normal);
1232 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1233 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1234 shadowmarklist[numshadowmark++] = t;
1239 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1241 v[0] = invertex3f + e[0] * 3;
1242 v[1] = invertex3f + e[1] * 3;
1243 v[2] = invertex3f + e[2] * 3;
1244 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1245 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1246 shadowmarklist[numshadowmark++] = t;
1252 qboolean R_Shadow_UseZPass(vec3_t mins, vec3_t maxs)
1257 if (r_shadow_compilingrtlight || !r_shadow_frontsidecasting.integer || !r_shadow_usezpassifpossible.integer)
1259 // check if the shadow volume intersects the near plane
1261 // a ray between the eye and light origin may intersect the caster,
1262 // indicating that the shadow may touch the eye location, however we must
1263 // test the near plane (a polygon), not merely the eye location, so it is
1264 // easiest to enlarge the caster bounding shape slightly for this.
1270 void R_Shadow_VolumeFromList(int numverts, int numtris, const float *invertex3f, const int *elements, const int *neighbors, const vec3_t projectorigin, const vec3_t projectdirection, float projectdistance, int nummarktris, const int *marktris, vec3_t trismins, vec3_t trismaxs)
1272 int i, tris, outverts;
1273 if (projectdistance < 0.1)
1275 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
1278 if (!numverts || !nummarktris)
1280 // make sure shadowelements is big enough for this volume
1281 if (maxshadowtriangles < nummarktris*8 || maxshadowvertices < numverts*2)
1282 R_Shadow_ResizeShadowArrays(numverts, nummarktris, 2, 8);
1284 if (maxvertexupdate < numverts)
1286 maxvertexupdate = numverts;
1288 Mem_Free(vertexupdate);
1290 Mem_Free(vertexremap);
1291 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1292 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1293 vertexupdatenum = 0;
1296 if (vertexupdatenum == 0)
1298 vertexupdatenum = 1;
1299 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
1300 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
1303 for (i = 0;i < nummarktris;i++)
1304 shadowmark[marktris[i]] = shadowmarkcount;
1306 if (r_shadow_compilingrtlight)
1308 // if we're compiling an rtlight, capture the mesh
1309 //tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1310 //Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zpass, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1311 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1312 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zfail, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1314 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
1316 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1317 R_Mesh_VertexPointer(shadowvertex3f, 0, 0);
1318 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1322 // decide which type of shadow to generate and set stencil mode
1323 R_Shadow_RenderMode_StencilShadowVolumes(R_Shadow_UseZPass(trismins, trismaxs));
1324 // generate the sides or a solid volume, depending on type
1325 if (r_shadow_rendermode >= R_SHADOW_RENDERMODE_ZPASS_STENCIL && r_shadow_rendermode <= R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE)
1326 tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1328 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1329 r_refdef.stats.lights_dynamicshadowtriangles += tris;
1330 r_refdef.stats.lights_shadowtriangles += tris;
1332 R_Mesh_VertexPointer(shadowvertex3f, 0, 0);
1333 GL_LockArrays(0, outverts);
1334 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
1336 // increment stencil if frontface is infront of depthbuffer
1337 GL_CullFace(r_refdef.view.cullface_front);
1338 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1339 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1340 // decrement stencil if backface is infront of depthbuffer
1341 GL_CullFace(r_refdef.view.cullface_back);
1342 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1344 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
1346 // decrement stencil if backface is behind depthbuffer
1347 GL_CullFace(r_refdef.view.cullface_front);
1348 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1349 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1350 // increment stencil if frontface is behind depthbuffer
1351 GL_CullFace(r_refdef.view.cullface_back);
1352 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1354 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1355 GL_LockArrays(0, 0);
1360 int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias)
1362 // p1, p2, p3 are in the cubemap's local coordinate system
1363 // bias = border/(size - border)
1366 float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1367 dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2),
1368 dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3);
1369 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1371 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1372 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1373 | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1374 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1376 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1377 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1378 | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1380 dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1381 dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2),
1382 dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3);
1383 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1385 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1386 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1387 | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1388 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1390 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1391 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1392 | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1394 dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1395 dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2),
1396 dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3);
1397 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1399 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1400 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1401 | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1402 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1404 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1405 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1406 | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1411 int R_Shadow_CalcBBoxSideMask(const vec3_t mins, const vec3_t maxs, const matrix4x4_t *worldtolight, const matrix4x4_t *radiustolight, float bias)
1413 vec3_t center, radius, lightcenter, lightradius, pmin, pmax;
1414 float dp1, dn1, ap1, an1, dp2, dn2, ap2, an2;
1417 VectorSubtract(maxs, mins, radius);
1418 VectorScale(radius, 0.5f, radius);
1419 VectorAdd(mins, radius, center);
1420 Matrix4x4_Transform(worldtolight, center, lightcenter);
1421 Matrix4x4_Transform3x3(radiustolight, radius, lightradius);
1422 VectorSubtract(lightcenter, lightradius, pmin);
1423 VectorAdd(lightcenter, lightradius, pmax);
1425 dp1 = pmax[0] + pmax[1], dn1 = pmax[0] - pmin[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1426 dp2 = pmin[0] + pmin[1], dn2 = pmin[0] - pmax[1], ap2 = fabs(dp2), an2 = fabs(dn2);
1427 if(ap1 > bias*an1 && ap2 > bias*an2)
1429 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1430 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1431 if(an1 > bias*ap1 && an2 > bias*ap2)
1433 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1434 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1436 dp1 = pmax[1] + pmax[2], dn1 = pmax[1] - pmin[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1437 dp2 = pmin[1] + pmin[2], dn2 = pmin[1] - pmax[2], ap2 = fabs(dp2), an2 = fabs(dn2);
1438 if(ap1 > bias*an1 && ap2 > bias*an2)
1440 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1441 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1442 if(an1 > bias*ap1 && an2 > bias*ap2)
1444 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1445 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1447 dp1 = pmax[2] + pmax[0], dn1 = pmax[2] - pmin[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1448 dp2 = pmin[2] + pmin[0], dn2 = pmin[2] - pmax[0], ap2 = fabs(dp2), an2 = fabs(dn2);
1449 if(ap1 > bias*an1 && ap2 > bias*an2)
1451 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1452 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1453 if(an1 > bias*ap1 && an2 > bias*ap2)
1455 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1456 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1461 #define R_Shadow_CalcEntitySideMask(ent, worldtolight, radiustolight, bias) R_Shadow_CalcBBoxSideMask((ent)->mins, (ent)->maxs, worldtolight, radiustolight, bias)
1463 int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
1465 // p is in the cubemap's local coordinate system
1466 // bias = border/(size - border)
1467 float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn);
1468 float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn);
1469 float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn);
1471 if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
1472 if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
1473 if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
1474 if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
1475 if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
1476 if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
1480 int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
1484 int sides = 0x3F, masks[6] = { 3<<4, 3<<4, 3<<0, 3<<0, 3<<2, 3<<2 };
1485 float scale = (size - 2*border)/size, len;
1486 float bias = border / (float)(size - border), dp, dn, ap, an;
1487 // check if cone enclosing side would cross frustum plane
1488 scale = 2 / (scale*scale + 2);
1489 for (i = 0;i < 5;i++)
1491 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) > -0.03125)
1493 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[i].normal, n);
1494 len = scale*VectorLength2(n);
1495 if(n[0]*n[0] > len) sides &= n[0] < 0 ? ~(1<<0) : ~(2 << 0);
1496 if(n[1]*n[1] > len) sides &= n[1] < 0 ? ~(1<<2) : ~(2 << 2);
1497 if(n[2]*n[2] > len) sides &= n[2] < 0 ? ~(1<<4) : ~(2 << 4);
1499 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[4]) >= r_refdef.farclip - r_refdef.nearclip + 0.03125)
1501 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[4].normal, n);
1502 len = scale*VectorLength(n);
1503 if(n[0]*n[0] > len) sides &= n[0] >= 0 ? ~(1<<0) : ~(2 << 0);
1504 if(n[1]*n[1] > len) sides &= n[1] >= 0 ? ~(1<<2) : ~(2 << 2);
1505 if(n[2]*n[2] > len) sides &= n[2] >= 0 ? ~(1<<4) : ~(2 << 4);
1507 // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results
1508 // check if frustum corners/origin cross plane sides
1509 for (i = 0;i < 5;i++)
1511 Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p);
1512 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn),
1513 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1514 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1515 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn),
1516 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1517 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1518 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn),
1519 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1520 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1522 return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5];
1525 int R_Shadow_ChooseSidesFromBox(int firsttriangle, int numtris, const float *invertex3f, const int *elements, const matrix4x4_t *worldtolight, const vec3_t projectorigin, const vec3_t projectdirection, const vec3_t lightmins, const vec3_t lightmaxs, const vec3_t surfacemins, const vec3_t surfacemaxs, int *totals)
1533 int mask, surfacemask = 0;
1534 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1536 bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
1537 tend = firsttriangle + numtris;
1538 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1540 // surface box entirely inside light box, no box cull
1541 if (projectdirection)
1543 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1545 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1546 TriangleNormal(v[0], v[1], v[2], normal);
1547 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1549 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1550 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1551 surfacemask |= mask;
1554 totals[0] += mask&1, totals[1] += (mask>>1)&1, totals[2] += (mask>>2)&1, totals[3] += (mask>>3)&1, totals[4] += (mask>>4)&1, totals[5] += mask>>5;
1555 shadowsides[numshadowsides] = mask;
1556 shadowsideslist[numshadowsides++] = t;
1563 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1565 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1566 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]))
1568 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1569 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1570 surfacemask |= mask;
1573 totals[0] += mask&1, totals[1] += (mask>>1)&1, totals[2] += (mask>>2)&1, totals[3] += (mask>>3)&1, totals[4] += (mask>>4)&1, totals[5] += mask>>5;
1574 shadowsides[numshadowsides] = mask;
1575 shadowsideslist[numshadowsides++] = t;
1583 // surface box not entirely inside light box, cull each triangle
1584 if (projectdirection)
1586 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1588 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1589 TriangleNormal(v[0], v[1], v[2], normal);
1590 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1591 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1593 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1594 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1595 surfacemask |= mask;
1598 totals[0] += mask&1, totals[1] += (mask>>1)&1, totals[2] += (mask>>2)&1, totals[3] += (mask>>3)&1, totals[4] += (mask>>4)&1, totals[5] += mask>>5;
1599 shadowsides[numshadowsides] = mask;
1600 shadowsideslist[numshadowsides++] = t;
1607 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1609 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1610 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1611 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1613 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1614 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1615 surfacemask |= mask;
1618 totals[0] += mask&1, totals[1] += (mask>>1)&1, totals[2] += (mask>>2)&1, totals[3] += (mask>>3)&1, totals[4] += (mask>>4)&1, totals[5] += mask>>5;
1619 shadowsides[numshadowsides] = mask;
1620 shadowsideslist[numshadowsides++] = t;
1629 void R_Shadow_ShadowMapFromList(int numverts, int numtris, const float *vertex3f, const int *elements, int numsidetris, const int *sidetotals, const unsigned char *sides, const int *sidetris)
1631 int i, j, outtriangles = 0;
1632 int *outelement3i[6];
1633 if (!numverts || !numsidetris || !r_shadow_compilingrtlight)
1635 outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5];
1636 // make sure shadowelements is big enough for this mesh
1637 if (maxshadowtriangles < outtriangles)
1638 R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1);
1640 // compute the offset and size of the separate index lists for each cubemap side
1642 for (i = 0;i < 6;i++)
1644 outelement3i[i] = shadowelements + outtriangles * 3;
1645 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles;
1646 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i];
1647 outtriangles += sidetotals[i];
1650 // gather up the (sparse) triangles into separate index lists for each cubemap side
1651 for (i = 0;i < numsidetris;i++)
1653 const int *element = elements + sidetris[i] * 3;
1654 for (j = 0;j < 6;j++)
1656 if (sides[i] & (1 << j))
1658 outelement3i[j][0] = element[0];
1659 outelement3i[j][1] = element[1];
1660 outelement3i[j][2] = element[2];
1661 outelement3i[j] += 3;
1666 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, outtriangles, shadowelements);
1669 static void R_Shadow_MakeTextures_MakeCorona(void)
1673 unsigned char pixels[32][32][4];
1674 for (y = 0;y < 32;y++)
1676 dy = (y - 15.5f) * (1.0f / 16.0f);
1677 for (x = 0;x < 32;x++)
1679 dx = (x - 15.5f) * (1.0f / 16.0f);
1680 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1681 a = bound(0, a, 255);
1682 pixels[y][x][0] = a;
1683 pixels[y][x][1] = a;
1684 pixels[y][x][2] = a;
1685 pixels[y][x][3] = 255;
1688 r_shadow_lightcorona = R_SkinFrame_LoadInternalBGRA("lightcorona", TEXF_FORCELINEAR, &pixels[0][0][0], 32, 32);
1691 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1693 float dist = sqrt(x*x+y*y+z*z);
1694 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1695 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1696 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1699 static void R_Shadow_MakeTextures(void)
1702 float intensity, dist;
1704 R_Shadow_FreeShadowMaps();
1705 R_FreeTexturePool(&r_shadow_texturepool);
1706 r_shadow_texturepool = R_AllocTexturePool();
1707 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1708 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1709 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1710 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1711 for (x = 0;x <= ATTENTABLESIZE;x++)
1713 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1714 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1715 r_shadow_attentable[x] = bound(0, intensity, 1);
1717 // 1D gradient texture
1718 for (x = 0;x < ATTEN1DSIZE;x++)
1719 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1720 r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, NULL);
1721 // 2D circle texture
1722 for (y = 0;y < ATTEN2DSIZE;y++)
1723 for (x = 0;x < ATTEN2DSIZE;x++)
1724 data[y*ATTEN2DSIZE+x] = R_Shadow_MakeTextures_SamplePoint(((x + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375), ((y + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375), 0);
1725 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, NULL);
1726 // 3D sphere texture
1727 if (r_shadow_texture3d.integer && vid.support.ext_texture_3d)
1729 for (z = 0;z < ATTEN3DSIZE;z++)
1730 for (y = 0;y < ATTEN3DSIZE;y++)
1731 for (x = 0;x < ATTEN3DSIZE;x++)
1732 data[(z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x] = R_Shadow_MakeTextures_SamplePoint(((x + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375), ((y + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375), ((z + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375));
1733 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, NULL);
1736 r_shadow_attenuation3dtexture = NULL;
1739 R_Shadow_MakeTextures_MakeCorona();
1741 // Editor light sprites
1742 r_editlights_sprcursor = R_SkinFrame_LoadInternal8bit("gfx/editlights/cursor", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1759 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1760 r_editlights_sprlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/light", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1777 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1778 r_editlights_sprnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/noshadow", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1795 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1796 r_editlights_sprcubemaplight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemaplight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1813 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1814 r_editlights_sprcubemapnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemapnoshadowlight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1831 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1832 r_editlights_sprselection = R_SkinFrame_LoadInternal8bit("gfx/editlights/selection", TEXF_ALPHA | TEXF_CLAMP, (unsigned char *)
1849 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1852 void R_Shadow_ValidateCvars(void)
1854 if (r_shadow_texture3d.integer && !vid.support.ext_texture_3d)
1855 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1856 if (gl_ext_separatestencil.integer && !vid.support.ati_separate_stencil)
1857 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
1858 if (gl_ext_stenciltwoside.integer && !vid.support.ext_stencil_two_side)
1859 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1862 void R_Shadow_RenderMode_Begin(void)
1868 R_Shadow_ValidateCvars();
1870 if (!r_shadow_attenuation2dtexture
1871 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1872 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1873 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1874 R_Shadow_MakeTextures();
1877 R_Mesh_ColorPointer(NULL, 0, 0);
1878 R_Mesh_ResetTextureState();
1879 GL_BlendFunc(GL_ONE, GL_ZERO);
1880 GL_DepthRange(0, 1);
1881 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1883 GL_DepthMask(false);
1884 GL_Color(0, 0, 0, 1);
1885 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1887 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1889 if (gl_ext_separatestencil.integer && vid.support.ati_separate_stencil)
1891 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
1892 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
1894 else if (gl_ext_stenciltwoside.integer && vid.support.ext_stencil_two_side)
1896 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
1897 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
1901 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
1902 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
1905 switch(vid.renderpath)
1907 case RENDERPATH_GL20:
1908 case RENDERPATH_CGGL:
1909 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1911 case RENDERPATH_GL13:
1912 case RENDERPATH_GL11:
1913 if (r_textureunits.integer >= 2 && vid.texunits >= 2 && r_shadow_texture3d.integer && r_shadow_attenuation3dtexture)
1914 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN;
1915 else if (r_textureunits.integer >= 3 && vid.texunits >= 3)
1916 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN;
1917 else if (r_textureunits.integer >= 2 && vid.texunits >= 2)
1918 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN;
1920 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1926 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
1927 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
1928 r_shadow_drawbuffer = drawbuffer;
1929 r_shadow_readbuffer = readbuffer;
1931 r_shadow_cullface_front = r_refdef.view.cullface_front;
1932 r_shadow_cullface_back = r_refdef.view.cullface_back;
1935 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
1937 rsurface.rtlight = rtlight;
1940 void R_Shadow_RenderMode_Reset(void)
1943 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE)
1945 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1947 if (vid.support.ext_framebuffer_object)
1949 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);CHECKGLERROR
1952 qglDrawBuffer(r_shadow_drawbuffer);CHECKGLERROR
1953 qglReadBuffer(r_shadow_readbuffer);CHECKGLERROR
1955 R_SetViewport(&r_refdef.view.viewport);
1956 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
1957 R_Mesh_ColorPointer(NULL, 0, 0);
1958 R_Mesh_ResetTextureState();
1959 GL_DepthRange(0, 1);
1961 GL_DepthMask(false);
1962 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1963 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1964 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
1965 qglStencilMask(255);CHECKGLERROR
1966 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
1967 qglStencilFunc(GL_ALWAYS, 128, 255);CHECKGLERROR
1968 r_refdef.view.cullface_front = r_shadow_cullface_front;
1969 r_refdef.view.cullface_back = r_shadow_cullface_back;
1970 GL_CullFace(r_refdef.view.cullface_back);
1971 GL_Color(1, 1, 1, 1);
1972 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
1973 GL_BlendFunc(GL_ONE, GL_ZERO);
1974 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
1975 r_shadow_usingshadowmaprect = false;
1976 r_shadow_usingshadowmapcube = false;
1977 r_shadow_usingshadowmap2d = false;
1981 void R_Shadow_ClearStencil(void)
1984 GL_Clear(GL_STENCIL_BUFFER_BIT);
1985 r_refdef.stats.lights_clears++;
1988 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
1990 r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
1991 if (r_shadow_rendermode == mode)
1994 R_Shadow_RenderMode_Reset();
1995 GL_ColorMask(0, 0, 0, 0);
1996 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1997 R_SetupShader_DepthOrShadow();
1998 qglDepthFunc(GL_LESS);CHECKGLERROR
1999 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2000 r_shadow_rendermode = mode;
2005 case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
2006 GL_CullFace(GL_NONE);
2007 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
2008 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
2010 case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
2011 GL_CullFace(GL_NONE);
2012 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
2013 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
2015 case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
2016 GL_CullFace(GL_NONE);
2017 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
2018 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
2019 qglStencilMask(255);CHECKGLERROR
2020 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
2021 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
2022 qglStencilMask(255);CHECKGLERROR
2023 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
2025 case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
2026 GL_CullFace(GL_NONE);
2027 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
2028 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
2029 qglStencilMask(255);CHECKGLERROR
2030 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
2031 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
2032 qglStencilMask(255);CHECKGLERROR
2033 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
2038 static void R_Shadow_MakeVSDCT(void)
2040 // maps to a 2x3 texture rectangle with normalized coordinates
2045 // stores abs(dir.xy), offset.xy/2.5
2046 unsigned char data[4*6] =
2048 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
2049 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
2050 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
2051 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
2052 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
2053 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
2055 r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, NULL);
2058 void R_Shadow_RenderMode_ShadowMap(int side, int clear, int size)
2062 float nearclip, farclip, bias;
2063 r_viewport_t viewport;
2066 maxsize = r_shadow_shadowmapmaxsize;
2067 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
2069 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
2070 r_shadow_shadowmap_parameters[2] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
2071 r_shadow_shadowmap_parameters[3] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
2072 r_shadow_shadowmapside = side;
2073 r_shadow_shadowmapsize = size;
2074 if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
2076 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2077 r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2078 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
2079 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D) goto init_done;
2081 // complex unrolled cube approach (more flexible)
2082 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2083 R_Shadow_MakeVSDCT();
2084 if (!r_shadow_shadowmap2dtexture)
2087 int w = maxsize*2, h = vid.support.arb_texture_non_power_of_two ? maxsize*3 : maxsize*4;
2088 r_shadow_shadowmap2dtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "shadowmap", w, h, r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
2089 qglGenFramebuffersEXT(1, &r_shadow_fbo2d);CHECKGLERROR
2090 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbo2d);CHECKGLERROR
2091 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_shadowmap2dtexture), 0);CHECKGLERROR
2092 // render depth into the fbo, do not render color at all
2093 qglDrawBuffer(GL_NONE);CHECKGLERROR
2094 qglReadBuffer(GL_NONE);CHECKGLERROR
2095 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2096 if (status != GL_FRAMEBUFFER_COMPLETE_EXT && (r_shadow_shadowmapping.integer || r_shadow_deferred.integer))
2098 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2099 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2100 Cvar_SetValueQuick(&r_shadow_deferred, 0);
2105 if (r_shadow_shadowmap2dtexture) fbo = r_shadow_fbo2d;
2106 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
2107 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
2108 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
2110 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE)
2112 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2113 r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2114 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
2115 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE) goto init_done;
2117 // complex unrolled cube approach (more flexible)
2118 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2119 R_Shadow_MakeVSDCT();
2120 if (!r_shadow_shadowmaprectangletexture)
2123 r_shadow_shadowmaprectangletexture = R_LoadTextureShadowMapRectangle(r_shadow_texturepool, "shadowmap", maxsize*2, maxsize*3, r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
2124 qglGenFramebuffersEXT(1, &r_shadow_fborectangle);CHECKGLERROR
2125 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fborectangle);CHECKGLERROR
2126 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, R_GetTexture(r_shadow_shadowmaprectangletexture), 0);CHECKGLERROR
2127 // render depth into the fbo, do not render color at all
2128 qglDrawBuffer(GL_NONE);CHECKGLERROR
2129 qglReadBuffer(GL_NONE);CHECKGLERROR
2130 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2131 if (status != GL_FRAMEBUFFER_COMPLETE_EXT && (r_shadow_shadowmapping.integer || r_shadow_deferred.integer))
2133 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2134 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2135 Cvar_SetValueQuick(&r_shadow_deferred, 0);
2140 if(r_shadow_shadowmaprectangletexture) fbo = r_shadow_fborectangle;
2141 r_shadow_shadowmap_texturescale[0] = 1.0f;
2142 r_shadow_shadowmap_texturescale[1] = 1.0f;
2143 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE;
2145 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
2147 r_shadow_shadowmap_parameters[0] = 1.0f;
2148 r_shadow_shadowmap_parameters[1] = 1.0f;
2149 R_Viewport_InitCubeSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, nearclip, farclip, NULL);
2150 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE) goto init_done;
2152 // simple cube approach
2153 if (!r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod])
2156 r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod] = R_LoadTextureShadowMapCube(r_shadow_texturepool, "shadowmapcube", size, r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
2157 qglGenFramebuffersEXT(1, &r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR
2158 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR
2159 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + side, R_GetTexture(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]), 0);CHECKGLERROR
2160 // render depth into the fbo, do not render color at all
2161 qglDrawBuffer(GL_NONE);CHECKGLERROR
2162 qglReadBuffer(GL_NONE);CHECKGLERROR
2163 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2164 if (status != GL_FRAMEBUFFER_COMPLETE_EXT && (r_shadow_shadowmapping.integer || r_shadow_deferred.integer))
2166 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2167 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2168 Cvar_SetValueQuick(&r_shadow_deferred, 0);
2173 if (r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]) fbo = r_shadow_fbocubeside[r_shadow_shadowmaplod];
2174 r_shadow_shadowmap_texturescale[0] = 0.0f;
2175 r_shadow_shadowmap_texturescale[1] = 0.0f;
2176 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE;
2179 R_Shadow_RenderMode_Reset();
2182 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);CHECKGLERROR
2183 R_SetupShader_DepthOrShadow();
2187 R_SetupShader_ShowDepth();
2188 qglClearColor(1,1,1,1);CHECKGLERROR
2191 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
2198 R_SetViewport(&viewport);
2199 if(r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE)
2201 int flipped = (side & 1) ^ (side >> 2);
2202 r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
2203 r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
2204 GL_CullFace(r_refdef.view.cullface_back);
2205 if ((clear & ((2 << side) - 1)) == (1 << side)) // only clear if the side is the first in the mask
2207 // get tightest scissor rectangle that encloses all viewports in the clear mask
2208 int x1 = clear & 0x15 ? 0 : size;
2209 int x2 = clear & 0x2A ? 2 * size : size;
2210 int y1 = clear & 0x03 ? 0 : (clear & 0xC ? size : 2 * size);
2211 int y2 = clear & 0x30 ? 3 * size : (clear & 0xC ? 2 * size : size);
2212 GL_Scissor(x1, y1, x2 - x1, y2 - y1);
2213 GL_Clear(GL_DEPTH_BUFFER_BIT);
2215 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2217 else if(r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE)
2219 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + side, R_GetTexture(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]), 0);CHECKGLERROR
2220 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2222 GL_Clear(GL_DEPTH_BUFFER_BIT);
2227 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
2231 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2232 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2233 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2234 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2237 R_Shadow_RenderMode_Reset();
2238 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2241 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2245 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2246 // only draw light where this geometry was already rendered AND the
2247 // stencil is 128 (values other than this mean shadow)
2248 qglStencilFunc(GL_EQUAL, 128, 255);CHECKGLERROR
2250 r_shadow_rendermode = r_shadow_lightingrendermode;
2251 // do global setup needed for the chosen lighting mode
2252 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2254 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2259 if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
2260 r_shadow_usingshadowmap2d = true;
2261 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE)
2262 r_shadow_usingshadowmaprect = true;
2263 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
2264 r_shadow_usingshadowmapcube = true;
2266 R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
2270 static const unsigned short bboxelements[36] =
2280 static const float bboxpoints[8][3] =
2292 void R_Shadow_RenderMode_DrawDeferredLight(qboolean stenciltest, qboolean shadowmapping)
2295 float vertex3f[8*3];
2296 const matrix4x4_t *matrix = &rsurface.rtlight->matrix_lighttoworld;
2298 R_Shadow_RenderMode_Reset();
2299 r_shadow_rendermode = r_shadow_lightingrendermode;
2300 // do global setup needed for the chosen lighting mode
2302 R_EntityMatrix(&identitymatrix);
2303 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2306 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2307 // only draw light where this geometry was already rendered AND the
2308 // stencil is 128 (values other than this mean shadow)
2309 qglStencilFunc(GL_EQUAL, 128, 255);CHECKGLERROR
2311 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepasslightingfbo);CHECKGLERROR
2314 if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
2315 r_shadow_usingshadowmap2d = true;
2316 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE)
2317 r_shadow_usingshadowmaprect = true;
2318 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
2319 r_shadow_usingshadowmapcube = true;
2322 // render the lighting
2323 R_SetupShader_DeferredLight(rsurface.rtlight);
2324 for (i = 0;i < 8;i++)
2325 Matrix4x4_Transform(matrix, bboxpoints[i], vertex3f + i*3);
2327 R_Mesh_VertexPointer(vertex3f, 0, 0);
2328 R_Mesh_ColorPointer(NULL, 0, 0);
2329 GL_ColorMask(1,1,1,1);
2330 GL_DepthMask(false);
2331 GL_DepthRange(0, 1);
2332 GL_PolygonOffset(0, 0);
2334 qglDepthFunc(GL_GREATER);CHECKGLERROR
2335 GL_CullFace(r_refdef.view.cullface_back);
2336 R_Mesh_Draw(0, 8, 0, 12, NULL, bboxelements, 0, 0);
2340 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
2343 R_Shadow_RenderMode_Reset();
2344 GL_BlendFunc(GL_ONE, GL_ONE);
2345 GL_DepthRange(0, 1);
2346 GL_DepthTest(r_showshadowvolumes.integer < 2);
2347 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
2348 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2349 GL_CullFace(GL_NONE);
2350 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
2353 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
2356 R_Shadow_RenderMode_Reset();
2357 GL_BlendFunc(GL_ONE, GL_ONE);
2358 GL_DepthRange(0, 1);
2359 GL_DepthTest(r_showlighting.integer < 2);
2360 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2363 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2367 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2368 qglStencilFunc(GL_EQUAL, 128, 255);CHECKGLERROR
2370 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2373 void R_Shadow_RenderMode_End(void)
2376 R_Shadow_RenderMode_Reset();
2377 R_Shadow_RenderMode_ActiveLight(NULL);
2379 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2380 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2383 int bboxedges[12][2] =
2402 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2404 int i, ix1, iy1, ix2, iy2;
2405 float x1, y1, x2, y2;
2407 float vertex[20][3];
2416 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2417 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2418 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2419 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2421 if (!r_shadow_scissor.integer)
2424 // if view is inside the light box, just say yes it's visible
2425 if (BoxesOverlap(r_refdef.view.origin, r_refdef.view.origin, mins, maxs))
2428 x1 = y1 = x2 = y2 = 0;
2430 // transform all corners that are infront of the nearclip plane
2431 VectorNegate(r_refdef.view.frustum[4].normal, plane4f);
2432 plane4f[3] = r_refdef.view.frustum[4].dist;
2434 for (i = 0;i < 8;i++)
2436 Vector4Set(corner[i], (i & 1) ? maxs[0] : mins[0], (i & 2) ? maxs[1] : mins[1], (i & 4) ? maxs[2] : mins[2], 1);
2437 dist[i] = DotProduct4(corner[i], plane4f);
2438 sign[i] = dist[i] > 0;
2441 VectorCopy(corner[i], vertex[numvertices]);
2445 // if some points are behind the nearclip, add clipped edge points to make
2446 // sure that the scissor boundary is complete
2447 if (numvertices > 0 && numvertices < 8)
2449 // add clipped edge points
2450 for (i = 0;i < 12;i++)
2452 j = bboxedges[i][0];
2453 k = bboxedges[i][1];
2454 if (sign[j] != sign[k])
2456 f = dist[j] / (dist[j] - dist[k]);
2457 VectorLerp(corner[j], f, corner[k], vertex[numvertices]);
2463 // if we have no points to check, the light is behind the view plane
2467 // if we have some points to transform, check what screen area is covered
2468 x1 = y1 = x2 = y2 = 0;
2470 //Con_Printf("%i vertices to transform...\n", numvertices);
2471 for (i = 0;i < numvertices;i++)
2473 VectorCopy(vertex[i], v);
2474 R_Viewport_TransformToScreen(&r_refdef.view.viewport, v, v2);
2475 //Con_Printf("%.3f %.3f %.3f %.3f transformed to %.3f %.3f %.3f %.3f\n", v[0], v[1], v[2], v[3], v2[0], v2[1], v2[2], v2[3]);
2478 if (x1 > v2[0]) x1 = v2[0];
2479 if (x2 < v2[0]) x2 = v2[0];
2480 if (y1 > v2[1]) y1 = v2[1];
2481 if (y2 < v2[1]) y2 = v2[1];
2490 // now convert the scissor rectangle to integer screen coordinates
2491 ix1 = (int)(x1 - 1.0f);
2492 iy1 = vid.height - (int)(y2 - 1.0f);
2493 ix2 = (int)(x2 + 1.0f);
2494 iy2 = vid.height - (int)(y1 + 1.0f);
2495 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
2497 // clamp it to the screen
2498 if (ix1 < r_refdef.view.viewport.x) ix1 = r_refdef.view.viewport.x;
2499 if (iy1 < r_refdef.view.viewport.y) iy1 = r_refdef.view.viewport.y;
2500 if (ix2 > r_refdef.view.viewport.x + r_refdef.view.viewport.width) ix2 = r_refdef.view.viewport.x + r_refdef.view.viewport.width;
2501 if (iy2 > r_refdef.view.viewport.y + r_refdef.view.viewport.height) iy2 = r_refdef.view.viewport.y + r_refdef.view.viewport.height;
2503 // if it is inside out, it's not visible
2504 if (ix2 <= ix1 || iy2 <= iy1)
2507 // the light area is visible, set up the scissor rectangle
2508 r_shadow_lightscissor[0] = ix1;
2509 r_shadow_lightscissor[1] = iy1;
2510 r_shadow_lightscissor[2] = ix2 - ix1;
2511 r_shadow_lightscissor[3] = iy2 - iy1;
2513 r_refdef.stats.lights_scissored++;
2517 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, int numtriangles, const int *element3i, const float *diffusecolor, const float *ambientcolor)
2519 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
2520 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
2521 float *color4f = rsurface.array_color4f + 4 * firstvertex;
2522 float dist, dot, distintensity, shadeintensity, v[3], n[3];
2523 switch (r_shadow_rendermode)
2525 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2526 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2527 if (VectorLength2(diffusecolor) > 0)
2529 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2531 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2532 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2533 if ((dot = DotProduct(n, v)) < 0)
2535 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2536 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
2539 VectorCopy(ambientcolor, color4f);
2540 if (r_refdef.fogenabled)
2543 f = RSurf_FogVertex(vertex3f);
2544 VectorScale(color4f, f, color4f);
2551 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2553 VectorCopy(ambientcolor, color4f);
2554 if (r_refdef.fogenabled)
2557 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2558 f = RSurf_FogVertex(vertex3f);
2559 VectorScale(color4f, f, color4f);
2565 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2566 if (VectorLength2(diffusecolor) > 0)
2568 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2570 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2571 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2573 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2574 if ((dot = DotProduct(n, v)) < 0)
2576 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2577 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2578 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2579 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2583 color4f[0] = ambientcolor[0] * distintensity;
2584 color4f[1] = ambientcolor[1] * distintensity;
2585 color4f[2] = ambientcolor[2] * distintensity;
2587 if (r_refdef.fogenabled)
2590 f = RSurf_FogVertex(vertex3f);
2591 VectorScale(color4f, f, color4f);
2595 VectorClear(color4f);
2601 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2603 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2604 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2606 color4f[0] = ambientcolor[0] * distintensity;
2607 color4f[1] = ambientcolor[1] * distintensity;
2608 color4f[2] = ambientcolor[2] * distintensity;
2609 if (r_refdef.fogenabled)
2612 f = RSurf_FogVertex(vertex3f);
2613 VectorScale(color4f, f, color4f);
2617 VectorClear(color4f);
2622 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2623 if (VectorLength2(diffusecolor) > 0)
2625 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2627 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2628 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2630 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2631 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2632 if ((dot = DotProduct(n, v)) < 0)
2634 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2635 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2636 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2637 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2641 color4f[0] = ambientcolor[0] * distintensity;
2642 color4f[1] = ambientcolor[1] * distintensity;
2643 color4f[2] = ambientcolor[2] * distintensity;
2645 if (r_refdef.fogenabled)
2648 f = RSurf_FogVertex(vertex3f);
2649 VectorScale(color4f, f, color4f);
2653 VectorClear(color4f);
2659 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2661 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2662 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2664 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2665 color4f[0] = ambientcolor[0] * distintensity;
2666 color4f[1] = ambientcolor[1] * distintensity;
2667 color4f[2] = ambientcolor[2] * distintensity;
2668 if (r_refdef.fogenabled)
2671 f = RSurf_FogVertex(vertex3f);
2672 VectorScale(color4f, f, color4f);
2676 VectorClear(color4f);
2686 static void R_Shadow_RenderLighting_VisibleLighting(int firstvertex, int numvertices, int firsttriangle, int numtriangles, const int *element3i, const unsigned short *element3s, int element3i_bufferobject, int element3s_bufferobject)
2688 // used to display how many times a surface is lit for level design purposes
2689 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2692 static void R_Shadow_RenderLighting_Light_GLSL(int firstvertex, int numvertices, int firsttriangle, int numtriangles, const int *element3i, const unsigned short *element3s, int element3i_bufferobject, int element3s_bufferobject, const vec3_t lightcolor, float ambientscale, float diffusescale, float specularscale)
2694 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2695 R_SetupShader_Surface(lightcolor, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT);
2696 if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND))
2697 R_Mesh_ColorPointer(rsurface.modellightmapcolor4f, rsurface.modellightmapcolor4f_bufferobject, rsurface.modellightmapcolor4f_bufferoffset);
2699 R_Mesh_ColorPointer(NULL, 0, 0);
2700 R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
2701 R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset);
2702 R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset);
2703 R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset);
2704 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2706 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2708 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2709 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2711 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
2715 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
2722 int newnumtriangles;
2726 int maxtriangles = 4096;
2727 static int newelements[4096*3];
2728 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, numtriangles, element3i, diffusecolor2, ambientcolor2);
2729 for (renders = 0;renders < 4;renders++)
2734 newnumtriangles = 0;
2736 // due to low fillrate on the cards this vertex lighting path is
2737 // designed for, we manually cull all triangles that do not
2738 // contain a lit vertex
2739 // this builds batches of triangles from multiple surfaces and
2740 // renders them at once
2741 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
2743 if (VectorLength2(rsurface.array_color4f + e[0] * 4) + VectorLength2(rsurface.array_color4f + e[1] * 4) + VectorLength2(rsurface.array_color4f + e[2] * 4) >= 0.01)
2745 if (newnumtriangles)
2747 newfirstvertex = min(newfirstvertex, e[0]);
2748 newlastvertex = max(newlastvertex, e[0]);
2752 newfirstvertex = e[0];
2753 newlastvertex = e[0];
2755 newfirstvertex = min(newfirstvertex, e[1]);
2756 newlastvertex = max(newlastvertex, e[1]);
2757 newfirstvertex = min(newfirstvertex, e[2]);
2758 newlastvertex = max(newlastvertex, e[2]);
2764 if (newnumtriangles >= maxtriangles)
2766 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
2767 newnumtriangles = 0;
2773 if (newnumtriangles >= 1)
2775 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
2778 // if we couldn't find any lit triangles, exit early
2781 // now reduce the intensity for the next overbright pass
2782 // we have to clamp to 0 here incase the drivers have improper
2783 // handling of negative colors
2784 // (some old drivers even have improper handling of >1 color)
2786 for (i = 0, c = rsurface.array_color4f + 4 * firstvertex;i < numvertices;i++, c += 4)
2788 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
2790 c[0] = max(0, c[0] - 1);
2791 c[1] = max(0, c[1] - 1);
2792 c[2] = max(0, c[2] - 1);
2804 static void R_Shadow_RenderLighting_Light_Vertex(int firstvertex, int numvertices, int numtriangles, const int *element3i, const vec3_t lightcolor, float ambientscale, float diffusescale)
2806 // OpenGL 1.1 path (anything)
2807 float ambientcolorbase[3], diffusecolorbase[3];
2808 float ambientcolorpants[3], diffusecolorpants[3];
2809 float ambientcolorshirt[3], diffusecolorshirt[3];
2810 const float *surfacecolor = rsurface.texture->dlightcolor;
2811 const float *surfacepants = rsurface.colormap_pantscolor;
2812 const float *surfaceshirt = rsurface.colormap_shirtcolor;
2813 rtexture_t *basetexture = rsurface.texture->basetexture;
2814 rtexture_t *pantstexture = rsurface.texture->pantstexture;
2815 rtexture_t *shirttexture = rsurface.texture->shirttexture;
2816 qboolean dopants = pantstexture && VectorLength2(surfacepants) >= (1.0f / 1048576.0f);
2817 qboolean doshirt = shirttexture && VectorLength2(surfaceshirt) >= (1.0f / 1048576.0f);
2818 ambientscale *= 2 * r_refdef.view.colorscale;
2819 diffusescale *= 2 * r_refdef.view.colorscale;
2820 ambientcolorbase[0] = lightcolor[0] * ambientscale * surfacecolor[0];ambientcolorbase[1] = lightcolor[1] * ambientscale * surfacecolor[1];ambientcolorbase[2] = lightcolor[2] * ambientscale * surfacecolor[2];
2821 diffusecolorbase[0] = lightcolor[0] * diffusescale * surfacecolor[0];diffusecolorbase[1] = lightcolor[1] * diffusescale * surfacecolor[1];diffusecolorbase[2] = lightcolor[2] * diffusescale * surfacecolor[2];
2822 ambientcolorpants[0] = ambientcolorbase[0] * surfacepants[0];ambientcolorpants[1] = ambientcolorbase[1] * surfacepants[1];ambientcolorpants[2] = ambientcolorbase[2] * surfacepants[2];
2823 diffusecolorpants[0] = diffusecolorbase[0] * surfacepants[0];diffusecolorpants[1] = diffusecolorbase[1] * surfacepants[1];diffusecolorpants[2] = diffusecolorbase[2] * surfacepants[2];
2824 ambientcolorshirt[0] = ambientcolorbase[0] * surfaceshirt[0];ambientcolorshirt[1] = ambientcolorbase[1] * surfaceshirt[1];ambientcolorshirt[2] = ambientcolorbase[2] * surfaceshirt[2];
2825 diffusecolorshirt[0] = diffusecolorbase[0] * surfaceshirt[0];diffusecolorshirt[1] = diffusecolorbase[1] * surfaceshirt[1];diffusecolorshirt[2] = diffusecolorbase[2] * surfaceshirt[2];
2826 R_Mesh_TexBind(0, basetexture);
2827 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
2828 R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
2829 R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
2830 switch(r_shadow_rendermode)
2832 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2833 R_Mesh_TexBind(1, r_shadow_attenuation3dtexture);
2834 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
2835 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
2836 R_Mesh_TexCoordPointer(1, 3, rsurface.vertex3f, rsurface.vertex3f_bufferobject, rsurface.vertex3f_bufferoffset);
2838 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2839 R_Mesh_TexBind(2, r_shadow_attenuation2dtexture);
2840 R_Mesh_TexMatrix(2, &rsurface.entitytoattenuationz);
2841 R_Mesh_TexCombine(2, GL_MODULATE, GL_MODULATE, 1, 1);
2842 R_Mesh_TexCoordPointer(2, 3, rsurface.vertex3f, rsurface.vertex3f_bufferobject, rsurface.vertex3f_bufferoffset);
2844 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2845 R_Mesh_TexBind(1, r_shadow_attenuation2dtexture);
2846 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
2847 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
2848 R_Mesh_TexCoordPointer(1, 3, rsurface.vertex3f, rsurface.vertex3f_bufferobject, rsurface.vertex3f_bufferoffset);
2850 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2855 //R_Mesh_TexBind(0, basetexture);
2856 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorbase, ambientcolorbase);
2859 R_Mesh_TexBind(0, pantstexture);
2860 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorpants, ambientcolorpants);
2864 R_Mesh_TexBind(0, shirttexture);
2865 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorshirt, ambientcolorshirt);
2869 extern cvar_t gl_lightmaps;
2870 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)
2872 float ambientscale, diffusescale, specularscale;
2874 float lightcolor[3];
2875 VectorCopy(rsurface.rtlight->currentcolor, lightcolor);
2876 ambientscale = rsurface.rtlight->ambientscale;
2877 diffusescale = rsurface.rtlight->diffusescale;
2878 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
2879 if (!r_shadow_usenormalmap.integer)
2881 ambientscale += 1.0f * diffusescale;
2885 if ((ambientscale + diffusescale) * VectorLength2(lightcolor) + specularscale * VectorLength2(lightcolor) < (1.0f / 1048576.0f))
2887 negated = (lightcolor[0] + lightcolor[1] + lightcolor[2] < 0) && vid.support.ext_blend_subtract;
2890 VectorNegate(lightcolor, lightcolor);
2891 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
2893 RSurf_SetupDepthAndCulling();
2894 switch (r_shadow_rendermode)
2896 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2897 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2898 R_Shadow_RenderLighting_VisibleLighting(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2900 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2901 R_Shadow_RenderLighting_Light_GLSL(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolor, ambientscale, diffusescale, specularscale);
2903 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2904 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2905 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2906 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2907 R_Shadow_RenderLighting_Light_Vertex(firstvertex, numvertices, numtriangles, element3i + firsttriangle * 3, lightcolor, ambientscale, diffusescale);
2910 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2914 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
2917 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)
2919 matrix4x4_t tempmatrix = *matrix;
2920 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
2922 // if this light has been compiled before, free the associated data
2923 R_RTLight_Uncompile(rtlight);
2925 // clear it completely to avoid any lingering data
2926 memset(rtlight, 0, sizeof(*rtlight));
2928 // copy the properties
2929 rtlight->matrix_lighttoworld = tempmatrix;
2930 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
2931 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
2932 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
2933 VectorCopy(color, rtlight->color);
2934 rtlight->cubemapname[0] = 0;
2935 if (cubemapname && cubemapname[0])
2936 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
2937 rtlight->shadow = shadow;
2938 rtlight->corona = corona;
2939 rtlight->style = style;
2940 rtlight->isstatic = isstatic;
2941 rtlight->coronasizescale = coronasizescale;
2942 rtlight->ambientscale = ambientscale;
2943 rtlight->diffusescale = diffusescale;
2944 rtlight->specularscale = specularscale;
2945 rtlight->flags = flags;
2947 // compute derived data
2948 //rtlight->cullradius = rtlight->radius;
2949 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2950 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2951 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2952 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2953 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2954 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2955 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2958 // compiles rtlight geometry
2959 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2960 void R_RTLight_Compile(rtlight_t *rtlight)
2963 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
2964 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
2965 entity_render_t *ent = r_refdef.scene.worldentity;
2966 dp_model_t *model = r_refdef.scene.worldmodel;
2967 unsigned char *data;
2970 // compile the light
2971 rtlight->compiled = true;
2972 rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
2973 rtlight->static_numleafs = 0;
2974 rtlight->static_numleafpvsbytes = 0;
2975 rtlight->static_leaflist = NULL;
2976 rtlight->static_leafpvs = NULL;
2977 rtlight->static_numsurfaces = 0;
2978 rtlight->static_surfacelist = NULL;
2979 rtlight->static_shadowmap_receivers = 0x3F;
2980 rtlight->static_shadowmap_casters = 0x3F;
2981 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2982 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2983 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2984 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2985 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2986 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2988 if (model && model->GetLightInfo)
2990 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
2991 r_shadow_compilingrtlight = rtlight;
2992 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);
2993 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2994 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
2995 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
2996 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
2997 rtlight->static_numsurfaces = numsurfaces;
2998 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
2999 rtlight->static_numleafs = numleafs;
3000 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
3001 rtlight->static_numleafpvsbytes = numleafpvsbytes;
3002 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
3003 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
3004 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
3005 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
3006 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3007 if (rtlight->static_numsurfaces)
3008 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3009 if (rtlight->static_numleafs)
3010 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3011 if (rtlight->static_numleafpvsbytes)
3012 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3013 if (rtlight->static_numshadowtrispvsbytes)
3014 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3015 if (rtlight->static_numlighttrispvsbytes)
3016 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3017 switch (rtlight->shadowmode)
3019 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
3020 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
3021 case R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE:
3022 if (model->CompileShadowMap && rtlight->shadow)
3023 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3026 if (model->CompileShadowVolume && rtlight->shadow)
3027 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3030 // now we're done compiling the rtlight
3031 r_shadow_compilingrtlight = NULL;
3035 // use smallest available cullradius - box radius or light radius
3036 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3037 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3039 shadowzpasstris = 0;
3040 if (rtlight->static_meshchain_shadow_zpass)
3041 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
3042 shadowzpasstris += mesh->numtriangles;
3044 shadowzfailtris = 0;
3045 if (rtlight->static_meshchain_shadow_zfail)
3046 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
3047 shadowzfailtris += mesh->numtriangles;
3050 if (rtlight->static_numlighttrispvsbytes)
3051 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3052 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3056 if (rtlight->static_numlighttrispvsbytes)
3057 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3058 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3061 if (developer_extra.integer)
3062 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);
3065 void R_RTLight_Uncompile(rtlight_t *rtlight)
3067 if (rtlight->compiled)
3069 if (rtlight->static_meshchain_shadow_zpass)
3070 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
3071 rtlight->static_meshchain_shadow_zpass = NULL;
3072 if (rtlight->static_meshchain_shadow_zfail)
3073 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
3074 rtlight->static_meshchain_shadow_zfail = NULL;
3075 if (rtlight->static_meshchain_shadow_shadowmap)
3076 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
3077 rtlight->static_meshchain_shadow_shadowmap = NULL;
3078 // these allocations are grouped
3079 if (rtlight->static_surfacelist)
3080 Mem_Free(rtlight->static_surfacelist);
3081 rtlight->static_numleafs = 0;
3082 rtlight->static_numleafpvsbytes = 0;
3083 rtlight->static_leaflist = NULL;
3084 rtlight->static_leafpvs = NULL;
3085 rtlight->static_numsurfaces = 0;
3086 rtlight->static_surfacelist = NULL;
3087 rtlight->static_numshadowtrispvsbytes = 0;
3088 rtlight->static_shadowtrispvs = NULL;
3089 rtlight->static_numlighttrispvsbytes = 0;
3090 rtlight->static_lighttrispvs = NULL;
3091 rtlight->compiled = false;
3095 void R_Shadow_UncompileWorldLights(void)
3099 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3100 for (lightindex = 0;lightindex < range;lightindex++)
3102 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3105 R_RTLight_Uncompile(&light->rtlight);
3109 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3113 // reset the count of frustum planes
3114 // see rtlight->cached_frustumplanes definition for how much this array
3116 rtlight->cached_numfrustumplanes = 0;
3118 // haven't implemented a culling path for ortho rendering
3119 if (!r_refdef.view.useperspective)
3121 // check if the light is on screen and copy the 4 planes if it is
3122 for (i = 0;i < 4;i++)
3123 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3126 for (i = 0;i < 4;i++)
3127 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3132 // generate a deformed frustum that includes the light origin, this is
3133 // used to cull shadow casting surfaces that can not possibly cast a
3134 // shadow onto the visible light-receiving surfaces, which can be a
3137 // if the light origin is onscreen the result will be 4 planes exactly
3138 // if the light origin is offscreen on only one axis the result will
3139 // be exactly 5 planes (split-side case)
3140 // if the light origin is offscreen on two axes the result will be
3141 // exactly 4 planes (stretched corner case)
3142 for (i = 0;i < 4;i++)
3144 // quickly reject standard frustum planes that put the light
3145 // origin outside the frustum
3146 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3149 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3151 // if all the standard frustum planes were accepted, the light is onscreen
3152 // otherwise we need to generate some more planes below...
3153 if (rtlight->cached_numfrustumplanes < 4)
3155 // at least one of the stock frustum planes failed, so we need to
3156 // create one or two custom planes to enclose the light origin
3157 for (i = 0;i < 4;i++)
3159 // create a plane using the view origin and light origin, and a
3160 // single point from the frustum corner set
3161 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3162 VectorNormalize(plane.normal);
3163 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3164 // see if this plane is backwards and flip it if so
3165 for (j = 0;j < 4;j++)
3166 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3170 VectorNegate(plane.normal, plane.normal);
3172 // flipped plane, test again to see if it is now valid
3173 for (j = 0;j < 4;j++)
3174 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3176 // if the plane is still not valid, then it is dividing the
3177 // frustum and has to be rejected
3181 // we have created a valid plane, compute extra info
3182 PlaneClassify(&plane);
3184 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3186 // if we've found 5 frustum planes then we have constructed a
3187 // proper split-side case and do not need to keep searching for
3188 // planes to enclose the light origin
3189 if (rtlight->cached_numfrustumplanes == 5)
3197 for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
3199 plane = rtlight->cached_frustumplanes[i];
3200 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));
3205 // now add the light-space box planes if the light box is rotated, as any
3206 // caster outside the oriented light box is irrelevant (even if it passed
3207 // the worldspace light box, which is axial)
3208 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3210 for (i = 0;i < 6;i++)
3214 v[i >> 1] = (i & 1) ? -1 : 1;
3215 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3216 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3217 plane.dist = VectorNormalizeLength(plane.normal);
3218 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3219 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3225 // add the world-space reduced box planes
3226 for (i = 0;i < 6;i++)
3228 VectorClear(plane.normal);
3229 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3230 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
3231 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3240 // reduce all plane distances to tightly fit the rtlight cull box, which
3242 VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3243 VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3244 VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3245 VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3246 VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3247 VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3248 VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3249 VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3250 oldnum = rtlight->cached_numfrustumplanes;
3251 rtlight->cached_numfrustumplanes = 0;
3252 for (j = 0;j < oldnum;j++)
3254 // find the nearest point on the box to this plane
3255 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
3256 for (i = 1;i < 8;i++)
3258 dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
3259 if (bestdist > dist)
3262 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);
3263 // if the nearest point is near or behind the plane, we want this
3264 // plane, otherwise the plane is useless as it won't cull anything
3265 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
3267 PlaneClassify(&rtlight->cached_frustumplanes[j]);
3268 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
3275 void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
3279 RSurf_ActiveWorldEntity();
3281 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3284 GL_CullFace(GL_NONE);
3285 mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3286 for (;mesh;mesh = mesh->next)
3288 if (!mesh->sidetotals[r_shadow_shadowmapside])
3290 r_refdef.stats.lights_shadowtriangles += mesh->sidetotals[r_shadow_shadowmapside];
3291 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
3292 R_Mesh_Draw(0, mesh->numverts, mesh->sideoffsets[r_shadow_shadowmapside], mesh->sidetotals[r_shadow_shadowmapside], mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3296 else if (r_refdef.scene.worldentity->model)
3297 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);
3299 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3302 void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3304 qboolean zpass = false;
3307 int surfacelistindex;
3308 msurface_t *surface;
3310 RSurf_ActiveWorldEntity();
3312 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3315 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
3317 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
3318 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
3320 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
3321 for (;mesh;mesh = mesh->next)
3323 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
3324 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
3325 GL_LockArrays(0, mesh->numverts);
3326 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
3328 // increment stencil if frontface is infront of depthbuffer
3329 GL_CullFace(r_refdef.view.cullface_back);
3330 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
3331 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3332 // decrement stencil if backface is infront of depthbuffer
3333 GL_CullFace(r_refdef.view.cullface_front);
3334 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
3336 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
3338 // decrement stencil if backface is behind depthbuffer
3339 GL_CullFace(r_refdef.view.cullface_front);
3340 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
3341 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3342 // increment stencil if frontface is behind depthbuffer
3343 GL_CullFace(r_refdef.view.cullface_back);
3344 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
3346 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3347 GL_LockArrays(0, 0);
3351 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh)
3353 // use the shadow trispvs calculated earlier by GetLightInfo to cull world triangles on this dynamic light
3354 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
3355 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
3357 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
3358 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
3359 if (CHECKPVSBIT(trispvs, t))
3360 shadowmarklist[numshadowmark++] = t;
3362 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);
3364 else if (numsurfaces)
3365 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);
3367 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3370 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3372 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3373 vec_t relativeshadowradius;
3374 RSurf_ActiveModelEntity(ent, false, false, false);
3375 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3376 // we need to re-init the shader for each entity because the matrix changed
3377 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3378 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3379 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3380 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3381 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3382 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3383 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3384 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D)
3386 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
3389 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3390 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3393 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3395 // set up properties for rendering light onto this entity
3396 RSurf_ActiveModelEntity(ent, true, true, false);
3397 GL_AlphaTest(false);
3398 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3399 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3400 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3401 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3404 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
3406 if (!r_refdef.scene.worldmodel->DrawLight)
3409 // set up properties for rendering light onto this entity
3410 RSurf_ActiveWorldEntity();
3411 GL_AlphaTest(false);
3412 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3413 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3414 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3415 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3417 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
3419 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3422 void R_Shadow_DrawEntityLight(entity_render_t *ent)
3424 dp_model_t *model = ent->model;
3425 if (!model->DrawLight)
3428 R_Shadow_SetupEntityLight(ent);
3430 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3432 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3435 void R_Shadow_PrepareLight(rtlight_t *rtlight)
3439 int numleafs, numsurfaces;
3440 int *leaflist, *surfacelist;
3441 unsigned char *leafpvs, *shadowtrispvs, *lighttrispvs, *surfacesides;
3442 int numlightentities;
3443 int numlightentities_noselfshadow;
3444 int numshadowentities;
3445 int numshadowentities_noselfshadow;
3446 static entity_render_t *lightentities[MAX_EDICTS];
3447 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3448 static entity_render_t *shadowentities[MAX_EDICTS];
3449 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3451 rtlight->draw = false;
3453 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3454 // skip lights that are basically invisible (color 0 0 0)
3455 if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
3458 // loading is done before visibility checks because loading should happen
3459 // all at once at the start of a level, not when it stalls gameplay.
3460 // (especially important to benchmarks)
3462 if (rtlight->isstatic && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
3464 if (rtlight->compiled)
3465 R_RTLight_Uncompile(rtlight);
3466 R_RTLight_Compile(rtlight);
3470 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
3472 // look up the light style value at this time
3473 f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3474 VectorScale(rtlight->color, f, rtlight->currentcolor);
3476 if (rtlight->selected)
3478 f = 2 + sin(realtime * M_PI * 4.0);
3479 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3483 // if lightstyle is currently off, don't draw the light
3484 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3487 // if the light box is offscreen, skip it
3488 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3491 VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
3492 VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
3494 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3496 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3498 // compiled light, world available and can receive realtime lighting
3499 // retrieve leaf information
3500 numleafs = rtlight->static_numleafs;
3501 leaflist = rtlight->static_leaflist;
3502 leafpvs = rtlight->static_leafpvs;
3503 numsurfaces = rtlight->static_numsurfaces;
3504 surfacelist = rtlight->static_surfacelist;
3505 surfacesides = NULL;
3506 shadowtrispvs = rtlight->static_shadowtrispvs;
3507 lighttrispvs = rtlight->static_lighttrispvs;
3509 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3511 // dynamic light, world available and can receive realtime lighting
3512 // calculate lit surfaces and leafs
3513 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);
3514 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3515 leaflist = r_shadow_buffer_leaflist;
3516 leafpvs = r_shadow_buffer_leafpvs;
3517 surfacelist = r_shadow_buffer_surfacelist;
3518 surfacesides = r_shadow_buffer_surfacesides;
3519 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3520 lighttrispvs = r_shadow_buffer_lighttrispvs;
3521 // if the reduced leaf bounds are offscreen, skip it
3522 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3533 surfacesides = NULL;
3534 shadowtrispvs = NULL;
3535 lighttrispvs = NULL;
3537 // check if light is illuminating any visible leafs
3540 for (i = 0;i < numleafs;i++)
3541 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3547 // make a list of lit entities and shadow casting entities
3548 numlightentities = 0;
3549 numlightentities_noselfshadow = 0;
3550 numshadowentities = 0;
3551 numshadowentities_noselfshadow = 0;
3553 // add dynamic entities that are lit by the light
3554 for (i = 0;i < r_refdef.scene.numentities;i++)
3557 entity_render_t *ent = r_refdef.scene.entities[i];
3559 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3561 // skip the object entirely if it is not within the valid
3562 // shadow-casting region (which includes the lit region)
3563 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
3565 if (!(model = ent->model))
3567 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
3569 // this entity wants to receive light, is visible, and is
3570 // inside the light box
3571 // TODO: check if the surfaces in the model can receive light
3572 // so now check if it's in a leaf seen by the light
3573 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))
3575 if (ent->flags & RENDER_NOSELFSHADOW)
3576 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
3578 lightentities[numlightentities++] = ent;
3579 // since it is lit, it probably also casts a shadow...
3580 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3581 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3582 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3584 // note: exterior models without the RENDER_NOSELFSHADOW
3585 // flag still create a RENDER_NOSELFSHADOW shadow but
3586 // are lit normally, this means that they are
3587 // self-shadowing but do not shadow other
3588 // RENDER_NOSELFSHADOW entities such as the gun
3589 // (very weird, but keeps the player shadow off the gun)
3590 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3591 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3593 shadowentities[numshadowentities++] = ent;
3596 else if (ent->flags & RENDER_SHADOW)
3598 // this entity is not receiving light, but may still need to
3600 // TODO: check if the surfaces in the model can cast shadow
3601 // now check if it is in a leaf seen by the light
3602 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))
3604 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3605 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3606 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3608 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3609 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3611 shadowentities[numshadowentities++] = ent;
3616 // return if there's nothing at all to light
3617 if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
3620 // count this light in the r_speeds
3621 r_refdef.stats.lights++;
3623 // flag it as worth drawing later
3624 rtlight->draw = true;
3626 // cache all the animated entities that cast a shadow but are not visible
3627 for (i = 0;i < numshadowentities;i++)
3628 if (!shadowentities[i]->animcache_vertex3f)
3629 R_AnimCache_GetEntity(shadowentities[i], false, false);
3630 for (i = 0;i < numshadowentities_noselfshadow;i++)
3631 if (!shadowentities_noselfshadow[i]->animcache_vertex3f)
3632 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
3634 // allocate some temporary memory for rendering this light later in the frame
3635 // reusable buffers need to be copied, static data can be used as-is
3636 rtlight->cached_numlightentities = numlightentities;
3637 rtlight->cached_numlightentities_noselfshadow = numlightentities_noselfshadow;
3638 rtlight->cached_numshadowentities = numshadowentities;
3639 rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
3640 rtlight->cached_numsurfaces = numsurfaces;
3641 rtlight->cached_lightentities = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
3642 rtlight->cached_lightentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
3643 rtlight->cached_shadowentities = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
3644 rtlight->cached_shadowentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
3645 if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
3647 int numshadowtrispvsbytes = (((r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles) + 7) >> 3);
3648 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
3649 rtlight->cached_shadowtrispvs = (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
3650 rtlight->cached_lighttrispvs = (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
3651 rtlight->cached_surfacelist = (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
3655 // compiled light data
3656 rtlight->cached_shadowtrispvs = shadowtrispvs;
3657 rtlight->cached_lighttrispvs = lighttrispvs;
3658 rtlight->cached_surfacelist = surfacelist;
3662 void R_Shadow_DrawLight(rtlight_t *rtlight)
3666 unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
3667 int numlightentities;
3668 int numlightentities_noselfshadow;
3669 int numshadowentities;
3670 int numshadowentities_noselfshadow;
3671 entity_render_t **lightentities;
3672 entity_render_t **lightentities_noselfshadow;
3673 entity_render_t **shadowentities;
3674 entity_render_t **shadowentities_noselfshadow;
3676 static unsigned char entitysides[MAX_EDICTS];
3677 static unsigned char entitysides_noselfshadow[MAX_EDICTS];
3678 vec3_t nearestpoint;
3680 qboolean castshadows;
3683 // check if we cached this light this frame (meaning it is worth drawing)
3687 // if R_FrameData_Store ran out of space we skip anything dependent on it
3688 if (r_framedata_failed)
3691 numlightentities = rtlight->cached_numlightentities;
3692 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
3693 numshadowentities = rtlight->cached_numshadowentities;
3694 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
3695 numsurfaces = rtlight->cached_numsurfaces;
3696 lightentities = rtlight->cached_lightentities;
3697 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
3698 shadowentities = rtlight->cached_shadowentities;
3699 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
3700 shadowtrispvs = rtlight->cached_shadowtrispvs;
3701 lighttrispvs = rtlight->cached_lighttrispvs;
3702 surfacelist = rtlight->cached_surfacelist;
3704 // set up a scissor rectangle for this light
3705 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3708 // don't let sound skip if going slow
3709 if (r_refdef.scene.extraupdate)
3712 // make this the active rtlight for rendering purposes
3713 R_Shadow_RenderMode_ActiveLight(rtlight);
3715 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
3717 // optionally draw visible shape of the shadow volumes
3718 // for performance analysis by level designers
3719 R_Shadow_RenderMode_VisibleShadowVolumes();
3721 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
3722 for (i = 0;i < numshadowentities;i++)
3723 R_Shadow_DrawEntityShadow(shadowentities[i]);
3724 for (i = 0;i < numshadowentities_noselfshadow;i++)
3725 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3726 R_Shadow_RenderMode_VisibleLighting(false, false);
3729 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
3731 // optionally draw the illuminated areas
3732 // for performance analysis by level designers
3733 R_Shadow_RenderMode_VisibleLighting(false, false);
3735 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3736 for (i = 0;i < numlightentities;i++)
3737 R_Shadow_DrawEntityLight(lightentities[i]);
3738 for (i = 0;i < numlightentities_noselfshadow;i++)
3739 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3742 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
3744 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
3745 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
3746 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
3747 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
3749 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance/rtlight->radius));
3750 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
3751 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
3753 if (castshadows && (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE))
3759 int receivermask = 0;
3760 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
3761 Matrix4x4_Abs(&radiustolight);
3763 r_shadow_shadowmaplod = 0;
3764 for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
3765 if ((r_shadow_shadowmapmaxsize >> i) > lodlinear)
3766 r_shadow_shadowmaplod = i;
3768 if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
3769 size = max(1, r_shadow_shadowmapmaxsize >> r_shadow_shadowmaplod);
3771 size = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
3773 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
3775 surfacesides = NULL;
3778 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3780 castermask = rtlight->static_shadowmap_casters;
3781 receivermask = rtlight->static_shadowmap_receivers;
3785 surfacesides = r_shadow_buffer_surfacesides;
3786 for(i = 0;i < numsurfaces;i++)
3788 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
3789 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3790 castermask |= surfacesides[i];
3791 receivermask |= surfacesides[i];
3795 if (receivermask < 0x3F)
3797 for (i = 0;i < numlightentities;i++)
3798 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3799 if (receivermask < 0x3F)
3800 for(i = 0; i < numlightentities_noselfshadow;i++)
3801 receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3804 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
3808 for (i = 0;i < numshadowentities;i++)
3809 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3810 for (i = 0;i < numshadowentities_noselfshadow;i++)
3811 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3814 //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
3816 // render shadow casters into 6 sided depth texture
3817 for (side = 0;side < 6;side++) if (receivermask & (1 << side))
3819 R_Shadow_RenderMode_ShadowMap(side, receivermask, size);
3820 if (! (castermask & (1 << side))) continue;
3822 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
3823 for (i = 0;i < numshadowentities;i++) if (entitysides[i] & (1 << side))
3824 R_Shadow_DrawEntityShadow(shadowentities[i]);
3827 if (numlightentities_noselfshadow)
3829 // render lighting using the depth texture as shadowmap
3830 // draw lighting in the unmasked areas
3831 R_Shadow_RenderMode_Lighting(false, false, true);
3832 for (i = 0;i < numlightentities_noselfshadow;i++)
3833 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3836 // render shadow casters into 6 sided depth texture
3837 if (numshadowentities_noselfshadow)
3839 for (side = 0;side < 6;side++) if ((receivermask & castermask) & (1 << side))
3841 R_Shadow_RenderMode_ShadowMap(side, 0, size);
3842 for (i = 0;i < numshadowentities_noselfshadow;i++) if (entitysides_noselfshadow[i] & (1 << side))
3843 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3847 // render lighting using the depth texture as shadowmap
3848 // draw lighting in the unmasked areas
3849 R_Shadow_RenderMode_Lighting(false, false, true);
3850 // draw lighting in the unmasked areas
3852 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3853 for (i = 0;i < numlightentities;i++)
3854 R_Shadow_DrawEntityLight(lightentities[i]);
3856 else if (castshadows && vid.stencil)
3858 // draw stencil shadow volumes to mask off pixels that are in shadow
3859 // so that they won't receive lighting
3860 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
3861 R_Shadow_ClearStencil();
3864 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
3865 for (i = 0;i < numshadowentities;i++)
3866 R_Shadow_DrawEntityShadow(shadowentities[i]);
3868 // draw lighting in the unmasked areas
3869 R_Shadow_RenderMode_Lighting(true, false, false);
3870 for (i = 0;i < numlightentities_noselfshadow;i++)
3871 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3873 for (i = 0;i < numshadowentities_noselfshadow;i++)
3874 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3876 // draw lighting in the unmasked areas
3877 R_Shadow_RenderMode_Lighting(true, false, false);
3879 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3880 for (i = 0;i < numlightentities;i++)
3881 R_Shadow_DrawEntityLight(lightentities[i]);
3885 // draw lighting in the unmasked areas
3886 R_Shadow_RenderMode_Lighting(false, false, false);
3888 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3889 for (i = 0;i < numlightentities;i++)
3890 R_Shadow_DrawEntityLight(lightentities[i]);
3891 for (i = 0;i < numlightentities_noselfshadow;i++)
3892 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3895 if (r_shadow_usingdeferredprepass)
3897 // when rendering deferred lighting, we simply rasterize the box
3898 if (castshadows && (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE))
3899 R_Shadow_RenderMode_DrawDeferredLight(false, true);
3900 else if (castshadows && vid.stencil)
3901 R_Shadow_RenderMode_DrawDeferredLight(true, false);
3903 R_Shadow_RenderMode_DrawDeferredLight(false, false);
3907 static void R_Shadow_FreeDeferred(void)
3909 if (r_shadow_prepassgeometryfbo)
3910 qglDeleteFramebuffersEXT(1, &r_shadow_prepassgeometryfbo);CHECKGLERROR
3911 r_shadow_prepassgeometryfbo = 0;
3913 if (r_shadow_prepasslightingfbo)
3914 qglDeleteFramebuffersEXT(1, &r_shadow_prepasslightingfbo);CHECKGLERROR
3915 r_shadow_prepasslightingfbo = 0;
3917 if (r_shadow_prepassgeometrydepthtexture)
3918 R_FreeTexture(r_shadow_prepassgeometrydepthtexture);
3919 r_shadow_prepassgeometrydepthtexture = NULL;
3921 if (r_shadow_prepassgeometrynormalmaptexture)
3922 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
3923 r_shadow_prepassgeometrynormalmaptexture = NULL;
3925 if (r_shadow_prepasslightingdiffusetexture)
3926 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
3927 r_shadow_prepasslightingdiffusetexture = NULL;
3929 if (r_shadow_prepasslightingspeculartexture)
3930 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
3931 r_shadow_prepasslightingspeculartexture = NULL;
3934 void R_Shadow_DrawPrepass(void)
3942 entity_render_t *ent;
3944 GL_AlphaTest(false);
3945 R_Mesh_ColorPointer(NULL, 0, 0);
3946 R_Mesh_ResetTextureState();
3948 GL_ColorMask(1,1,1,1);
3949 GL_BlendFunc(GL_ONE, GL_ZERO);
3952 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepassgeometryfbo);CHECKGLERROR
3953 qglClearColor(0.5f,0.5f,0.5f,1.0f);CHECKGLERROR
3954 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);CHECKGLERROR
3956 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
3957 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
3958 if (r_timereport_active)
3959 R_TimeReport("prepassworld");
3961 for (i = 0;i < r_refdef.scene.numentities;i++)
3963 if (!r_refdef.viewcache.entityvisible[i])
3965 ent = r_refdef.scene.entities[i];
3966 if (ent->model && ent->model->DrawPrepass != NULL)
3967 ent->model->DrawPrepass(ent);
3970 if (r_timereport_active)
3971 R_TimeReport("prepassmodels");
3973 GL_DepthMask(false);
3974 GL_ColorMask(1,1,1,1);
3977 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepasslightingfbo);CHECKGLERROR
3978 qglClearColor(0.0f,0.0f,0.0f,0.0f);CHECKGLERROR
3979 GL_Clear(GL_COLOR_BUFFER_BIT);CHECKGLERROR
3980 if (r_refdef.fogenabled)
3981 qglClearColor(r_refdef.fogcolor[0],r_refdef.fogcolor[1],r_refdef.fogcolor[2],0);CHECKGLERROR
3983 R_Shadow_RenderMode_Begin();
3985 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3986 if (r_shadow_debuglight.integer >= 0)
3988 lightindex = r_shadow_debuglight.integer;
3989 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3990 if (light && (light->flags & flag))
3991 R_Shadow_DrawLight(&light->rtlight);
3995 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3996 for (lightindex = 0;lightindex < range;lightindex++)
3998 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3999 if (light && (light->flags & flag))
4000 R_Shadow_DrawLight(&light->rtlight);
4003 if (r_refdef.scene.rtdlight)
4004 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4005 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4007 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);CHECKGLERROR
4008 if (r_refdef.fogenabled)
4009 qglClearColor(r_refdef.fogcolor[0],r_refdef.fogcolor[1],r_refdef.fogcolor[2],0);CHECKGLERROR
4011 R_Shadow_RenderMode_End();
4013 if (r_timereport_active)
4014 R_TimeReport("prepasslights");
4017 void R_Shadow_DrawLightSprites(void);
4018 void R_Shadow_PrepareLights(void)
4028 if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4) ||
4029 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
4030 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0) ||
4031 r_shadow_shadowmaptexturetype != r_shadow_shadowmapping_texturetype.integer ||
4032 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
4033 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
4034 r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
4035 R_Shadow_FreeShadowMaps();
4037 switch (vid.renderpath)
4039 case RENDERPATH_GL20:
4040 case RENDERPATH_CGGL:
4041 if (!r_shadow_deferred.integer || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_STENCIL || !vid.support.ext_framebuffer_object || vid.maxdrawbuffers < 2)
4043 r_shadow_usingdeferredprepass = false;
4044 if (r_shadow_prepass_width)
4045 R_Shadow_FreeDeferred();
4046 r_shadow_prepass_width = r_shadow_prepass_height = 0;
4050 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
4052 R_Shadow_FreeDeferred();
4054 r_shadow_usingdeferredprepass = true;
4055 r_shadow_prepass_width = vid.width;
4056 r_shadow_prepass_height = vid.height;
4057 r_shadow_prepassgeometrydepthtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "prepassgeometrydepthmap", vid.width, vid.height, 24, false);
4058 r_shadow_prepassgeometrynormalmaptexture = R_LoadTexture2D(r_shadow_texturepool, "prepassgeometrynormalmap", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, NULL);
4059 r_shadow_prepasslightingdiffusetexture = R_LoadTexture2D(r_shadow_texturepool, "prepasslightingdiffuse", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, NULL);
4060 r_shadow_prepasslightingspeculartexture = R_LoadTexture2D(r_shadow_texturepool, "prepasslightingspecular", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, NULL);
4062 // set up the geometry pass fbo (depth + normalmap)
4063 qglGenFramebuffersEXT(1, &r_shadow_prepassgeometryfbo);CHECKGLERROR
4064 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepassgeometryfbo);CHECKGLERROR
4065 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_prepassgeometrydepthtexture), 0);CHECKGLERROR
4066 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_prepassgeometrynormalmaptexture), 0);CHECKGLERROR
4067 // render depth into one texture and normalmap into the other
4068 if (qglDrawBuffersARB)
4070 qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);CHECKGLERROR
4071 qglReadBuffer(GL_NONE);CHECKGLERROR
4073 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4074 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4076 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4077 Cvar_SetValueQuick(&r_shadow_deferred, 0);
4078 r_shadow_usingdeferredprepass = false;
4081 // set up the lighting pass fbo (diffuse + specular)
4082 qglGenFramebuffersEXT(1, &r_shadow_prepasslightingfbo);CHECKGLERROR
4083 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepasslightingfbo);CHECKGLERROR
4084 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_prepassgeometrydepthtexture), 0);CHECKGLERROR
4085 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_prepasslightingdiffusetexture), 0);CHECKGLERROR
4086 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_prepasslightingspeculartexture), 0);CHECKGLERROR
4087 // render diffuse into one texture and specular into another,
4088 // with depth and normalmap bound as textures,
4089 // with depth bound as attachment as well
4090 if (qglDrawBuffersARB)
4092 qglDrawBuffersARB(2, r_shadow_prepasslightingdrawbuffers);CHECKGLERROR
4093 qglReadBuffer(GL_NONE);CHECKGLERROR
4095 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4096 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4098 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4099 Cvar_SetValueQuick(&r_shadow_deferred, 0);
4100 r_shadow_usingdeferredprepass = false;
4104 case RENDERPATH_GL13:
4105 case RENDERPATH_GL11:
4106 r_shadow_usingdeferredprepass = false;
4110 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);
4112 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4113 if (r_shadow_debuglight.integer >= 0)
4115 lightindex = r_shadow_debuglight.integer;
4116 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4117 if (light && (light->flags & flag))
4118 R_Shadow_PrepareLight(&light->rtlight);
4122 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4123 for (lightindex = 0;lightindex < range;lightindex++)
4125 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4126 if (light && (light->flags & flag))
4127 R_Shadow_PrepareLight(&light->rtlight);
4130 if (r_refdef.scene.rtdlight)
4132 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4133 R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
4135 else if(gl_flashblend.integer)
4137 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4139 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
4140 f = (rtlight->style >= 0 ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4141 VectorScale(rtlight->color, f, rtlight->currentcolor);
4145 if (r_editlights.integer)
4146 R_Shadow_DrawLightSprites();
4149 void R_Shadow_DrawLights(void)
4157 R_Shadow_RenderMode_Begin();
4159 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4160 if (r_shadow_debuglight.integer >= 0)
4162 lightindex = r_shadow_debuglight.integer;
4163 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4164 if (light && (light->flags & flag))
4165 R_Shadow_DrawLight(&light->rtlight);
4169 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4170 for (lightindex = 0;lightindex < range;lightindex++)
4172 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4173 if (light && (light->flags & flag))
4174 R_Shadow_DrawLight(&light->rtlight);
4177 if (r_refdef.scene.rtdlight)
4178 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4179 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4181 R_Shadow_RenderMode_End();
4184 extern const float r_screenvertex3f[12];
4185 extern void R_SetupView(qboolean allowwaterclippingplane);
4186 extern void R_ResetViewRendering3D(void);
4187 extern void R_ResetViewRendering2D(void);
4188 extern cvar_t r_shadows;
4189 extern cvar_t r_shadows_darken;
4190 extern cvar_t r_shadows_drawafterrtlighting;
4191 extern cvar_t r_shadows_castfrombmodels;
4192 extern cvar_t r_shadows_throwdistance;
4193 extern cvar_t r_shadows_throwdirection;
4194 void R_DrawModelShadows(void)
4197 float relativethrowdistance;
4198 entity_render_t *ent;
4199 vec3_t relativelightorigin;
4200 vec3_t relativelightdirection;
4201 vec3_t relativeshadowmins, relativeshadowmaxs;
4202 vec3_t tmp, shadowdir;
4204 if (!r_refdef.scene.numentities || !vid.stencil)
4208 R_ResetViewRendering3D();
4209 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4210 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4211 R_Shadow_RenderMode_Begin();
4212 R_Shadow_RenderMode_ActiveLight(NULL);
4213 r_shadow_lightscissor[0] = r_refdef.view.x;
4214 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
4215 r_shadow_lightscissor[2] = r_refdef.view.width;
4216 r_shadow_lightscissor[3] = r_refdef.view.height;
4217 R_Shadow_RenderMode_StencilShadowVolumes(false);
4220 if (r_shadows.integer == 2)
4222 Math_atov(r_shadows_throwdirection.string, shadowdir);
4223 VectorNormalize(shadowdir);
4226 R_Shadow_ClearStencil();
4228 for (i = 0;i < r_refdef.scene.numentities;i++)
4230 ent = r_refdef.scene.entities[i];
4232 // cast shadows from anything of the map (submodels are optional)
4233 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4235 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4236 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
4237 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
4238 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
4239 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4242 if(ent->entitynumber != 0)
4244 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
4245 int entnum, entnum2, recursion;
4246 entnum = entnum2 = ent->entitynumber;
4247 for(recursion = 32; recursion > 0; --recursion)
4249 entnum2 = cl.entities[entnum].state_current.tagentity;
4250 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
4255 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
4257 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
4258 // transform into modelspace of OUR entity
4259 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
4260 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
4263 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4266 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4269 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
4270 RSurf_ActiveModelEntity(ent, false, false, false);
4271 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4272 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4276 // not really the right mode, but this will disable any silly stencil features
4277 R_Shadow_RenderMode_End();
4279 // set up ortho view for rendering this pass
4280 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4281 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4282 //GL_ScissorTest(true);
4283 //R_EntityMatrix(&identitymatrix);
4284 //R_Mesh_ResetTextureState();
4285 R_ResetViewRendering2D();
4286 R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
4287 R_Mesh_ColorPointer(NULL, 0, 0);
4288 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
4290 // set up a darkening blend on shadowed areas
4291 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4292 //GL_DepthRange(0, 1);
4293 //GL_DepthTest(false);
4294 //GL_DepthMask(false);
4295 //GL_PolygonOffset(0, 0);CHECKGLERROR
4296 GL_Color(0, 0, 0, r_shadows_darken.value);
4297 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4298 //qglDepthFunc(GL_ALWAYS);CHECKGLERROR
4299 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
4300 qglStencilMask(255);CHECKGLERROR
4301 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
4302 qglStencilFunc(GL_NOTEQUAL, 128, 255);CHECKGLERROR
4304 // apply the blend to the shadowed areas
4305 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
4307 // restore the viewport
4308 R_SetViewport(&r_refdef.view.viewport);
4310 // restore other state to normal
4311 //R_Shadow_RenderMode_End();
4314 void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4317 vec3_t centerorigin;
4319 // if it's too close, skip it
4320 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
4322 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4325 if (usequery && r_numqueries + 2 <= r_maxqueries)
4327 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4328 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4329 // 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
4330 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4333 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use qglDepthFunc instead
4334 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
4335 qglDepthFunc(GL_ALWAYS);
4336 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4337 R_Mesh_VertexPointer(vertex3f, 0, 0);
4338 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
4339 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4340 qglDepthFunc(GL_LEQUAL);
4341 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
4342 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4343 R_Mesh_VertexPointer(vertex3f, 0, 0);
4344 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
4345 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4348 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4351 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
4353 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4356 GLint allpixels = 0, visiblepixels = 0;
4357 // now we have to check the query result
4358 if (rtlight->corona_queryindex_visiblepixels)
4361 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
4362 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
4364 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
4365 if (visiblepixels < 1 || allpixels < 1)
4367 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
4368 cscale *= rtlight->corona_visibility;
4372 // FIXME: these traces should scan all render entities instead of cl.world
4373 if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
4376 VectorScale(rtlight->currentcolor, cscale, color);
4377 if (VectorLength(color) > (1.0f / 256.0f))
4380 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
4383 VectorNegate(color, color);
4384 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
4386 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4387 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);
4388 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4390 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
4394 void R_Shadow_DrawCoronas(void)
4402 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4404 if (r_waterstate.renderingscene)
4406 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4407 R_EntityMatrix(&identitymatrix);
4409 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4411 // check occlusion of coronas
4412 // use GL_ARB_occlusion_query if available
4413 // otherwise use raytraces
4415 usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
4418 GL_ColorMask(0,0,0,0);
4419 if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
4420 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
4423 r_maxqueries = (range + r_refdef.scene.numlights) * 4;
4424 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
4426 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
4429 RSurf_ActiveWorldEntity();
4430 GL_BlendFunc(GL_ONE, GL_ZERO);
4431 GL_CullFace(GL_NONE);
4432 GL_DepthMask(false);
4433 GL_DepthRange(0, 1);
4434 GL_PolygonOffset(0, 0);
4436 R_Mesh_ColorPointer(NULL, 0, 0);
4437 R_Mesh_ResetTextureState();
4438 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
4440 for (lightindex = 0;lightindex < range;lightindex++)
4442 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4445 rtlight = &light->rtlight;
4446 rtlight->corona_visibility = 0;
4447 rtlight->corona_queryindex_visiblepixels = 0;
4448 rtlight->corona_queryindex_allpixels = 0;
4449 if (!(rtlight->flags & flag))
4451 if (rtlight->corona <= 0)
4453 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4455 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4457 for (i = 0;i < r_refdef.scene.numlights;i++)
4459 rtlight = r_refdef.scene.lights[i];
4460 rtlight->corona_visibility = 0;
4461 rtlight->corona_queryindex_visiblepixels = 0;
4462 rtlight->corona_queryindex_allpixels = 0;
4463 if (!(rtlight->flags & flag))
4465 if (rtlight->corona <= 0)
4467 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4470 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4472 // now draw the coronas using the query data for intensity info
4473 for (lightindex = 0;lightindex < range;lightindex++)
4475 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4478 rtlight = &light->rtlight;
4479 if (rtlight->corona_visibility <= 0)
4481 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4483 for (i = 0;i < r_refdef.scene.numlights;i++)
4485 rtlight = r_refdef.scene.lights[i];
4486 if (rtlight->corona_visibility <= 0)
4488 if (gl_flashblend.integer)
4489 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4491 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4497 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
4498 typedef struct suffixinfo_s
4501 qboolean flipx, flipy, flipdiagonal;
4504 static suffixinfo_t suffix[3][6] =
4507 {"px", false, false, false},
4508 {"nx", false, false, false},
4509 {"py", false, false, false},
4510 {"ny", false, false, false},
4511 {"pz", false, false, false},
4512 {"nz", false, false, false}
4515 {"posx", false, false, false},
4516 {"negx", false, false, false},
4517 {"posy", false, false, false},
4518 {"negy", false, false, false},
4519 {"posz", false, false, false},
4520 {"negz", false, false, false}
4523 {"rt", true, false, true},
4524 {"lf", false, true, true},
4525 {"ft", true, true, false},
4526 {"bk", false, false, false},
4527 {"up", true, false, true},
4528 {"dn", true, false, true}
4532 static int componentorder[4] = {0, 1, 2, 3};
4534 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
4536 int i, j, cubemapsize;
4537 unsigned char *cubemappixels, *image_buffer;
4538 rtexture_t *cubemaptexture;
4540 // must start 0 so the first loadimagepixels has no requested width/height
4542 cubemappixels = NULL;
4543 cubemaptexture = NULL;
4544 // keep trying different suffix groups (posx, px, rt) until one loads
4545 for (j = 0;j < 3 && !cubemappixels;j++)
4547 // load the 6 images in the suffix group
4548 for (i = 0;i < 6;i++)
4550 // generate an image name based on the base and and suffix
4551 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
4553 if ((image_buffer = loadimagepixelsbgra(name, false, false)))
4555 // an image loaded, make sure width and height are equal
4556 if (image_width == image_height && (!cubemappixels || image_width == cubemapsize))
4558 // if this is the first image to load successfully, allocate the cubemap memory
4559 if (!cubemappixels && image_width >= 1)
4561 cubemapsize = image_width;
4562 // note this clears to black, so unavailable sides are black
4563 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
4565 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
4567 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);
4570 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
4572 Mem_Free(image_buffer);
4576 // if a cubemap loaded, upload it
4579 if (developer_loading.integer)
4580 Con_Printf("loading cubemap \"%s\"\n", basename);
4582 if (!r_shadow_filters_texturepool)
4583 r_shadow_filters_texturepool = R_AllocTexturePool();
4584 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_BGRA, (gl_texturecompression_lightcubemaps.integer ? TEXF_COMPRESS : 0) | TEXF_FORCELINEAR, NULL);
4585 Mem_Free(cubemappixels);
4589 Con_DPrintf("failed to load cubemap \"%s\"\n", basename);
4590 if (developer_loading.integer)
4592 Con_Printf("(tried tried images ");
4593 for (j = 0;j < 3;j++)
4594 for (i = 0;i < 6;i++)
4595 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
4596 Con_Print(" and was unable to find any of them).\n");
4599 return cubemaptexture;
4602 rtexture_t *R_Shadow_Cubemap(const char *basename)
4605 for (i = 0;i < numcubemaps;i++)
4606 if (!strcasecmp(cubemaps[i].basename, basename))
4607 return cubemaps[i].texture ? cubemaps[i].texture : r_texture_whitecube;
4608 if (i >= MAX_CUBEMAPS)
4609 return r_texture_whitecube;
4611 strlcpy(cubemaps[i].basename, basename, sizeof(cubemaps[i].basename));
4612 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
4613 return cubemaps[i].texture;
4616 void R_Shadow_FreeCubemaps(void)
4619 for (i = 0;i < numcubemaps;i++)
4621 if (developer_loading.integer)
4622 Con_Printf("unloading cubemap \"%s\"\n", cubemaps[i].basename);
4623 if (cubemaps[i].texture)
4624 R_FreeTexture(cubemaps[i].texture);
4628 R_FreeTexturePool(&r_shadow_filters_texturepool);
4631 dlight_t *R_Shadow_NewWorldLight(void)
4633 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4636 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)
4639 // validate parameters
4640 if (style < 0 || style >= MAX_LIGHTSTYLES)
4642 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
4648 // copy to light properties
4649 VectorCopy(origin, light->origin);
4650 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4651 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4652 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4654 light->color[0] = max(color[0], 0);
4655 light->color[1] = max(color[1], 0);
4656 light->color[2] = max(color[2], 0);
4658 light->color[0] = color[0];
4659 light->color[1] = color[1];
4660 light->color[2] = color[2];
4661 light->radius = max(radius, 0);
4662 light->style = style;
4663 light->shadow = shadowenable;
4664 light->corona = corona;
4665 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4666 light->coronasizescale = coronasizescale;
4667 light->ambientscale = ambientscale;
4668 light->diffusescale = diffusescale;
4669 light->specularscale = specularscale;
4670 light->flags = flags;
4672 // update renderable light data
4673 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4674 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);
4677 void R_Shadow_FreeWorldLight(dlight_t *light)
4679 if (r_shadow_selectedlight == light)
4680 r_shadow_selectedlight = NULL;
4681 R_RTLight_Uncompile(&light->rtlight);
4682 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4685 void R_Shadow_ClearWorldLights(void)
4689 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4690 for (lightindex = 0;lightindex < range;lightindex++)
4692 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4694 R_Shadow_FreeWorldLight(light);
4696 r_shadow_selectedlight = NULL;
4697 R_Shadow_FreeCubemaps();
4700 void R_Shadow_SelectLight(dlight_t *light)
4702 if (r_shadow_selectedlight)
4703 r_shadow_selectedlight->selected = false;
4704 r_shadow_selectedlight = light;
4705 if (r_shadow_selectedlight)
4706 r_shadow_selectedlight->selected = true;
4709 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4711 // this is never batched (there can be only one)
4713 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
4714 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4715 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4718 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4723 skinframe_t *skinframe;
4726 // this is never batched (due to the ent parameter changing every time)
4727 // so numsurfaces == 1 and surfacelist[0] == lightnumber
4728 const dlight_t *light = (dlight_t *)ent;
4731 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
4734 VectorScale(light->color, intensity, spritecolor);
4735 if (VectorLength(spritecolor) < 0.1732f)
4736 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
4737 if (VectorLength(spritecolor) > 1.0f)
4738 VectorNormalize(spritecolor);
4740 // draw light sprite
4741 if (light->cubemapname[0] && !light->shadow)
4742 skinframe = r_editlights_sprcubemapnoshadowlight;
4743 else if (light->cubemapname[0])
4744 skinframe = r_editlights_sprcubemaplight;
4745 else if (!light->shadow)
4746 skinframe = r_editlights_sprnoshadowlight;
4748 skinframe = r_editlights_sprlight;
4750 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);
4751 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4753 // draw selection sprite if light is selected
4754 if (light->selected)
4756 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4757 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4758 // VorteX todo: add normalmode/realtime mode light overlay sprites?
4762 void R_Shadow_DrawLightSprites(void)
4766 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4767 for (lightindex = 0;lightindex < range;lightindex++)
4769 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4771 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
4773 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
4776 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
4781 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
4782 if (lightindex >= range)
4784 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4787 rtlight = &light->rtlight;
4788 //if (!(rtlight->flags & flag))
4790 VectorCopy(rtlight->shadoworigin, origin);
4791 *radius = rtlight->radius;
4792 VectorCopy(rtlight->color, color);
4796 void R_Shadow_SelectLightInView(void)
4798 float bestrating, rating, temp[3];
4802 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4805 for (lightindex = 0;lightindex < range;lightindex++)
4807 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4810 VectorSubtract(light->origin, r_refdef.view.origin, temp);
4811 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
4814 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
4815 if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1.0f)
4817 bestrating = rating;
4822 R_Shadow_SelectLight(best);
4825 void R_Shadow_LoadWorldLights(void)
4827 int n, a, style, shadow, flags;
4828 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
4829 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
4830 if (cl.worldmodel == NULL)
4832 Con_Print("No map loaded.\n");
4835 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4836 strlcat (name, ".rtlights", sizeof (name));
4837 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4847 for (;COM_Parse(t, true) && strcmp(
4848 if (COM_Parse(t, true))
4850 if (com_token[0] == '!')
4853 origin[0] = atof(com_token+1);
4856 origin[0] = atof(com_token);
4861 while (*s && *s != '\n' && *s != '\r')
4867 // check for modifier flags
4874 #if _MSC_VER >= 1400
4875 #define sscanf sscanf_s
4877 cubemapname[sizeof(cubemapname)-1] = 0;
4878 #if MAX_QPATH != 128
4879 #error update this code if MAX_QPATH changes
4881 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
4882 #if _MSC_VER >= 1400
4883 , sizeof(cubemapname)
4885 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
4888 flags = LIGHTFLAG_REALTIMEMODE;
4896 coronasizescale = 0.25f;
4898 VectorClear(angles);
4901 if (a < 9 || !strcmp(cubemapname, "\"\""))
4903 // remove quotes on cubemapname
4904 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
4907 namelen = strlen(cubemapname) - 2;
4908 memmove(cubemapname, cubemapname + 1, namelen);
4909 cubemapname[namelen] = '\0';
4913 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);
4916 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4924 Con_Printf("invalid rtlights file \"%s\"\n", name);
4925 Mem_Free(lightsstring);
4929 void R_Shadow_SaveWorldLights(void)
4933 size_t bufchars, bufmaxchars;
4935 char name[MAX_QPATH];
4936 char line[MAX_INPUTLINE];
4937 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
4938 // I hate lines which are 3 times my screen size :( --blub
4941 if (cl.worldmodel == NULL)
4943 Con_Print("No map loaded.\n");
4946 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4947 strlcat (name, ".rtlights", sizeof (name));
4948 bufchars = bufmaxchars = 0;
4950 for (lightindex = 0;lightindex < range;lightindex++)
4952 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4955 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
4956 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);
4957 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
4958 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]);
4960 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);
4961 if (bufchars + strlen(line) > bufmaxchars)
4963 bufmaxchars = bufchars + strlen(line) + 2048;
4965 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
4969 memcpy(buf, oldbuf, bufchars);
4975 memcpy(buf + bufchars, line, strlen(line));
4976 bufchars += strlen(line);
4980 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
4985 void R_Shadow_LoadLightsFile(void)
4988 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
4989 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
4990 if (cl.worldmodel == NULL)
4992 Con_Print("No map loaded.\n");
4995 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4996 strlcat (name, ".lights", sizeof (name));
4997 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5005 while (*s && *s != '\n' && *s != '\r')
5011 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);
5015 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);
5018 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
5019 radius = bound(15, radius, 4096);
5020 VectorScale(color, (2.0f / (8388608.0f)), color);
5021 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5029 Con_Printf("invalid lights file \"%s\"\n", name);
5030 Mem_Free(lightsstring);
5034 // tyrlite/hmap2 light types in the delay field
5035 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
5037 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
5039 int entnum, style, islight, skin, pflags, effects, type, n;
5042 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
5043 char key[256], value[MAX_INPUTLINE];
5045 if (cl.worldmodel == NULL)
5047 Con_Print("No map loaded.\n");
5050 // try to load a .ent file first
5051 FS_StripExtension (cl.worldmodel->name, key, sizeof (key));
5052 strlcat (key, ".ent", sizeof (key));
5053 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
5054 // and if that is not found, fall back to the bsp file entity string
5056 data = cl.worldmodel->brush.entities;
5059 for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
5061 type = LIGHTTYPE_MINUSX;
5062 origin[0] = origin[1] = origin[2] = 0;
5063 originhack[0] = originhack[1] = originhack[2] = 0;
5064 angles[0] = angles[1] = angles[2] = 0;
5065 color[0] = color[1] = color[2] = 1;
5066 light[0] = light[1] = light[2] = 1;light[3] = 300;
5067 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
5077 if (!COM_ParseToken_Simple(&data, false, false))
5079 if (com_token[0] == '}')
5080 break; // end of entity
5081 if (com_token[0] == '_')
5082 strlcpy(key, com_token + 1, sizeof(key));
5084 strlcpy(key, com_token, sizeof(key));
5085 while (key[strlen(key)-1] == ' ') // remove trailing spaces
5086 key[strlen(key)-1] = 0;
5087 if (!COM_ParseToken_Simple(&data, false, false))
5089 strlcpy(value, com_token, sizeof(value));
5091 // now that we have the key pair worked out...
5092 if (!strcmp("light", key))
5094 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5098 light[0] = vec[0] * (1.0f / 256.0f);
5099 light[1] = vec[0] * (1.0f / 256.0f);
5100 light[2] = vec[0] * (1.0f / 256.0f);
5106 light[0] = vec[0] * (1.0f / 255.0f);
5107 light[1] = vec[1] * (1.0f / 255.0f);
5108 light[2] = vec[2] * (1.0f / 255.0f);
5112 else if (!strcmp("delay", key))
5114 else if (!strcmp("origin", key))
5115 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5116 else if (!strcmp("angle", key))
5117 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5118 else if (!strcmp("angles", key))
5119 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5120 else if (!strcmp("color", key))
5121 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5122 else if (!strcmp("wait", key))
5123 fadescale = atof(value);
5124 else if (!strcmp("classname", key))
5126 if (!strncmp(value, "light", 5))
5129 if (!strcmp(value, "light_fluoro"))
5134 overridecolor[0] = 1;
5135 overridecolor[1] = 1;
5136 overridecolor[2] = 1;
5138 if (!strcmp(value, "light_fluorospark"))
5143 overridecolor[0] = 1;
5144 overridecolor[1] = 1;
5145 overridecolor[2] = 1;
5147 if (!strcmp(value, "light_globe"))
5152 overridecolor[0] = 1;
5153 overridecolor[1] = 0.8;
5154 overridecolor[2] = 0.4;
5156 if (!strcmp(value, "light_flame_large_yellow"))
5161 overridecolor[0] = 1;
5162 overridecolor[1] = 0.5;
5163 overridecolor[2] = 0.1;
5165 if (!strcmp(value, "light_flame_small_yellow"))
5170 overridecolor[0] = 1;
5171 overridecolor[1] = 0.5;
5172 overridecolor[2] = 0.1;
5174 if (!strcmp(value, "light_torch_small_white"))
5179 overridecolor[0] = 1;
5180 overridecolor[1] = 0.5;
5181 overridecolor[2] = 0.1;
5183 if (!strcmp(value, "light_torch_small_walltorch"))
5188 overridecolor[0] = 1;
5189 overridecolor[1] = 0.5;
5190 overridecolor[2] = 0.1;
5194 else if (!strcmp("style", key))
5195 style = atoi(value);
5196 else if (!strcmp("skin", key))
5197 skin = (int)atof(value);
5198 else if (!strcmp("pflags", key))
5199 pflags = (int)atof(value);
5200 else if (!strcmp("effects", key))
5201 effects = (int)atof(value);
5202 else if (cl.worldmodel->type == mod_brushq3)
5204 if (!strcmp("scale", key))
5205 lightscale = atof(value);
5206 if (!strcmp("fade", key))
5207 fadescale = atof(value);
5212 if (lightscale <= 0)
5216 if (color[0] == color[1] && color[0] == color[2])
5218 color[0] *= overridecolor[0];
5219 color[1] *= overridecolor[1];
5220 color[2] *= overridecolor[2];
5222 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5223 color[0] = color[0] * light[0];
5224 color[1] = color[1] * light[1];
5225 color[2] = color[2] * light[2];
5228 case LIGHTTYPE_MINUSX:
5230 case LIGHTTYPE_RECIPX:
5232 VectorScale(color, (1.0f / 16.0f), color);
5234 case LIGHTTYPE_RECIPXX:
5236 VectorScale(color, (1.0f / 16.0f), color);
5239 case LIGHTTYPE_NONE:
5243 case LIGHTTYPE_MINUSXX:
5246 VectorAdd(origin, originhack, origin);
5248 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);
5251 Mem_Free(entfiledata);
5255 void R_Shadow_SetCursorLocationForView(void)
5258 vec3_t dest, endpos;
5260 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5261 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
5262 if (trace.fraction < 1)
5264 dist = trace.fraction * r_editlights_cursordistance.value;
5265 push = r_editlights_cursorpushback.value;
5269 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5270 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5274 VectorClear( endpos );
5276 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5277 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5278 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5281 void R_Shadow_UpdateWorldLightSelection(void)
5283 if (r_editlights.integer)
5285 R_Shadow_SetCursorLocationForView();
5286 R_Shadow_SelectLightInView();
5289 R_Shadow_SelectLight(NULL);
5292 void R_Shadow_EditLights_Clear_f(void)
5294 R_Shadow_ClearWorldLights();
5297 void R_Shadow_EditLights_Reload_f(void)
5301 strlcpy(r_shadow_mapname, cl.worldmodel->name, sizeof(r_shadow_mapname));
5302 R_Shadow_ClearWorldLights();
5303 R_Shadow_LoadWorldLights();
5304 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5306 R_Shadow_LoadLightsFile();
5307 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5308 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5312 void R_Shadow_EditLights_Save_f(void)
5316 R_Shadow_SaveWorldLights();
5319 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
5321 R_Shadow_ClearWorldLights();
5322 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5325 void R_Shadow_EditLights_ImportLightsFile_f(void)
5327 R_Shadow_ClearWorldLights();
5328 R_Shadow_LoadLightsFile();
5331 void R_Shadow_EditLights_Spawn_f(void)
5334 if (!r_editlights.integer)
5336 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5339 if (Cmd_Argc() != 1)
5341 Con_Print("r_editlights_spawn does not take parameters\n");
5344 color[0] = color[1] = color[2] = 1;
5345 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5348 void R_Shadow_EditLights_Edit_f(void)
5350 vec3_t origin, angles, color;
5351 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5352 int style, shadows, flags, normalmode, realtimemode;
5353 char cubemapname[MAX_INPUTLINE];
5354 if (!r_editlights.integer)
5356 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5359 if (!r_shadow_selectedlight)
5361 Con_Print("No selected light.\n");
5364 VectorCopy(r_shadow_selectedlight->origin, origin);
5365 VectorCopy(r_shadow_selectedlight->angles, angles);
5366 VectorCopy(r_shadow_selectedlight->color, color);
5367 radius = r_shadow_selectedlight->radius;
5368 style = r_shadow_selectedlight->style;
5369 if (r_shadow_selectedlight->cubemapname)
5370 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5373 shadows = r_shadow_selectedlight->shadow;
5374 corona = r_shadow_selectedlight->corona;
5375 coronasizescale = r_shadow_selectedlight->coronasizescale;
5376 ambientscale = r_shadow_selectedlight->ambientscale;
5377 diffusescale = r_shadow_selectedlight->diffusescale;
5378 specularscale = r_shadow_selectedlight->specularscale;
5379 flags = r_shadow_selectedlight->flags;
5380 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5381 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5382 if (!strcmp(Cmd_Argv(1), "origin"))
5384 if (Cmd_Argc() != 5)
5386 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5389 origin[0] = atof(Cmd_Argv(2));
5390 origin[1] = atof(Cmd_Argv(3));
5391 origin[2] = atof(Cmd_Argv(4));
5393 else if (!strcmp(Cmd_Argv(1), "originx"))
5395 if (Cmd_Argc() != 3)
5397 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5400 origin[0] = atof(Cmd_Argv(2));
5402 else if (!strcmp(Cmd_Argv(1), "originy"))
5404 if (Cmd_Argc() != 3)
5406 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5409 origin[1] = atof(Cmd_Argv(2));
5411 else if (!strcmp(Cmd_Argv(1), "originz"))
5413 if (Cmd_Argc() != 3)
5415 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5418 origin[2] = atof(Cmd_Argv(2));
5420 else if (!strcmp(Cmd_Argv(1), "move"))
5422 if (Cmd_Argc() != 5)
5424 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5427 origin[0] += atof(Cmd_Argv(2));
5428 origin[1] += atof(Cmd_Argv(3));
5429 origin[2] += atof(Cmd_Argv(4));
5431 else if (!strcmp(Cmd_Argv(1), "movex"))
5433 if (Cmd_Argc() != 3)
5435 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5438 origin[0] += atof(Cmd_Argv(2));
5440 else if (!strcmp(Cmd_Argv(1), "movey"))
5442 if (Cmd_Argc() != 3)
5444 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5447 origin[1] += atof(Cmd_Argv(2));
5449 else if (!strcmp(Cmd_Argv(1), "movez"))
5451 if (Cmd_Argc() != 3)
5453 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5456 origin[2] += atof(Cmd_Argv(2));
5458 else if (!strcmp(Cmd_Argv(1), "angles"))
5460 if (Cmd_Argc() != 5)
5462 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5465 angles[0] = atof(Cmd_Argv(2));
5466 angles[1] = atof(Cmd_Argv(3));
5467 angles[2] = atof(Cmd_Argv(4));
5469 else if (!strcmp(Cmd_Argv(1), "anglesx"))
5471 if (Cmd_Argc() != 3)
5473 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5476 angles[0] = atof(Cmd_Argv(2));
5478 else if (!strcmp(Cmd_Argv(1), "anglesy"))
5480 if (Cmd_Argc() != 3)
5482 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5485 angles[1] = atof(Cmd_Argv(2));
5487 else if (!strcmp(Cmd_Argv(1), "anglesz"))
5489 if (Cmd_Argc() != 3)
5491 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5494 angles[2] = atof(Cmd_Argv(2));
5496 else if (!strcmp(Cmd_Argv(1), "color"))
5498 if (Cmd_Argc() != 5)
5500 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
5503 color[0] = atof(Cmd_Argv(2));
5504 color[1] = atof(Cmd_Argv(3));
5505 color[2] = atof(Cmd_Argv(4));
5507 else if (!strcmp(Cmd_Argv(1), "radius"))
5509 if (Cmd_Argc() != 3)
5511 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5514 radius = atof(Cmd_Argv(2));
5516 else if (!strcmp(Cmd_Argv(1), "colorscale"))
5518 if (Cmd_Argc() == 3)
5520 double scale = atof(Cmd_Argv(2));
5527 if (Cmd_Argc() != 5)
5529 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
5532 color[0] *= atof(Cmd_Argv(2));
5533 color[1] *= atof(Cmd_Argv(3));
5534 color[2] *= atof(Cmd_Argv(4));
5537 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
5539 if (Cmd_Argc() != 3)
5541 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5544 radius *= atof(Cmd_Argv(2));
5546 else if (!strcmp(Cmd_Argv(1), "style"))
5548 if (Cmd_Argc() != 3)
5550 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5553 style = atoi(Cmd_Argv(2));
5555 else if (!strcmp(Cmd_Argv(1), "cubemap"))
5559 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5562 if (Cmd_Argc() == 3)
5563 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
5567 else if (!strcmp(Cmd_Argv(1), "shadows"))
5569 if (Cmd_Argc() != 3)
5571 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5574 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5576 else if (!strcmp(Cmd_Argv(1), "corona"))
5578 if (Cmd_Argc() != 3)
5580 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5583 corona = atof(Cmd_Argv(2));
5585 else if (!strcmp(Cmd_Argv(1), "coronasize"))
5587 if (Cmd_Argc() != 3)
5589 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5592 coronasizescale = atof(Cmd_Argv(2));
5594 else if (!strcmp(Cmd_Argv(1), "ambient"))
5596 if (Cmd_Argc() != 3)
5598 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5601 ambientscale = atof(Cmd_Argv(2));
5603 else if (!strcmp(Cmd_Argv(1), "diffuse"))
5605 if (Cmd_Argc() != 3)
5607 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5610 diffusescale = atof(Cmd_Argv(2));
5612 else if (!strcmp(Cmd_Argv(1), "specular"))
5614 if (Cmd_Argc() != 3)
5616 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5619 specularscale = atof(Cmd_Argv(2));
5621 else if (!strcmp(Cmd_Argv(1), "normalmode"))
5623 if (Cmd_Argc() != 3)
5625 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5628 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5630 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
5632 if (Cmd_Argc() != 3)
5634 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5637 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5641 Con_Print("usage: r_editlights_edit [property] [value]\n");
5642 Con_Print("Selected light's properties:\n");
5643 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5644 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5645 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5646 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
5647 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
5648 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
5649 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5650 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
5651 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
5652 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
5653 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
5654 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
5655 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5656 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5659 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5660 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5663 void R_Shadow_EditLights_EditAll_f(void)
5669 if (!r_editlights.integer)
5671 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5675 // EditLights doesn't seem to have a "remove" command or something so:
5676 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5677 for (lightindex = 0;lightindex < range;lightindex++)
5679 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5682 R_Shadow_SelectLight(light);
5683 R_Shadow_EditLights_Edit_f();
5687 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
5689 int lightnumber, lightcount;
5690 size_t lightindex, range;
5694 if (!r_editlights.integer)
5696 x = vid_conwidth.value - 240;
5698 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
5701 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5702 for (lightindex = 0;lightindex < range;lightindex++)
5704 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5707 if (light == r_shadow_selectedlight)
5708 lightnumber = lightindex;
5711 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;
5712 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;
5714 if (r_shadow_selectedlight == NULL)
5716 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;
5717 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;
5718 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;
5719 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;
5720 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;
5721 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;
5722 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;
5723 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;
5724 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;
5725 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;
5726 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;
5727 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;
5728 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;
5729 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;
5730 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;
5733 void R_Shadow_EditLights_ToggleShadow_f(void)
5735 if (!r_editlights.integer)
5737 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5740 if (!r_shadow_selectedlight)
5742 Con_Print("No selected light.\n");
5745 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);
5748 void R_Shadow_EditLights_ToggleCorona_f(void)
5750 if (!r_editlights.integer)
5752 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5755 if (!r_shadow_selectedlight)
5757 Con_Print("No selected light.\n");
5760 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);
5763 void R_Shadow_EditLights_Remove_f(void)
5765 if (!r_editlights.integer)
5767 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
5770 if (!r_shadow_selectedlight)
5772 Con_Print("No selected light.\n");
5775 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
5776 r_shadow_selectedlight = NULL;
5779 void R_Shadow_EditLights_Help_f(void)
5782 "Documentation on r_editlights system:\n"
5784 "r_editlights : enable/disable editing mode\n"
5785 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
5786 "r_editlights_cursorpushback : push back cursor this far from surface\n"
5787 "r_editlights_cursorpushoff : push cursor off surface this far\n"
5788 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
5789 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
5791 "r_editlights_help : this help\n"
5792 "r_editlights_clear : remove all lights\n"
5793 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
5794 "r_editlights_save : save to .rtlights file\n"
5795 "r_editlights_spawn : create a light with default settings\n"
5796 "r_editlights_edit command : edit selected light - more documentation below\n"
5797 "r_editlights_remove : remove selected light\n"
5798 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
5799 "r_editlights_importlightentitiesfrommap : reload light entities\n"
5800 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
5802 "origin x y z : set light location\n"
5803 "originx x: set x component of light location\n"
5804 "originy y: set y component of light location\n"
5805 "originz z: set z component of light location\n"
5806 "move x y z : adjust light location\n"
5807 "movex x: adjust x component of light location\n"
5808 "movey y: adjust y component of light location\n"
5809 "movez z: adjust z component of light location\n"
5810 "angles x y z : set light angles\n"
5811 "anglesx x: set x component of light angles\n"
5812 "anglesy y: set y component of light angles\n"
5813 "anglesz z: set z component of light angles\n"
5814 "color r g b : set color of light (can be brighter than 1 1 1)\n"
5815 "radius radius : set radius (size) of light\n"
5816 "colorscale grey : multiply color of light (1 does nothing)\n"
5817 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
5818 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
5819 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
5820 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
5821 "cubemap basename : set filter cubemap of light (not yet supported)\n"
5822 "shadows 1/0 : turn on/off shadows\n"
5823 "corona n : set corona intensity\n"
5824 "coronasize n : set corona size (0-1)\n"
5825 "ambient n : set ambient intensity (0-1)\n"
5826 "diffuse n : set diffuse intensity (0-1)\n"
5827 "specular n : set specular intensity (0-1)\n"
5828 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
5829 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
5830 "<nothing> : print light properties to console\n"
5834 void R_Shadow_EditLights_CopyInfo_f(void)
5836 if (!r_editlights.integer)
5838 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
5841 if (!r_shadow_selectedlight)
5843 Con_Print("No selected light.\n");
5846 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
5847 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
5848 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
5849 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
5850 if (r_shadow_selectedlight->cubemapname)
5851 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
5853 r_shadow_bufferlight.cubemapname[0] = 0;
5854 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
5855 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
5856 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
5857 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
5858 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
5859 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
5860 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
5863 void R_Shadow_EditLights_PasteInfo_f(void)
5865 if (!r_editlights.integer)
5867 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
5870 if (!r_shadow_selectedlight)
5872 Con_Print("No selected light.\n");
5875 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);
5878 void R_Shadow_EditLights_Init(void)
5880 Cvar_RegisterVariable(&r_editlights);
5881 Cvar_RegisterVariable(&r_editlights_cursordistance);
5882 Cvar_RegisterVariable(&r_editlights_cursorpushback);
5883 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
5884 Cvar_RegisterVariable(&r_editlights_cursorgrid);
5885 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
5886 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
5887 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
5888 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)");
5889 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
5890 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
5891 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
5892 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)");
5893 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
5894 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
5895 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
5896 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
5897 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
5898 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
5899 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)");
5905 =============================================================================
5909 =============================================================================
5912 void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, int dynamic)
5914 VectorClear(diffusecolor);
5915 VectorClear(diffusenormal);
5917 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
5919 ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_refdef.scene.ambient;
5920 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
5923 VectorSet(ambientcolor, 1, 1, 1);
5930 for (i = 0;i < r_refdef.scene.numlights;i++)
5932 light = r_refdef.scene.lights[i];
5933 Matrix4x4_Transform(&light->matrix_worldtolight, p, v);
5934 f = 1 - VectorLength2(v);
5935 if (f > 0 && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
5936 VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);