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_portallight = {0, "r_shadow_portallight", "1", "use portal culling to exactly determine lit triangles when compiling world lights"};
290 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000", "how far to cast shadows"};
291 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)"};
292 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
293 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
294 cvar_t r_shadow_realtime_dlight_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
295 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
296 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)"};
297 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"};
298 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
299 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
300 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"};
301 cvar_t r_shadow_realtime_world_compilesvbsp = {0, "r_shadow_realtime_world_compilesvbsp", "1", "enables svbsp optimization during compilation"};
302 cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "1", "enables portal-based culling optimization during compilation"};
303 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)"};
304 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"};
305 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"};
306 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)"};
307 cvar_t r_shadow_shadowmapping_depthbits = {CVAR_SAVE, "r_shadow_shadowmapping_depthbits", "24", "requested minimum shadowmap texture depth bits"};
308 cvar_t r_shadow_shadowmapping_vsdct = {CVAR_SAVE, "r_shadow_shadowmapping_vsdct", "1", "enables use of virtual shadow depth cube texture"};
309 cvar_t r_shadow_shadowmapping_minsize = {CVAR_SAVE, "r_shadow_shadowmapping_minsize", "32", "shadowmap size limit"};
310 cvar_t r_shadow_shadowmapping_maxsize = {CVAR_SAVE, "r_shadow_shadowmapping_maxsize", "512", "shadowmap size limit"};
311 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"};
312 //cvar_t r_shadow_shadowmapping_lod_bias = {CVAR_SAVE, "r_shadow_shadowmapping_lod_bias", "16", "shadowmap size bias"};
313 //cvar_t r_shadow_shadowmapping_lod_scale = {CVAR_SAVE, "r_shadow_shadowmapping_lod_scale", "128", "shadowmap size scaling parameter"};
314 cvar_t r_shadow_shadowmapping_bordersize = {CVAR_SAVE, "r_shadow_shadowmapping_bordersize", "4", "shadowmap size bias for filtering"};
315 cvar_t r_shadow_shadowmapping_nearclip = {CVAR_SAVE, "r_shadow_shadowmapping_nearclip", "1", "shadowmap nearclip in world units"};
316 cvar_t r_shadow_shadowmapping_bias = {CVAR_SAVE, "r_shadow_shadowmapping_bias", "0.03", "shadowmap bias parameter (this is multiplied by nearclip * 1024 / lodsize)"};
317 cvar_t r_shadow_shadowmapping_polygonfactor = {CVAR_SAVE, "r_shadow_shadowmapping_polygonfactor", "2", "slope-dependent shadowmapping bias"};
318 cvar_t r_shadow_shadowmapping_polygonoffset = {CVAR_SAVE, "r_shadow_shadowmapping_polygonoffset", "0", "constant shadowmapping bias"};
319 cvar_t r_shadow_culltriangles = {0, "r_shadow_culltriangles", "1", "performs more expensive tests to remove unnecessary triangles of lit surfaces"};
320 cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
321 cvar_t r_shadow_polygonoffset = {0, "r_shadow_polygonoffset", "1", "how much to push shadow volumes into the distance when rendering, to reduce chances of zfighting artifacts (should not be less than 0)"};
322 cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "1", "use 3D voxel textures for spherical attenuation rather than cylindrical (does not affect OpenGL 2.0 render path)"};
323 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "1", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
324 cvar_t r_coronas_occlusionsizescale = {CVAR_SAVE, "r_coronas_occlusionsizescale", "0.1", "size of light source for corona occlusion checksm the proportion of hidden pixels controls corona intensity"};
325 cvar_t r_coronas_occlusionquery = {CVAR_SAVE, "r_coronas_occlusionquery", "1", "use GL_ARB_occlusion_query extension if supported (fades coronas according to visibility)"};
326 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
327 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
328 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
329 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
330 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
331 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
332 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
333 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
334 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
336 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
337 #define ATTENTABLESIZE 256
338 // 1D gradient, 2D circle and 3D sphere attenuation textures
339 #define ATTEN1DSIZE 32
340 #define ATTEN2DSIZE 64
341 #define ATTEN3DSIZE 32
343 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
344 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
345 static float r_shadow_attentable[ATTENTABLESIZE+1];
347 rtlight_t *r_shadow_compilingrtlight;
348 static memexpandablearray_t r_shadow_worldlightsarray;
349 dlight_t *r_shadow_selectedlight;
350 dlight_t r_shadow_bufferlight;
351 vec3_t r_editlights_cursorlocation;
353 extern int con_vislines;
355 typedef struct cubemapinfo_s
362 static int numcubemaps;
363 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
365 void R_Shadow_UncompileWorldLights(void);
366 void R_Shadow_ClearWorldLights(void);
367 void R_Shadow_SaveWorldLights(void);
368 void R_Shadow_LoadWorldLights(void);
369 void R_Shadow_LoadLightsFile(void);
370 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
371 void R_Shadow_EditLights_Reload_f(void);
372 void R_Shadow_ValidateCvars(void);
373 static void R_Shadow_MakeTextures(void);
375 #define EDLIGHTSPRSIZE 8
376 skinframe_t *r_editlights_sprcursor;
377 skinframe_t *r_editlights_sprlight;
378 skinframe_t *r_editlights_sprnoshadowlight;
379 skinframe_t *r_editlights_sprcubemaplight;
380 skinframe_t *r_editlights_sprcubemapnoshadowlight;
381 skinframe_t *r_editlights_sprselection;
383 void R_Shadow_SetShadowMode(void)
385 r_shadow_shadowmapmaxsize = bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4);
386 r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer != 0;
387 r_shadow_shadowmapfilterquality = r_shadow_shadowmapping_filterquality.integer;
388 r_shadow_shadowmaptexturetype = r_shadow_shadowmapping_texturetype.integer;
389 r_shadow_shadowmapdepthbits = r_shadow_shadowmapping_depthbits.integer;
390 r_shadow_shadowmapborder = bound(0, r_shadow_shadowmapping_bordersize.integer, 16);
391 r_shadow_shadowmaplod = -1;
392 r_shadow_shadowmapsize = 0;
393 r_shadow_shadowmapsampler = false;
394 r_shadow_shadowmappcf = 0;
395 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
396 switch(vid.renderpath)
398 case RENDERPATH_GL20:
399 case RENDERPATH_CGGL:
400 if ((r_shadow_shadowmapping.integer || r_shadow_deferred.integer) && vid.support.ext_framebuffer_object)
402 if(r_shadow_shadowmapfilterquality < 0)
404 if(strstr(gl_vendor, "NVIDIA"))
406 r_shadow_shadowmapsampler = vid.support.arb_shadow;
407 r_shadow_shadowmappcf = 1;
409 else if(vid.support.amd_texture_texture4 || vid.support.arb_texture_gather)
410 r_shadow_shadowmappcf = 1;
411 else if(strstr(gl_vendor, "ATI"))
412 r_shadow_shadowmappcf = 1;
414 r_shadow_shadowmapsampler = vid.support.arb_shadow;
418 switch (r_shadow_shadowmapfilterquality)
421 r_shadow_shadowmapsampler = vid.support.arb_shadow;
424 r_shadow_shadowmapsampler = vid.support.arb_shadow;
425 r_shadow_shadowmappcf = 1;
428 r_shadow_shadowmappcf = 1;
431 r_shadow_shadowmappcf = 2;
435 switch (r_shadow_shadowmaptexturetype)
438 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
441 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE;
444 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE;
447 if((vid.support.amd_texture_texture4 || vid.support.arb_texture_gather) && r_shadow_shadowmappcf && !r_shadow_shadowmapsampler)
448 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
449 else if(vid.support.arb_texture_rectangle)
450 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE;
452 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
457 case RENDERPATH_GL13:
459 case RENDERPATH_GL11:
464 void R_Shadow_FreeShadowMaps(void)
468 R_Shadow_SetShadowMode();
470 if (!vid.support.ext_framebuffer_object || !vid.support.arb_fragment_shader)
475 if (r_shadow_fborectangle)
476 qglDeleteFramebuffersEXT(1, &r_shadow_fborectangle);CHECKGLERROR
477 r_shadow_fborectangle = 0;
480 qglDeleteFramebuffersEXT(1, &r_shadow_fbo2d);CHECKGLERROR
482 for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
483 if (r_shadow_fbocubeside[i])
484 qglDeleteFramebuffersEXT(1, &r_shadow_fbocubeside[i]);CHECKGLERROR
485 memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
487 if (r_shadow_shadowmaprectangletexture)
488 R_FreeTexture(r_shadow_shadowmaprectangletexture);
489 r_shadow_shadowmaprectangletexture = NULL;
491 if (r_shadow_shadowmap2dtexture)
492 R_FreeTexture(r_shadow_shadowmap2dtexture);
493 r_shadow_shadowmap2dtexture = NULL;
495 for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
496 if (r_shadow_shadowmapcubetexture[i])
497 R_FreeTexture(r_shadow_shadowmapcubetexture[i]);
498 memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
500 if (r_shadow_shadowmapvsdcttexture)
501 R_FreeTexture(r_shadow_shadowmapvsdcttexture);
502 r_shadow_shadowmapvsdcttexture = NULL;
507 void r_shadow_start(void)
509 // allocate vertex processing arrays
511 r_shadow_attenuationgradienttexture = NULL;
512 r_shadow_attenuation2dtexture = NULL;
513 r_shadow_attenuation3dtexture = NULL;
514 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
515 r_shadow_shadowmaprectangletexture = NULL;
516 r_shadow_shadowmap2dtexture = NULL;
517 memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
518 r_shadow_shadowmapvsdcttexture = NULL;
519 r_shadow_shadowmapmaxsize = 0;
520 r_shadow_shadowmapsize = 0;
521 r_shadow_shadowmaplod = 0;
522 r_shadow_shadowmapfilterquality = -1;
523 r_shadow_shadowmaptexturetype = -1;
524 r_shadow_shadowmapdepthbits = 0;
525 r_shadow_shadowmapvsdct = false;
526 r_shadow_shadowmapsampler = false;
527 r_shadow_shadowmappcf = 0;
528 r_shadow_fborectangle = 0;
530 memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
532 R_Shadow_FreeShadowMaps();
534 r_shadow_texturepool = NULL;
535 r_shadow_filters_texturepool = NULL;
536 R_Shadow_ValidateCvars();
537 R_Shadow_MakeTextures();
538 maxshadowtriangles = 0;
539 shadowelements = NULL;
540 maxshadowvertices = 0;
541 shadowvertex3f = NULL;
549 shadowmarklist = NULL;
554 shadowsideslist = NULL;
555 r_shadow_buffer_numleafpvsbytes = 0;
556 r_shadow_buffer_visitingleafpvs = NULL;
557 r_shadow_buffer_leafpvs = NULL;
558 r_shadow_buffer_leaflist = NULL;
559 r_shadow_buffer_numsurfacepvsbytes = 0;
560 r_shadow_buffer_surfacepvs = NULL;
561 r_shadow_buffer_surfacelist = NULL;
562 r_shadow_buffer_surfacesides = NULL;
563 r_shadow_buffer_numshadowtrispvsbytes = 0;
564 r_shadow_buffer_shadowtrispvs = NULL;
565 r_shadow_buffer_numlighttrispvsbytes = 0;
566 r_shadow_buffer_lighttrispvs = NULL;
568 r_shadow_usingdeferredprepass = false;
569 r_shadow_prepass_width = r_shadow_prepass_height = 0;
572 static void R_Shadow_FreeDeferred(void);
573 void r_shadow_shutdown(void)
576 R_Shadow_UncompileWorldLights();
578 R_Shadow_FreeShadowMaps();
580 r_shadow_usingdeferredprepass = false;
581 if (r_shadow_prepass_width)
582 R_Shadow_FreeDeferred();
583 r_shadow_prepass_width = r_shadow_prepass_height = 0;
587 r_shadow_attenuationgradienttexture = NULL;
588 r_shadow_attenuation2dtexture = NULL;
589 r_shadow_attenuation3dtexture = NULL;
590 R_FreeTexturePool(&r_shadow_texturepool);
591 R_FreeTexturePool(&r_shadow_filters_texturepool);
592 maxshadowtriangles = 0;
594 Mem_Free(shadowelements);
595 shadowelements = NULL;
597 Mem_Free(shadowvertex3f);
598 shadowvertex3f = NULL;
601 Mem_Free(vertexupdate);
604 Mem_Free(vertexremap);
610 Mem_Free(shadowmark);
613 Mem_Free(shadowmarklist);
614 shadowmarklist = NULL;
619 Mem_Free(shadowsides);
622 Mem_Free(shadowsideslist);
623 shadowsideslist = NULL;
624 r_shadow_buffer_numleafpvsbytes = 0;
625 if (r_shadow_buffer_visitingleafpvs)
626 Mem_Free(r_shadow_buffer_visitingleafpvs);
627 r_shadow_buffer_visitingleafpvs = NULL;
628 if (r_shadow_buffer_leafpvs)
629 Mem_Free(r_shadow_buffer_leafpvs);
630 r_shadow_buffer_leafpvs = NULL;
631 if (r_shadow_buffer_leaflist)
632 Mem_Free(r_shadow_buffer_leaflist);
633 r_shadow_buffer_leaflist = NULL;
634 r_shadow_buffer_numsurfacepvsbytes = 0;
635 if (r_shadow_buffer_surfacepvs)
636 Mem_Free(r_shadow_buffer_surfacepvs);
637 r_shadow_buffer_surfacepvs = NULL;
638 if (r_shadow_buffer_surfacelist)
639 Mem_Free(r_shadow_buffer_surfacelist);
640 r_shadow_buffer_surfacelist = NULL;
641 if (r_shadow_buffer_surfacesides)
642 Mem_Free(r_shadow_buffer_surfacesides);
643 r_shadow_buffer_surfacesides = NULL;
644 r_shadow_buffer_numshadowtrispvsbytes = 0;
645 if (r_shadow_buffer_shadowtrispvs)
646 Mem_Free(r_shadow_buffer_shadowtrispvs);
647 r_shadow_buffer_numlighttrispvsbytes = 0;
648 if (r_shadow_buffer_lighttrispvs)
649 Mem_Free(r_shadow_buffer_lighttrispvs);
652 void r_shadow_newmap(void)
654 if (r_shadow_lightcorona) R_SkinFrame_MarkUsed(r_shadow_lightcorona);
655 if (r_editlights_sprcursor) R_SkinFrame_MarkUsed(r_editlights_sprcursor);
656 if (r_editlights_sprlight) R_SkinFrame_MarkUsed(r_editlights_sprlight);
657 if (r_editlights_sprnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprnoshadowlight);
658 if (r_editlights_sprcubemaplight) R_SkinFrame_MarkUsed(r_editlights_sprcubemaplight);
659 if (r_editlights_sprcubemapnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprcubemapnoshadowlight);
660 if (r_editlights_sprselection) R_SkinFrame_MarkUsed(r_editlights_sprselection);
661 if (cl.worldmodel && strncmp(cl.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
662 R_Shadow_EditLights_Reload_f();
665 void R_Shadow_Init(void)
667 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
668 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
669 Cvar_RegisterVariable(&r_shadow_usenormalmap);
670 Cvar_RegisterVariable(&r_shadow_debuglight);
671 Cvar_RegisterVariable(&r_shadow_deferred);
672 Cvar_RegisterVariable(&r_shadow_deferred_8bitrange);
673 // Cvar_RegisterVariable(&r_shadow_deferred_fp);
674 Cvar_RegisterVariable(&r_shadow_gloss);
675 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
676 Cvar_RegisterVariable(&r_shadow_glossintensity);
677 Cvar_RegisterVariable(&r_shadow_glossexponent);
678 Cvar_RegisterVariable(&r_shadow_gloss2exponent);
679 Cvar_RegisterVariable(&r_shadow_glossexact);
680 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
681 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
682 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
683 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
684 Cvar_RegisterVariable(&r_shadow_portallight);
685 Cvar_RegisterVariable(&r_shadow_projectdistance);
686 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
687 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
688 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
689 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
690 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
691 Cvar_RegisterVariable(&r_shadow_realtime_world);
692 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
693 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
694 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
695 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
696 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
697 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
698 Cvar_RegisterVariable(&r_shadow_scissor);
699 Cvar_RegisterVariable(&r_shadow_shadowmapping);
700 Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
701 Cvar_RegisterVariable(&r_shadow_shadowmapping_texturetype);
702 Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
703 Cvar_RegisterVariable(&r_shadow_shadowmapping_depthbits);
704 Cvar_RegisterVariable(&r_shadow_shadowmapping_precision);
705 Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
706 Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
707 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
708 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
709 Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
710 Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
711 Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
712 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonfactor);
713 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonoffset);
714 Cvar_RegisterVariable(&r_shadow_culltriangles);
715 Cvar_RegisterVariable(&r_shadow_polygonfactor);
716 Cvar_RegisterVariable(&r_shadow_polygonoffset);
717 Cvar_RegisterVariable(&r_shadow_texture3d);
718 Cvar_RegisterVariable(&r_coronas);
719 Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
720 Cvar_RegisterVariable(&r_coronas_occlusionquery);
721 Cvar_RegisterVariable(&gl_flashblend);
722 Cvar_RegisterVariable(&gl_ext_separatestencil);
723 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
724 if (gamemode == GAME_TENEBRAE)
726 Cvar_SetValue("r_shadow_gloss", 2);
727 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
729 R_Shadow_EditLights_Init();
730 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
731 maxshadowtriangles = 0;
732 shadowelements = NULL;
733 maxshadowvertices = 0;
734 shadowvertex3f = NULL;
742 shadowmarklist = NULL;
747 shadowsideslist = NULL;
748 r_shadow_buffer_numleafpvsbytes = 0;
749 r_shadow_buffer_visitingleafpvs = NULL;
750 r_shadow_buffer_leafpvs = NULL;
751 r_shadow_buffer_leaflist = NULL;
752 r_shadow_buffer_numsurfacepvsbytes = 0;
753 r_shadow_buffer_surfacepvs = NULL;
754 r_shadow_buffer_surfacelist = NULL;
755 r_shadow_buffer_surfacesides = NULL;
756 r_shadow_buffer_shadowtrispvs = NULL;
757 r_shadow_buffer_lighttrispvs = NULL;
758 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
761 matrix4x4_t matrix_attenuationxyz =
764 {0.5, 0.0, 0.0, 0.5},
765 {0.0, 0.5, 0.0, 0.5},
766 {0.0, 0.0, 0.5, 0.5},
771 matrix4x4_t matrix_attenuationz =
774 {0.0, 0.0, 0.5, 0.5},
775 {0.0, 0.0, 0.0, 0.5},
776 {0.0, 0.0, 0.0, 0.5},
781 void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles, int vertscale, int triscale)
783 numvertices = ((numvertices + 255) & ~255) * vertscale;
784 numtriangles = ((numtriangles + 255) & ~255) * triscale;
785 // make sure shadowelements is big enough for this volume
786 if (maxshadowtriangles < numtriangles)
788 maxshadowtriangles = numtriangles;
790 Mem_Free(shadowelements);
791 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[3]));
793 // make sure shadowvertex3f is big enough for this volume
794 if (maxshadowvertices < numvertices)
796 maxshadowvertices = numvertices;
798 Mem_Free(shadowvertex3f);
799 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[3]));
803 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
805 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
806 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
807 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
808 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
809 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
811 if (r_shadow_buffer_visitingleafpvs)
812 Mem_Free(r_shadow_buffer_visitingleafpvs);
813 if (r_shadow_buffer_leafpvs)
814 Mem_Free(r_shadow_buffer_leafpvs);
815 if (r_shadow_buffer_leaflist)
816 Mem_Free(r_shadow_buffer_leaflist);
817 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
818 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
819 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
820 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
822 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
824 if (r_shadow_buffer_surfacepvs)
825 Mem_Free(r_shadow_buffer_surfacepvs);
826 if (r_shadow_buffer_surfacelist)
827 Mem_Free(r_shadow_buffer_surfacelist);
828 if (r_shadow_buffer_surfacesides)
829 Mem_Free(r_shadow_buffer_surfacesides);
830 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
831 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
832 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
833 r_shadow_buffer_surfacesides = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
835 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
837 if (r_shadow_buffer_shadowtrispvs)
838 Mem_Free(r_shadow_buffer_shadowtrispvs);
839 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
840 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
842 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
844 if (r_shadow_buffer_lighttrispvs)
845 Mem_Free(r_shadow_buffer_lighttrispvs);
846 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
847 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
851 void R_Shadow_PrepareShadowMark(int numtris)
853 // make sure shadowmark is big enough for this volume
854 if (maxshadowmark < numtris)
856 maxshadowmark = numtris;
858 Mem_Free(shadowmark);
860 Mem_Free(shadowmarklist);
861 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
862 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
866 // if shadowmarkcount wrapped we clear the array and adjust accordingly
867 if (shadowmarkcount == 0)
870 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
875 void R_Shadow_PrepareShadowSides(int numtris)
877 if (maxshadowsides < numtris)
879 maxshadowsides = numtris;
881 Mem_Free(shadowsides);
883 Mem_Free(shadowsideslist);
884 shadowsides = (unsigned char *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsides));
885 shadowsideslist = (int *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsideslist));
890 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)
893 int outtriangles = 0, outvertices = 0;
896 float ratio, direction[3], projectvector[3];
898 if (projectdirection)
899 VectorScale(projectdirection, projectdistance, projectvector);
901 VectorClear(projectvector);
903 // create the vertices
904 if (projectdirection)
906 for (i = 0;i < numshadowmarktris;i++)
908 element = inelement3i + shadowmarktris[i] * 3;
909 for (j = 0;j < 3;j++)
911 if (vertexupdate[element[j]] != vertexupdatenum)
913 vertexupdate[element[j]] = vertexupdatenum;
914 vertexremap[element[j]] = outvertices;
915 vertex = invertex3f + element[j] * 3;
916 // project one copy of the vertex according to projectvector
917 VectorCopy(vertex, outvertex3f);
918 VectorAdd(vertex, projectvector, (outvertex3f + 3));
927 for (i = 0;i < numshadowmarktris;i++)
929 element = inelement3i + shadowmarktris[i] * 3;
930 for (j = 0;j < 3;j++)
932 if (vertexupdate[element[j]] != vertexupdatenum)
934 vertexupdate[element[j]] = vertexupdatenum;
935 vertexremap[element[j]] = outvertices;
936 vertex = invertex3f + element[j] * 3;
937 // project one copy of the vertex to the sphere radius of the light
938 // (FIXME: would projecting it to the light box be better?)
939 VectorSubtract(vertex, projectorigin, direction);
940 ratio = projectdistance / VectorLength(direction);
941 VectorCopy(vertex, outvertex3f);
942 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
950 if (r_shadow_frontsidecasting.integer)
952 for (i = 0;i < numshadowmarktris;i++)
954 int remappedelement[3];
956 const int *neighbortriangle;
958 markindex = shadowmarktris[i] * 3;
959 element = inelement3i + markindex;
960 neighbortriangle = inneighbor3i + markindex;
961 // output the front and back triangles
962 outelement3i[0] = vertexremap[element[0]];
963 outelement3i[1] = vertexremap[element[1]];
964 outelement3i[2] = vertexremap[element[2]];
965 outelement3i[3] = vertexremap[element[2]] + 1;
966 outelement3i[4] = vertexremap[element[1]] + 1;
967 outelement3i[5] = vertexremap[element[0]] + 1;
971 // output the sides (facing outward from this triangle)
972 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
974 remappedelement[0] = vertexremap[element[0]];
975 remappedelement[1] = vertexremap[element[1]];
976 outelement3i[0] = remappedelement[1];
977 outelement3i[1] = remappedelement[0];
978 outelement3i[2] = remappedelement[0] + 1;
979 outelement3i[3] = remappedelement[1];
980 outelement3i[4] = remappedelement[0] + 1;
981 outelement3i[5] = remappedelement[1] + 1;
986 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
988 remappedelement[1] = vertexremap[element[1]];
989 remappedelement[2] = vertexremap[element[2]];
990 outelement3i[0] = remappedelement[2];
991 outelement3i[1] = remappedelement[1];
992 outelement3i[2] = remappedelement[1] + 1;
993 outelement3i[3] = remappedelement[2];
994 outelement3i[4] = remappedelement[1] + 1;
995 outelement3i[5] = remappedelement[2] + 1;
1000 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1002 remappedelement[0] = vertexremap[element[0]];
1003 remappedelement[2] = vertexremap[element[2]];
1004 outelement3i[0] = remappedelement[0];
1005 outelement3i[1] = remappedelement[2];
1006 outelement3i[2] = remappedelement[2] + 1;
1007 outelement3i[3] = remappedelement[0];
1008 outelement3i[4] = remappedelement[2] + 1;
1009 outelement3i[5] = remappedelement[0] + 1;
1018 for (i = 0;i < numshadowmarktris;i++)
1020 int remappedelement[3];
1022 const int *neighbortriangle;
1024 markindex = shadowmarktris[i] * 3;
1025 element = inelement3i + markindex;
1026 neighbortriangle = inneighbor3i + markindex;
1027 // output the front and back triangles
1028 outelement3i[0] = vertexremap[element[2]];
1029 outelement3i[1] = vertexremap[element[1]];
1030 outelement3i[2] = vertexremap[element[0]];
1031 outelement3i[3] = vertexremap[element[0]] + 1;
1032 outelement3i[4] = vertexremap[element[1]] + 1;
1033 outelement3i[5] = vertexremap[element[2]] + 1;
1037 // output the sides (facing outward from this triangle)
1038 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
1040 remappedelement[0] = vertexremap[element[0]];
1041 remappedelement[1] = vertexremap[element[1]];
1042 outelement3i[0] = remappedelement[0];
1043 outelement3i[1] = remappedelement[1];
1044 outelement3i[2] = remappedelement[1] + 1;
1045 outelement3i[3] = remappedelement[0];
1046 outelement3i[4] = remappedelement[1] + 1;
1047 outelement3i[5] = remappedelement[0] + 1;
1052 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1054 remappedelement[1] = vertexremap[element[1]];
1055 remappedelement[2] = vertexremap[element[2]];
1056 outelement3i[0] = remappedelement[1];
1057 outelement3i[1] = remappedelement[2];
1058 outelement3i[2] = remappedelement[2] + 1;
1059 outelement3i[3] = remappedelement[1];
1060 outelement3i[4] = remappedelement[2] + 1;
1061 outelement3i[5] = remappedelement[1] + 1;
1066 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1068 remappedelement[0] = vertexremap[element[0]];
1069 remappedelement[2] = vertexremap[element[2]];
1070 outelement3i[0] = remappedelement[2];
1071 outelement3i[1] = remappedelement[0];
1072 outelement3i[2] = remappedelement[0] + 1;
1073 outelement3i[3] = remappedelement[2];
1074 outelement3i[4] = remappedelement[0] + 1;
1075 outelement3i[5] = remappedelement[2] + 1;
1083 *outnumvertices = outvertices;
1084 return outtriangles;
1087 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)
1090 int outtriangles = 0, outvertices = 0;
1092 const float *vertex;
1093 float ratio, direction[3], projectvector[3];
1096 if (projectdirection)
1097 VectorScale(projectdirection, projectdistance, projectvector);
1099 VectorClear(projectvector);
1101 for (i = 0;i < numshadowmarktris;i++)
1103 int remappedelement[3];
1105 const int *neighbortriangle;
1107 markindex = shadowmarktris[i] * 3;
1108 neighbortriangle = inneighbor3i + markindex;
1109 side[0] = shadowmark[neighbortriangle[0]] == shadowmarkcount;
1110 side[1] = shadowmark[neighbortriangle[1]] == shadowmarkcount;
1111 side[2] = shadowmark[neighbortriangle[2]] == shadowmarkcount;
1112 if (side[0] + side[1] + side[2] == 0)
1116 element = inelement3i + markindex;
1118 // create the vertices
1119 for (j = 0;j < 3;j++)
1121 if (side[j] + side[j+1] == 0)
1124 if (vertexupdate[k] != vertexupdatenum)
1126 vertexupdate[k] = vertexupdatenum;
1127 vertexremap[k] = outvertices;
1128 vertex = invertex3f + k * 3;
1129 VectorCopy(vertex, outvertex3f);
1130 if (projectdirection)
1132 // project one copy of the vertex according to projectvector
1133 VectorAdd(vertex, projectvector, (outvertex3f + 3));
1137 // project one copy of the vertex to the sphere radius of the light
1138 // (FIXME: would projecting it to the light box be better?)
1139 VectorSubtract(vertex, projectorigin, direction);
1140 ratio = projectdistance / VectorLength(direction);
1141 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1148 // output the sides (facing outward from this triangle)
1151 remappedelement[0] = vertexremap[element[0]];
1152 remappedelement[1] = vertexremap[element[1]];
1153 outelement3i[0] = remappedelement[1];
1154 outelement3i[1] = remappedelement[0];
1155 outelement3i[2] = remappedelement[0] + 1;
1156 outelement3i[3] = remappedelement[1];
1157 outelement3i[4] = remappedelement[0] + 1;
1158 outelement3i[5] = remappedelement[1] + 1;
1165 remappedelement[1] = vertexremap[element[1]];
1166 remappedelement[2] = vertexremap[element[2]];
1167 outelement3i[0] = remappedelement[2];
1168 outelement3i[1] = remappedelement[1];
1169 outelement3i[2] = remappedelement[1] + 1;
1170 outelement3i[3] = remappedelement[2];
1171 outelement3i[4] = remappedelement[1] + 1;
1172 outelement3i[5] = remappedelement[2] + 1;
1179 remappedelement[0] = vertexremap[element[0]];
1180 remappedelement[2] = vertexremap[element[2]];
1181 outelement3i[0] = remappedelement[0];
1182 outelement3i[1] = remappedelement[2];
1183 outelement3i[2] = remappedelement[2] + 1;
1184 outelement3i[3] = remappedelement[0];
1185 outelement3i[4] = remappedelement[2] + 1;
1186 outelement3i[5] = remappedelement[0] + 1;
1193 *outnumvertices = outvertices;
1194 return outtriangles;
1197 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)
1203 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1205 tend = firsttriangle + numtris;
1206 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1208 // surface box entirely inside light box, no box cull
1209 if (projectdirection)
1211 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1213 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
1214 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1215 shadowmarklist[numshadowmark++] = t;
1220 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1221 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
1222 shadowmarklist[numshadowmark++] = t;
1227 // surface box not entirely inside light box, cull each triangle
1228 if (projectdirection)
1230 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1232 v[0] = invertex3f + e[0] * 3;
1233 v[1] = invertex3f + e[1] * 3;
1234 v[2] = invertex3f + e[2] * 3;
1235 TriangleNormal(v[0], v[1], v[2], normal);
1236 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1237 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1238 shadowmarklist[numshadowmark++] = t;
1243 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1245 v[0] = invertex3f + e[0] * 3;
1246 v[1] = invertex3f + e[1] * 3;
1247 v[2] = invertex3f + e[2] * 3;
1248 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1249 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1250 shadowmarklist[numshadowmark++] = t;
1256 qboolean R_Shadow_UseZPass(vec3_t mins, vec3_t maxs)
1261 if (r_shadow_compilingrtlight || !r_shadow_frontsidecasting.integer || !r_shadow_usezpassifpossible.integer)
1263 // check if the shadow volume intersects the near plane
1265 // a ray between the eye and light origin may intersect the caster,
1266 // indicating that the shadow may touch the eye location, however we must
1267 // test the near plane (a polygon), not merely the eye location, so it is
1268 // easiest to enlarge the caster bounding shape slightly for this.
1274 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)
1276 int i, tris, outverts;
1277 if (projectdistance < 0.1)
1279 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
1282 if (!numverts || !nummarktris)
1284 // make sure shadowelements is big enough for this volume
1285 if (maxshadowtriangles < nummarktris*8 || maxshadowvertices < numverts*2)
1286 R_Shadow_ResizeShadowArrays(numverts, nummarktris, 2, 8);
1288 if (maxvertexupdate < numverts)
1290 maxvertexupdate = numverts;
1292 Mem_Free(vertexupdate);
1294 Mem_Free(vertexremap);
1295 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1296 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1297 vertexupdatenum = 0;
1300 if (vertexupdatenum == 0)
1302 vertexupdatenum = 1;
1303 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
1304 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
1307 for (i = 0;i < nummarktris;i++)
1308 shadowmark[marktris[i]] = shadowmarkcount;
1310 if (r_shadow_compilingrtlight)
1312 // if we're compiling an rtlight, capture the mesh
1313 //tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1314 //Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zpass, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1315 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1316 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zfail, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1318 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
1320 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1321 R_Mesh_VertexPointer(shadowvertex3f, 0, 0);
1322 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1326 // decide which type of shadow to generate and set stencil mode
1327 R_Shadow_RenderMode_StencilShadowVolumes(R_Shadow_UseZPass(trismins, trismaxs));
1328 // generate the sides or a solid volume, depending on type
1329 if (r_shadow_rendermode >= R_SHADOW_RENDERMODE_ZPASS_STENCIL && r_shadow_rendermode <= R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE)
1330 tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1332 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1333 r_refdef.stats.lights_dynamicshadowtriangles += tris;
1334 r_refdef.stats.lights_shadowtriangles += tris;
1336 R_Mesh_VertexPointer(shadowvertex3f, 0, 0);
1337 GL_LockArrays(0, outverts);
1338 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
1340 // increment stencil if frontface is infront of depthbuffer
1341 GL_CullFace(r_refdef.view.cullface_front);
1342 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1343 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1344 // decrement stencil if backface is infront of depthbuffer
1345 GL_CullFace(r_refdef.view.cullface_back);
1346 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1348 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
1350 // decrement stencil if backface is behind depthbuffer
1351 GL_CullFace(r_refdef.view.cullface_front);
1352 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1353 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1354 // increment stencil if frontface is behind depthbuffer
1355 GL_CullFace(r_refdef.view.cullface_back);
1356 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1358 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1359 GL_LockArrays(0, 0);
1364 int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias)
1366 // p1, p2, p3 are in the cubemap's local coordinate system
1367 // bias = border/(size - border)
1370 float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1371 dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2),
1372 dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3);
1373 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1375 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1376 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1377 | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1378 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1380 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1381 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1382 | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1384 dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1385 dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2),
1386 dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3);
1387 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1389 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1390 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1391 | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1392 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1394 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1395 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1396 | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1398 dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1399 dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2),
1400 dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3);
1401 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1403 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1404 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1405 | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1406 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1408 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1409 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1410 | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1415 int R_Shadow_CalcBBoxSideMask(const vec3_t mins, const vec3_t maxs, const matrix4x4_t *worldtolight, const matrix4x4_t *radiustolight, float bias)
1417 vec3_t center, radius, lightcenter, lightradius, pmin, pmax;
1418 float dp1, dn1, ap1, an1, dp2, dn2, ap2, an2;
1421 VectorSubtract(maxs, mins, radius);
1422 VectorScale(radius, 0.5f, radius);
1423 VectorAdd(mins, radius, center);
1424 Matrix4x4_Transform(worldtolight, center, lightcenter);
1425 Matrix4x4_Transform3x3(radiustolight, radius, lightradius);
1426 VectorSubtract(lightcenter, lightradius, pmin);
1427 VectorAdd(lightcenter, lightradius, pmax);
1429 dp1 = pmax[0] + pmax[1], dn1 = pmax[0] - pmin[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1430 dp2 = pmin[0] + pmin[1], dn2 = pmin[0] - pmax[1], ap2 = fabs(dp2), an2 = fabs(dn2);
1431 if(ap1 > bias*an1 && ap2 > bias*an2)
1433 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1434 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1435 if(an1 > bias*ap1 && an2 > bias*ap2)
1437 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1438 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1440 dp1 = pmax[1] + pmax[2], dn1 = pmax[1] - pmin[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1441 dp2 = pmin[1] + pmin[2], dn2 = pmin[1] - pmax[2], ap2 = fabs(dp2), an2 = fabs(dn2);
1442 if(ap1 > bias*an1 && ap2 > bias*an2)
1444 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1445 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1446 if(an1 > bias*ap1 && an2 > bias*ap2)
1448 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1449 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1451 dp1 = pmax[2] + pmax[0], dn1 = pmax[2] - pmin[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1452 dp2 = pmin[2] + pmin[0], dn2 = pmin[2] - pmax[0], ap2 = fabs(dp2), an2 = fabs(dn2);
1453 if(ap1 > bias*an1 && ap2 > bias*an2)
1455 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1456 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1457 if(an1 > bias*ap1 && an2 > bias*ap2)
1459 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1460 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1465 #define R_Shadow_CalcEntitySideMask(ent, worldtolight, radiustolight, bias) R_Shadow_CalcBBoxSideMask((ent)->mins, (ent)->maxs, worldtolight, radiustolight, bias)
1467 int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
1469 // p is in the cubemap's local coordinate system
1470 // bias = border/(size - border)
1471 float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn);
1472 float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn);
1473 float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn);
1475 if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
1476 if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
1477 if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
1478 if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
1479 if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
1480 if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
1484 int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
1488 int sides = 0x3F, masks[6] = { 3<<4, 3<<4, 3<<0, 3<<0, 3<<2, 3<<2 };
1489 float scale = (size - 2*border)/size, len;
1490 float bias = border / (float)(size - border), dp, dn, ap, an;
1491 // check if cone enclosing side would cross frustum plane
1492 scale = 2 / (scale*scale + 2);
1493 for (i = 0;i < 5;i++)
1495 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) > -0.03125)
1497 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[i].normal, n);
1498 len = scale*VectorLength2(n);
1499 if(n[0]*n[0] > len) sides &= n[0] < 0 ? ~(1<<0) : ~(2 << 0);
1500 if(n[1]*n[1] > len) sides &= n[1] < 0 ? ~(1<<2) : ~(2 << 2);
1501 if(n[2]*n[2] > len) sides &= n[2] < 0 ? ~(1<<4) : ~(2 << 4);
1503 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[4]) >= r_refdef.farclip - r_refdef.nearclip + 0.03125)
1505 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[4].normal, n);
1506 len = scale*VectorLength(n);
1507 if(n[0]*n[0] > len) sides &= n[0] >= 0 ? ~(1<<0) : ~(2 << 0);
1508 if(n[1]*n[1] > len) sides &= n[1] >= 0 ? ~(1<<2) : ~(2 << 2);
1509 if(n[2]*n[2] > len) sides &= n[2] >= 0 ? ~(1<<4) : ~(2 << 4);
1511 // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results
1512 // check if frustum corners/origin cross plane sides
1513 for (i = 0;i < 5;i++)
1515 Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p);
1516 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn),
1517 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1518 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1519 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn),
1520 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1521 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1522 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn),
1523 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1524 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1526 return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5];
1529 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)
1537 int mask, surfacemask = 0;
1538 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1540 bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
1541 tend = firsttriangle + numtris;
1542 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1544 // surface box entirely inside light box, no box cull
1545 if (projectdirection)
1547 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1549 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1550 TriangleNormal(v[0], v[1], v[2], normal);
1551 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1553 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1554 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1555 surfacemask |= mask;
1558 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;
1559 shadowsides[numshadowsides] = mask;
1560 shadowsideslist[numshadowsides++] = t;
1567 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1569 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1570 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]))
1572 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1573 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1574 surfacemask |= mask;
1577 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;
1578 shadowsides[numshadowsides] = mask;
1579 shadowsideslist[numshadowsides++] = t;
1587 // surface box not entirely inside light box, cull each triangle
1588 if (projectdirection)
1590 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1592 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1593 TriangleNormal(v[0], v[1], v[2], normal);
1594 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1595 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1597 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1598 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1599 surfacemask |= mask;
1602 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;
1603 shadowsides[numshadowsides] = mask;
1604 shadowsideslist[numshadowsides++] = t;
1611 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1613 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1614 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1615 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1617 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1618 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1619 surfacemask |= mask;
1622 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;
1623 shadowsides[numshadowsides] = mask;
1624 shadowsideslist[numshadowsides++] = t;
1633 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)
1635 int i, j, outtriangles = 0;
1636 int *outelement3i[6];
1637 if (!numverts || !numsidetris || !r_shadow_compilingrtlight)
1639 outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5];
1640 // make sure shadowelements is big enough for this mesh
1641 if (maxshadowtriangles < outtriangles)
1642 R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1);
1644 // compute the offset and size of the separate index lists for each cubemap side
1646 for (i = 0;i < 6;i++)
1648 outelement3i[i] = shadowelements + outtriangles * 3;
1649 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles;
1650 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i];
1651 outtriangles += sidetotals[i];
1654 // gather up the (sparse) triangles into separate index lists for each cubemap side
1655 for (i = 0;i < numsidetris;i++)
1657 const int *element = elements + sidetris[i] * 3;
1658 for (j = 0;j < 6;j++)
1660 if (sides[i] & (1 << j))
1662 outelement3i[j][0] = element[0];
1663 outelement3i[j][1] = element[1];
1664 outelement3i[j][2] = element[2];
1665 outelement3i[j] += 3;
1670 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, outtriangles, shadowelements);
1673 static void R_Shadow_MakeTextures_MakeCorona(void)
1677 unsigned char pixels[32][32][4];
1678 for (y = 0;y < 32;y++)
1680 dy = (y - 15.5f) * (1.0f / 16.0f);
1681 for (x = 0;x < 32;x++)
1683 dx = (x - 15.5f) * (1.0f / 16.0f);
1684 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1685 a = bound(0, a, 255);
1686 pixels[y][x][0] = a;
1687 pixels[y][x][1] = a;
1688 pixels[y][x][2] = a;
1689 pixels[y][x][3] = 255;
1692 r_shadow_lightcorona = R_SkinFrame_LoadInternalBGRA("lightcorona", TEXF_FORCELINEAR, &pixels[0][0][0], 32, 32);
1695 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1697 float dist = sqrt(x*x+y*y+z*z);
1698 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1699 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1700 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1703 static void R_Shadow_MakeTextures(void)
1706 float intensity, dist;
1708 R_Shadow_FreeShadowMaps();
1709 R_FreeTexturePool(&r_shadow_texturepool);
1710 r_shadow_texturepool = R_AllocTexturePool();
1711 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1712 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1713 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1714 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1715 for (x = 0;x <= ATTENTABLESIZE;x++)
1717 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1718 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1719 r_shadow_attentable[x] = bound(0, intensity, 1);
1721 // 1D gradient texture
1722 for (x = 0;x < ATTEN1DSIZE;x++)
1723 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1724 r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, NULL);
1725 // 2D circle texture
1726 for (y = 0;y < ATTEN2DSIZE;y++)
1727 for (x = 0;x < ATTEN2DSIZE;x++)
1728 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);
1729 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, NULL);
1730 // 3D sphere texture
1731 if (r_shadow_texture3d.integer && vid.support.ext_texture_3d)
1733 for (z = 0;z < ATTEN3DSIZE;z++)
1734 for (y = 0;y < ATTEN3DSIZE;y++)
1735 for (x = 0;x < ATTEN3DSIZE;x++)
1736 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));
1737 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, NULL);
1740 r_shadow_attenuation3dtexture = NULL;
1743 R_Shadow_MakeTextures_MakeCorona();
1745 // Editor light sprites
1746 r_editlights_sprcursor = R_SkinFrame_LoadInternal8bit("gfx/editlights/cursor", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1763 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1764 r_editlights_sprlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/light", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1781 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1782 r_editlights_sprnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/noshadow", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1799 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1800 r_editlights_sprcubemaplight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemaplight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1817 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1818 r_editlights_sprcubemapnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemapnoshadowlight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1835 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1836 r_editlights_sprselection = R_SkinFrame_LoadInternal8bit("gfx/editlights/selection", TEXF_ALPHA | TEXF_CLAMP, (unsigned char *)
1853 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1856 void R_Shadow_ValidateCvars(void)
1858 if (r_shadow_texture3d.integer && !vid.support.ext_texture_3d)
1859 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1860 if (gl_ext_separatestencil.integer && !vid.support.ati_separate_stencil)
1861 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
1862 if (gl_ext_stenciltwoside.integer && !vid.support.ext_stencil_two_side)
1863 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1866 void R_Shadow_RenderMode_Begin(void)
1872 R_Shadow_ValidateCvars();
1874 if (!r_shadow_attenuation2dtexture
1875 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1876 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1877 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1878 R_Shadow_MakeTextures();
1881 R_Mesh_ColorPointer(NULL, 0, 0);
1882 R_Mesh_ResetTextureState();
1883 GL_BlendFunc(GL_ONE, GL_ZERO);
1884 GL_DepthRange(0, 1);
1885 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1887 GL_DepthMask(false);
1888 GL_Color(0, 0, 0, 1);
1889 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1891 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1893 if (gl_ext_separatestencil.integer && vid.support.ati_separate_stencil)
1895 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
1896 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
1898 else if (gl_ext_stenciltwoside.integer && vid.support.ext_stencil_two_side)
1900 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
1901 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
1905 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
1906 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
1909 switch(vid.renderpath)
1911 case RENDERPATH_GL20:
1912 case RENDERPATH_CGGL:
1913 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1915 case RENDERPATH_GL13:
1916 case RENDERPATH_GL11:
1917 if (r_textureunits.integer >= 2 && vid.texunits >= 2 && r_shadow_texture3d.integer && r_shadow_attenuation3dtexture)
1918 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN;
1919 else if (r_textureunits.integer >= 3 && vid.texunits >= 3)
1920 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN;
1921 else if (r_textureunits.integer >= 2 && vid.texunits >= 2)
1922 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN;
1924 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1930 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
1931 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
1932 r_shadow_drawbuffer = drawbuffer;
1933 r_shadow_readbuffer = readbuffer;
1935 r_shadow_cullface_front = r_refdef.view.cullface_front;
1936 r_shadow_cullface_back = r_refdef.view.cullface_back;
1939 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
1941 rsurface.rtlight = rtlight;
1944 void R_Shadow_RenderMode_Reset(void)
1947 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE)
1949 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1951 if (vid.support.ext_framebuffer_object)
1953 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);CHECKGLERROR
1956 qglDrawBuffer(r_shadow_drawbuffer);CHECKGLERROR
1957 qglReadBuffer(r_shadow_readbuffer);CHECKGLERROR
1959 R_SetViewport(&r_refdef.view.viewport);
1960 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
1961 R_Mesh_ColorPointer(NULL, 0, 0);
1962 R_Mesh_ResetTextureState();
1963 GL_DepthRange(0, 1);
1965 GL_DepthMask(false);
1966 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1967 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1968 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
1969 qglStencilMask(~0);CHECKGLERROR
1970 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
1971 qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
1972 r_refdef.view.cullface_front = r_shadow_cullface_front;
1973 r_refdef.view.cullface_back = r_shadow_cullface_back;
1974 GL_CullFace(r_refdef.view.cullface_back);
1975 GL_Color(1, 1, 1, 1);
1976 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
1977 GL_BlendFunc(GL_ONE, GL_ZERO);
1978 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
1979 r_shadow_usingshadowmaprect = false;
1980 r_shadow_usingshadowmapcube = false;
1981 r_shadow_usingshadowmap2d = false;
1985 void R_Shadow_ClearStencil(void)
1988 GL_Clear(GL_STENCIL_BUFFER_BIT);
1989 r_refdef.stats.lights_clears++;
1992 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
1994 r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
1995 if (r_shadow_rendermode == mode)
1998 R_Shadow_RenderMode_Reset();
1999 GL_ColorMask(0, 0, 0, 0);
2000 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2001 R_SetupShader_DepthOrShadow();
2002 qglDepthFunc(GL_LESS);CHECKGLERROR
2003 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2004 r_shadow_rendermode = mode;
2009 case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
2010 GL_CullFace(GL_NONE);
2011 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
2012 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
2014 case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
2015 GL_CullFace(GL_NONE);
2016 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
2017 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
2019 case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
2020 GL_CullFace(GL_NONE);
2021 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
2022 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
2023 qglStencilMask(~0);CHECKGLERROR
2024 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
2025 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
2026 qglStencilMask(~0);CHECKGLERROR
2027 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
2029 case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
2030 GL_CullFace(GL_NONE);
2031 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
2032 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
2033 qglStencilMask(~0);CHECKGLERROR
2034 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
2035 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
2036 qglStencilMask(~0);CHECKGLERROR
2037 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
2042 static void R_Shadow_MakeVSDCT(void)
2044 // maps to a 2x3 texture rectangle with normalized coordinates
2049 // stores abs(dir.xy), offset.xy/2.5
2050 unsigned char data[4*6] =
2052 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
2053 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
2054 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
2055 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
2056 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
2057 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
2059 r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, NULL);
2062 void R_Shadow_RenderMode_ShadowMap(int side, qboolean clear, int size)
2066 float nearclip, farclip, bias;
2067 r_viewport_t viewport;
2070 maxsize = r_shadow_shadowmapmaxsize;
2071 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
2073 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
2074 r_shadow_shadowmap_parameters[2] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
2075 r_shadow_shadowmap_parameters[3] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
2076 r_shadow_shadowmapside = side;
2077 r_shadow_shadowmapsize = size;
2078 if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
2080 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2081 r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2082 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
2083 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D) goto init_done;
2085 // complex unrolled cube approach (more flexible)
2086 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2087 R_Shadow_MakeVSDCT();
2088 if (!r_shadow_shadowmap2dtexture)
2091 int w = maxsize*2, h = vid.support.arb_texture_non_power_of_two ? maxsize*3 : maxsize*4;
2092 r_shadow_shadowmap2dtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "shadowmap", w, h, r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
2093 qglGenFramebuffersEXT(1, &r_shadow_fbo2d);CHECKGLERROR
2094 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbo2d);CHECKGLERROR
2095 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_shadowmap2dtexture), 0);CHECKGLERROR
2096 // render depth into the fbo, do not render color at all
2097 qglDrawBuffer(GL_NONE);CHECKGLERROR
2098 qglReadBuffer(GL_NONE);CHECKGLERROR
2099 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2100 if (status != GL_FRAMEBUFFER_COMPLETE_EXT && (r_shadow_shadowmapping.integer || r_shadow_deferred.integer))
2102 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2103 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2104 Cvar_SetValueQuick(&r_shadow_deferred, 0);
2109 if (r_shadow_shadowmap2dtexture) fbo = r_shadow_fbo2d;
2110 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
2111 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
2112 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
2114 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE)
2116 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2117 r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2118 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
2119 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE) goto init_done;
2121 // complex unrolled cube approach (more flexible)
2122 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2123 R_Shadow_MakeVSDCT();
2124 if (!r_shadow_shadowmaprectangletexture)
2127 r_shadow_shadowmaprectangletexture = R_LoadTextureShadowMapRectangle(r_shadow_texturepool, "shadowmap", maxsize*2, maxsize*3, r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
2128 qglGenFramebuffersEXT(1, &r_shadow_fborectangle);CHECKGLERROR
2129 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fborectangle);CHECKGLERROR
2130 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, R_GetTexture(r_shadow_shadowmaprectangletexture), 0);CHECKGLERROR
2131 // render depth into the fbo, do not render color at all
2132 qglDrawBuffer(GL_NONE);CHECKGLERROR
2133 qglReadBuffer(GL_NONE);CHECKGLERROR
2134 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2135 if (status != GL_FRAMEBUFFER_COMPLETE_EXT && (r_shadow_shadowmapping.integer || r_shadow_deferred.integer))
2137 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2138 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2139 Cvar_SetValueQuick(&r_shadow_deferred, 0);
2144 if(r_shadow_shadowmaprectangletexture) fbo = r_shadow_fborectangle;
2145 r_shadow_shadowmap_texturescale[0] = 1.0f;
2146 r_shadow_shadowmap_texturescale[1] = 1.0f;
2147 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE;
2149 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
2151 r_shadow_shadowmap_parameters[0] = 1.0f;
2152 r_shadow_shadowmap_parameters[1] = 1.0f;
2153 R_Viewport_InitCubeSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, nearclip, farclip, NULL);
2154 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE) goto init_done;
2156 // simple cube approach
2157 if (!r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod])
2160 r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod] = R_LoadTextureShadowMapCube(r_shadow_texturepool, "shadowmapcube", size, r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
2161 qglGenFramebuffersEXT(1, &r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR
2162 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR
2163 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
2164 // render depth into the fbo, do not render color at all
2165 qglDrawBuffer(GL_NONE);CHECKGLERROR
2166 qglReadBuffer(GL_NONE);CHECKGLERROR
2167 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2168 if (status != GL_FRAMEBUFFER_COMPLETE_EXT && (r_shadow_shadowmapping.integer || r_shadow_deferred.integer))
2170 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2171 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2172 Cvar_SetValueQuick(&r_shadow_deferred, 0);
2177 if (r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]) fbo = r_shadow_fbocubeside[r_shadow_shadowmaplod];
2178 r_shadow_shadowmap_texturescale[0] = 0.0f;
2179 r_shadow_shadowmap_texturescale[1] = 0.0f;
2180 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE;
2183 R_Shadow_RenderMode_Reset();
2186 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);CHECKGLERROR
2187 R_SetupShader_DepthOrShadow();
2191 R_SetupShader_ShowDepth();
2192 qglClearColor(1,1,1,1);CHECKGLERROR
2195 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
2202 R_SetViewport(&viewport);
2203 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2204 if(r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE)
2206 int flipped = (side&1)^(side>>2);
2207 r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
2208 r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
2209 GL_CullFace(r_refdef.view.cullface_back);
2211 else if(r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE)
2213 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
2216 qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
2220 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
2224 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2225 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2226 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2227 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2230 R_Shadow_RenderMode_Reset();
2231 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2234 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2238 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2239 // only draw light where this geometry was already rendered AND the
2240 // stencil is 128 (values other than this mean shadow)
2241 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
2243 r_shadow_rendermode = r_shadow_lightingrendermode;
2244 // do global setup needed for the chosen lighting mode
2245 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2247 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2252 if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
2253 r_shadow_usingshadowmap2d = true;
2254 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE)
2255 r_shadow_usingshadowmaprect = true;
2256 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
2257 r_shadow_usingshadowmapcube = true;
2259 R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
2263 static const unsigned short bboxelements[36] =
2273 static const float bboxpoints[8][3] =
2285 void R_Shadow_RenderMode_DrawDeferredLight(qboolean stenciltest, qboolean shadowmapping)
2288 float vertex3f[8*3];
2289 const matrix4x4_t *matrix = &rsurface.rtlight->matrix_lighttoworld;
2291 R_Shadow_RenderMode_Reset();
2292 r_shadow_rendermode = r_shadow_lightingrendermode;
2293 // do global setup needed for the chosen lighting mode
2295 R_EntityMatrix(&identitymatrix);
2296 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2299 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2300 // only draw light where this geometry was already rendered AND the
2301 // stencil is 128 (values other than this mean shadow)
2302 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
2304 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepasslightingfbo);CHECKGLERROR
2307 if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
2308 r_shadow_usingshadowmap2d = true;
2309 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE)
2310 r_shadow_usingshadowmaprect = true;
2311 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
2312 r_shadow_usingshadowmapcube = true;
2315 // render the lighting
2316 R_SetupShader_DeferredLight(rsurface.rtlight);
2317 for (i = 0;i < 8;i++)
2318 Matrix4x4_Transform(matrix, bboxpoints[i], vertex3f + i*3);
2320 R_Mesh_VertexPointer(vertex3f, 0, 0);
2321 R_Mesh_ColorPointer(NULL, 0, 0);
2322 GL_ColorMask(1,1,1,1);
2323 GL_DepthMask(false);
2324 GL_DepthRange(0, 1);
2325 GL_PolygonOffset(0, 0);
2327 qglDepthFunc(GL_GREATER);CHECKGLERROR
2328 GL_CullFace(r_refdef.view.cullface_back);
2329 R_Mesh_Draw(0, 8, 0, 12, NULL, bboxelements, 0, 0);
2333 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
2336 R_Shadow_RenderMode_Reset();
2337 GL_BlendFunc(GL_ONE, GL_ONE);
2338 GL_DepthRange(0, 1);
2339 GL_DepthTest(r_showshadowvolumes.integer < 2);
2340 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
2341 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2342 GL_CullFace(GL_NONE);
2343 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
2346 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
2349 R_Shadow_RenderMode_Reset();
2350 GL_BlendFunc(GL_ONE, GL_ONE);
2351 GL_DepthRange(0, 1);
2352 GL_DepthTest(r_showlighting.integer < 2);
2353 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2356 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2360 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2361 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
2363 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2366 void R_Shadow_RenderMode_End(void)
2369 R_Shadow_RenderMode_Reset();
2370 R_Shadow_RenderMode_ActiveLight(NULL);
2372 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2373 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2376 int bboxedges[12][2] =
2395 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2397 int i, ix1, iy1, ix2, iy2;
2398 float x1, y1, x2, y2;
2400 float vertex[20][3];
2409 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2410 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2411 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2412 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2414 if (!r_shadow_scissor.integer)
2417 // if view is inside the light box, just say yes it's visible
2418 if (BoxesOverlap(r_refdef.view.origin, r_refdef.view.origin, mins, maxs))
2421 x1 = y1 = x2 = y2 = 0;
2423 // transform all corners that are infront of the nearclip plane
2424 VectorNegate(r_refdef.view.frustum[4].normal, plane4f);
2425 plane4f[3] = r_refdef.view.frustum[4].dist;
2427 for (i = 0;i < 8;i++)
2429 Vector4Set(corner[i], (i & 1) ? maxs[0] : mins[0], (i & 2) ? maxs[1] : mins[1], (i & 4) ? maxs[2] : mins[2], 1);
2430 dist[i] = DotProduct4(corner[i], plane4f);
2431 sign[i] = dist[i] > 0;
2434 VectorCopy(corner[i], vertex[numvertices]);
2438 // if some points are behind the nearclip, add clipped edge points to make
2439 // sure that the scissor boundary is complete
2440 if (numvertices > 0 && numvertices < 8)
2442 // add clipped edge points
2443 for (i = 0;i < 12;i++)
2445 j = bboxedges[i][0];
2446 k = bboxedges[i][1];
2447 if (sign[j] != sign[k])
2449 f = dist[j] / (dist[j] - dist[k]);
2450 VectorLerp(corner[j], f, corner[k], vertex[numvertices]);
2456 // if we have no points to check, the light is behind the view plane
2460 // if we have some points to transform, check what screen area is covered
2461 x1 = y1 = x2 = y2 = 0;
2463 //Con_Printf("%i vertices to transform...\n", numvertices);
2464 for (i = 0;i < numvertices;i++)
2466 VectorCopy(vertex[i], v);
2467 R_Viewport_TransformToScreen(&r_refdef.view.viewport, v, v2);
2468 //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]);
2471 if (x1 > v2[0]) x1 = v2[0];
2472 if (x2 < v2[0]) x2 = v2[0];
2473 if (y1 > v2[1]) y1 = v2[1];
2474 if (y2 < v2[1]) y2 = v2[1];
2483 // now convert the scissor rectangle to integer screen coordinates
2484 ix1 = (int)(x1 - 1.0f);
2485 iy1 = vid.height - (int)(y2 - 1.0f);
2486 ix2 = (int)(x2 + 1.0f);
2487 iy2 = vid.height - (int)(y1 + 1.0f);
2488 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
2490 // clamp it to the screen
2491 if (ix1 < r_refdef.view.viewport.x) ix1 = r_refdef.view.viewport.x;
2492 if (iy1 < r_refdef.view.viewport.y) iy1 = r_refdef.view.viewport.y;
2493 if (ix2 > r_refdef.view.viewport.x + r_refdef.view.viewport.width) ix2 = r_refdef.view.viewport.x + r_refdef.view.viewport.width;
2494 if (iy2 > r_refdef.view.viewport.y + r_refdef.view.viewport.height) iy2 = r_refdef.view.viewport.y + r_refdef.view.viewport.height;
2496 // if it is inside out, it's not visible
2497 if (ix2 <= ix1 || iy2 <= iy1)
2500 // the light area is visible, set up the scissor rectangle
2501 r_shadow_lightscissor[0] = ix1;
2502 r_shadow_lightscissor[1] = iy1;
2503 r_shadow_lightscissor[2] = ix2 - ix1;
2504 r_shadow_lightscissor[3] = iy2 - iy1;
2506 r_refdef.stats.lights_scissored++;
2510 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, int numtriangles, const int *element3i, const float *diffusecolor, const float *ambientcolor)
2512 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
2513 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
2514 float *color4f = rsurface.array_color4f + 4 * firstvertex;
2515 float dist, dot, distintensity, shadeintensity, v[3], n[3];
2516 switch (r_shadow_rendermode)
2518 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2519 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2520 if (VectorLength2(diffusecolor) > 0)
2522 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2524 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2525 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2526 if ((dot = DotProduct(n, v)) < 0)
2528 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2529 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
2532 VectorCopy(ambientcolor, color4f);
2533 if (r_refdef.fogenabled)
2536 f = RSurf_FogVertex(vertex3f);
2537 VectorScale(color4f, f, color4f);
2544 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2546 VectorCopy(ambientcolor, color4f);
2547 if (r_refdef.fogenabled)
2550 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2551 f = RSurf_FogVertex(vertex3f);
2552 VectorScale(color4f, f, color4f);
2558 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2559 if (VectorLength2(diffusecolor) > 0)
2561 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2563 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2564 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2566 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2567 if ((dot = DotProduct(n, v)) < 0)
2569 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2570 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2571 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2572 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2576 color4f[0] = ambientcolor[0] * distintensity;
2577 color4f[1] = ambientcolor[1] * distintensity;
2578 color4f[2] = ambientcolor[2] * distintensity;
2580 if (r_refdef.fogenabled)
2583 f = RSurf_FogVertex(vertex3f);
2584 VectorScale(color4f, f, color4f);
2588 VectorClear(color4f);
2594 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2596 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2597 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2599 color4f[0] = ambientcolor[0] * distintensity;
2600 color4f[1] = ambientcolor[1] * distintensity;
2601 color4f[2] = ambientcolor[2] * distintensity;
2602 if (r_refdef.fogenabled)
2605 f = RSurf_FogVertex(vertex3f);
2606 VectorScale(color4f, f, color4f);
2610 VectorClear(color4f);
2615 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2616 if (VectorLength2(diffusecolor) > 0)
2618 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2620 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2621 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2623 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2624 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2625 if ((dot = DotProduct(n, v)) < 0)
2627 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2628 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2629 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2630 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2634 color4f[0] = ambientcolor[0] * distintensity;
2635 color4f[1] = ambientcolor[1] * distintensity;
2636 color4f[2] = ambientcolor[2] * distintensity;
2638 if (r_refdef.fogenabled)
2641 f = RSurf_FogVertex(vertex3f);
2642 VectorScale(color4f, f, color4f);
2646 VectorClear(color4f);
2652 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2654 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2655 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2657 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2658 color4f[0] = ambientcolor[0] * distintensity;
2659 color4f[1] = ambientcolor[1] * distintensity;
2660 color4f[2] = ambientcolor[2] * distintensity;
2661 if (r_refdef.fogenabled)
2664 f = RSurf_FogVertex(vertex3f);
2665 VectorScale(color4f, f, color4f);
2669 VectorClear(color4f);
2679 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)
2681 // used to display how many times a surface is lit for level design purposes
2682 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2685 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)
2687 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2688 R_SetupShader_Surface(lightcolor, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT);
2689 if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND))
2690 R_Mesh_ColorPointer(rsurface.modellightmapcolor4f, rsurface.modellightmapcolor4f_bufferobject, rsurface.modellightmapcolor4f_bufferoffset);
2692 R_Mesh_ColorPointer(NULL, 0, 0);
2693 R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
2694 R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset);
2695 R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset);
2696 R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset);
2697 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2699 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2701 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2702 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2704 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
2708 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
2715 int newnumtriangles;
2719 int maxtriangles = 4096;
2720 static int newelements[4096*3];
2721 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, numtriangles, element3i, diffusecolor2, ambientcolor2);
2722 for (renders = 0;renders < 64;renders++)
2727 newnumtriangles = 0;
2729 // due to low fillrate on the cards this vertex lighting path is
2730 // designed for, we manually cull all triangles that do not
2731 // contain a lit vertex
2732 // this builds batches of triangles from multiple surfaces and
2733 // renders them at once
2734 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
2736 if (VectorLength2(rsurface.array_color4f + e[0] * 4) + VectorLength2(rsurface.array_color4f + e[1] * 4) + VectorLength2(rsurface.array_color4f + e[2] * 4) >= 0.01)
2738 if (newnumtriangles)
2740 newfirstvertex = min(newfirstvertex, e[0]);
2741 newlastvertex = max(newlastvertex, e[0]);
2745 newfirstvertex = e[0];
2746 newlastvertex = e[0];
2748 newfirstvertex = min(newfirstvertex, e[1]);
2749 newlastvertex = max(newlastvertex, e[1]);
2750 newfirstvertex = min(newfirstvertex, e[2]);
2751 newlastvertex = max(newlastvertex, e[2]);
2757 if (newnumtriangles >= maxtriangles)
2759 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
2760 newnumtriangles = 0;
2766 if (newnumtriangles >= 1)
2768 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
2771 // if we couldn't find any lit triangles, exit early
2774 // now reduce the intensity for the next overbright pass
2775 // we have to clamp to 0 here incase the drivers have improper
2776 // handling of negative colors
2777 // (some old drivers even have improper handling of >1 color)
2779 for (i = 0, c = rsurface.array_color4f + 4 * firstvertex;i < numvertices;i++, c += 4)
2781 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
2783 c[0] = max(0, c[0] - 1);
2784 c[1] = max(0, c[1] - 1);
2785 c[2] = max(0, c[2] - 1);
2797 static void R_Shadow_RenderLighting_Light_Vertex(int firstvertex, int numvertices, int numtriangles, const int *element3i, const vec3_t lightcolor, float ambientscale, float diffusescale)
2799 // OpenGL 1.1 path (anything)
2800 float ambientcolorbase[3], diffusecolorbase[3];
2801 float ambientcolorpants[3], diffusecolorpants[3];
2802 float ambientcolorshirt[3], diffusecolorshirt[3];
2803 const float *surfacecolor = rsurface.texture->dlightcolor;
2804 const float *surfacepants = rsurface.colormap_pantscolor;
2805 const float *surfaceshirt = rsurface.colormap_shirtcolor;
2806 rtexture_t *basetexture = rsurface.texture->basetexture;
2807 rtexture_t *pantstexture = rsurface.texture->pantstexture;
2808 rtexture_t *shirttexture = rsurface.texture->shirttexture;
2809 qboolean dopants = pantstexture && VectorLength2(surfacepants) >= (1.0f / 1048576.0f);
2810 qboolean doshirt = shirttexture && VectorLength2(surfaceshirt) >= (1.0f / 1048576.0f);
2811 ambientscale *= 2 * r_refdef.view.colorscale;
2812 diffusescale *= 2 * r_refdef.view.colorscale;
2813 ambientcolorbase[0] = lightcolor[0] * ambientscale * surfacecolor[0];ambientcolorbase[1] = lightcolor[1] * ambientscale * surfacecolor[1];ambientcolorbase[2] = lightcolor[2] * ambientscale * surfacecolor[2];
2814 diffusecolorbase[0] = lightcolor[0] * diffusescale * surfacecolor[0];diffusecolorbase[1] = lightcolor[1] * diffusescale * surfacecolor[1];diffusecolorbase[2] = lightcolor[2] * diffusescale * surfacecolor[2];
2815 ambientcolorpants[0] = ambientcolorbase[0] * surfacepants[0];ambientcolorpants[1] = ambientcolorbase[1] * surfacepants[1];ambientcolorpants[2] = ambientcolorbase[2] * surfacepants[2];
2816 diffusecolorpants[0] = diffusecolorbase[0] * surfacepants[0];diffusecolorpants[1] = diffusecolorbase[1] * surfacepants[1];diffusecolorpants[2] = diffusecolorbase[2] * surfacepants[2];
2817 ambientcolorshirt[0] = ambientcolorbase[0] * surfaceshirt[0];ambientcolorshirt[1] = ambientcolorbase[1] * surfaceshirt[1];ambientcolorshirt[2] = ambientcolorbase[2] * surfaceshirt[2];
2818 diffusecolorshirt[0] = diffusecolorbase[0] * surfaceshirt[0];diffusecolorshirt[1] = diffusecolorbase[1] * surfaceshirt[1];diffusecolorshirt[2] = diffusecolorbase[2] * surfaceshirt[2];
2819 R_Mesh_TexBind(0, R_GetTexture(basetexture));
2820 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
2821 R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
2822 R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
2823 switch(r_shadow_rendermode)
2825 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2826 R_Mesh_TexBindAll(1, 0, R_GetTexture(r_shadow_attenuation3dtexture), 0, 0);
2827 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
2828 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
2829 R_Mesh_TexCoordPointer(1, 3, rsurface.vertex3f, rsurface.vertex3f_bufferobject, rsurface.vertex3f_bufferoffset);
2831 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2832 R_Mesh_TexBind(2, R_GetTexture(r_shadow_attenuation2dtexture));
2833 R_Mesh_TexMatrix(2, &rsurface.entitytoattenuationz);
2834 R_Mesh_TexCombine(2, GL_MODULATE, GL_MODULATE, 1, 1);
2835 R_Mesh_TexCoordPointer(2, 3, rsurface.vertex3f, rsurface.vertex3f_bufferobject, rsurface.vertex3f_bufferoffset);
2837 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2838 R_Mesh_TexBind(1, R_GetTexture(r_shadow_attenuation2dtexture));
2839 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
2840 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
2841 R_Mesh_TexCoordPointer(1, 3, rsurface.vertex3f, rsurface.vertex3f_bufferobject, rsurface.vertex3f_bufferoffset);
2843 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2848 //R_Mesh_TexBind(0, R_GetTexture(basetexture));
2849 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorbase, ambientcolorbase);
2852 R_Mesh_TexBind(0, R_GetTexture(pantstexture));
2853 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorpants, ambientcolorpants);
2857 R_Mesh_TexBind(0, R_GetTexture(shirttexture));
2858 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorshirt, ambientcolorshirt);
2862 extern cvar_t gl_lightmaps;
2863 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)
2865 float ambientscale, diffusescale, specularscale;
2867 float lightcolor[3];
2868 VectorCopy(rsurface.rtlight->currentcolor, lightcolor);
2869 ambientscale = rsurface.rtlight->ambientscale;
2870 diffusescale = rsurface.rtlight->diffusescale;
2871 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
2872 if (!r_shadow_usenormalmap.integer)
2874 ambientscale += 1.0f * diffusescale;
2878 if ((ambientscale + diffusescale) * VectorLength2(lightcolor) + specularscale * VectorLength2(lightcolor) < (1.0f / 1048576.0f))
2880 negated = (lightcolor[0] + lightcolor[1] + lightcolor[2] < 0) && vid.support.ext_blend_subtract;
2883 VectorNegate(lightcolor, lightcolor);
2884 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
2886 RSurf_SetupDepthAndCulling();
2887 switch (r_shadow_rendermode)
2889 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2890 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2891 R_Shadow_RenderLighting_VisibleLighting(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2893 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2894 R_Shadow_RenderLighting_Light_GLSL(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolor, ambientscale, diffusescale, specularscale);
2896 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2897 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2898 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2899 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2900 R_Shadow_RenderLighting_Light_Vertex(firstvertex, numvertices, numtriangles, element3i + firsttriangle * 3, lightcolor, ambientscale, diffusescale);
2903 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2907 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
2910 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)
2912 matrix4x4_t tempmatrix = *matrix;
2913 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
2915 // if this light has been compiled before, free the associated data
2916 R_RTLight_Uncompile(rtlight);
2918 // clear it completely to avoid any lingering data
2919 memset(rtlight, 0, sizeof(*rtlight));
2921 // copy the properties
2922 rtlight->matrix_lighttoworld = tempmatrix;
2923 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
2924 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
2925 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
2926 VectorCopy(color, rtlight->color);
2927 rtlight->cubemapname[0] = 0;
2928 if (cubemapname && cubemapname[0])
2929 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
2930 rtlight->shadow = shadow;
2931 rtlight->corona = corona;
2932 rtlight->style = style;
2933 rtlight->isstatic = isstatic;
2934 rtlight->coronasizescale = coronasizescale;
2935 rtlight->ambientscale = ambientscale;
2936 rtlight->diffusescale = diffusescale;
2937 rtlight->specularscale = specularscale;
2938 rtlight->flags = flags;
2940 // compute derived data
2941 //rtlight->cullradius = rtlight->radius;
2942 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2943 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2944 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2945 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2946 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2947 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2948 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2951 // compiles rtlight geometry
2952 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2953 void R_RTLight_Compile(rtlight_t *rtlight)
2956 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
2957 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
2958 entity_render_t *ent = r_refdef.scene.worldentity;
2959 dp_model_t *model = r_refdef.scene.worldmodel;
2960 unsigned char *data;
2963 // compile the light
2964 rtlight->compiled = true;
2965 rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
2966 rtlight->static_numleafs = 0;
2967 rtlight->static_numleafpvsbytes = 0;
2968 rtlight->static_leaflist = NULL;
2969 rtlight->static_leafpvs = NULL;
2970 rtlight->static_numsurfaces = 0;
2971 rtlight->static_surfacelist = NULL;
2972 rtlight->static_shadowmap_receivers = 0x3F;
2973 rtlight->static_shadowmap_casters = 0x3F;
2974 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2975 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2976 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2977 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2978 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2979 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2981 if (model && model->GetLightInfo)
2983 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
2984 r_shadow_compilingrtlight = rtlight;
2985 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);
2986 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2987 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
2988 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
2989 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
2990 rtlight->static_numsurfaces = numsurfaces;
2991 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
2992 rtlight->static_numleafs = numleafs;
2993 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
2994 rtlight->static_numleafpvsbytes = numleafpvsbytes;
2995 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
2996 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
2997 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
2998 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
2999 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3000 if (rtlight->static_numsurfaces)
3001 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3002 if (rtlight->static_numleafs)
3003 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3004 if (rtlight->static_numleafpvsbytes)
3005 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3006 if (rtlight->static_numshadowtrispvsbytes)
3007 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3008 if (rtlight->static_numlighttrispvsbytes)
3009 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3010 switch (rtlight->shadowmode)
3012 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
3013 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
3014 case R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE:
3015 if (model->CompileShadowMap && rtlight->shadow)
3016 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3019 if (model->CompileShadowVolume && rtlight->shadow)
3020 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3023 // now we're done compiling the rtlight
3024 r_shadow_compilingrtlight = NULL;
3028 // use smallest available cullradius - box radius or light radius
3029 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3030 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3032 shadowzpasstris = 0;
3033 if (rtlight->static_meshchain_shadow_zpass)
3034 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
3035 shadowzpasstris += mesh->numtriangles;
3037 shadowzfailtris = 0;
3038 if (rtlight->static_meshchain_shadow_zfail)
3039 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
3040 shadowzfailtris += mesh->numtriangles;
3043 if (rtlight->static_numlighttrispvsbytes)
3044 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3045 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3049 if (rtlight->static_numlighttrispvsbytes)
3050 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3051 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3054 if (developer.integer >= 10)
3055 Con_Printf("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);
3058 void R_RTLight_Uncompile(rtlight_t *rtlight)
3060 if (rtlight->compiled)
3062 if (rtlight->static_meshchain_shadow_zpass)
3063 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
3064 rtlight->static_meshchain_shadow_zpass = NULL;
3065 if (rtlight->static_meshchain_shadow_zfail)
3066 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
3067 rtlight->static_meshchain_shadow_zfail = NULL;
3068 if (rtlight->static_meshchain_shadow_shadowmap)
3069 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
3070 rtlight->static_meshchain_shadow_shadowmap = NULL;
3071 // these allocations are grouped
3072 if (rtlight->static_surfacelist)
3073 Mem_Free(rtlight->static_surfacelist);
3074 rtlight->static_numleafs = 0;
3075 rtlight->static_numleafpvsbytes = 0;
3076 rtlight->static_leaflist = NULL;
3077 rtlight->static_leafpvs = NULL;
3078 rtlight->static_numsurfaces = 0;
3079 rtlight->static_surfacelist = NULL;
3080 rtlight->static_numshadowtrispvsbytes = 0;
3081 rtlight->static_shadowtrispvs = NULL;
3082 rtlight->static_numlighttrispvsbytes = 0;
3083 rtlight->static_lighttrispvs = NULL;
3084 rtlight->compiled = false;
3088 void R_Shadow_UncompileWorldLights(void)
3092 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3093 for (lightindex = 0;lightindex < range;lightindex++)
3095 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3098 R_RTLight_Uncompile(&light->rtlight);
3102 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3106 // reset the count of frustum planes
3107 // see rtlight->cached_frustumplanes definition for how much this array
3109 rtlight->cached_numfrustumplanes = 0;
3111 // haven't implemented a culling path for ortho rendering
3112 if (!r_refdef.view.useperspective)
3114 // check if the light is on screen and copy the 4 planes if it is
3115 for (i = 0;i < 4;i++)
3116 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3119 for (i = 0;i < 4;i++)
3120 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3125 // generate a deformed frustum that includes the light origin, this is
3126 // used to cull shadow casting surfaces that can not possibly cast a
3127 // shadow onto the visible light-receiving surfaces, which can be a
3130 // if the light origin is onscreen the result will be 4 planes exactly
3131 // if the light origin is offscreen on only one axis the result will
3132 // be exactly 5 planes (split-side case)
3133 // if the light origin is offscreen on two axes the result will be
3134 // exactly 4 planes (stretched corner case)
3135 for (i = 0;i < 4;i++)
3137 // quickly reject standard frustum planes that put the light
3138 // origin outside the frustum
3139 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3142 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3144 // if all the standard frustum planes were accepted, the light is onscreen
3145 // otherwise we need to generate some more planes below...
3146 if (rtlight->cached_numfrustumplanes < 4)
3148 // at least one of the stock frustum planes failed, so we need to
3149 // create one or two custom planes to enclose the light origin
3150 for (i = 0;i < 4;i++)
3152 // create a plane using the view origin and light origin, and a
3153 // single point from the frustum corner set
3154 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3155 VectorNormalize(plane.normal);
3156 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3157 // see if this plane is backwards and flip it if so
3158 for (j = 0;j < 4;j++)
3159 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3163 VectorNegate(plane.normal, plane.normal);
3165 // flipped plane, test again to see if it is now valid
3166 for (j = 0;j < 4;j++)
3167 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3169 // if the plane is still not valid, then it is dividing the
3170 // frustum and has to be rejected
3174 // we have created a valid plane, compute extra info
3175 PlaneClassify(&plane);
3177 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3179 // if we've found 5 frustum planes then we have constructed a
3180 // proper split-side case and do not need to keep searching for
3181 // planes to enclose the light origin
3182 if (rtlight->cached_numfrustumplanes == 5)
3190 for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
3192 plane = rtlight->cached_frustumplanes[i];
3193 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));
3198 // now add the light-space box planes if the light box is rotated, as any
3199 // caster outside the oriented light box is irrelevant (even if it passed
3200 // the worldspace light box, which is axial)
3201 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3203 for (i = 0;i < 6;i++)
3207 v[i >> 1] = (i & 1) ? -1 : 1;
3208 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3209 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3210 plane.dist = VectorNormalizeLength(plane.normal);
3211 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3212 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3218 // add the world-space reduced box planes
3219 for (i = 0;i < 6;i++)
3221 VectorClear(plane.normal);
3222 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3223 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
3224 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3233 // reduce all plane distances to tightly fit the rtlight cull box, which
3235 VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3236 VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3237 VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3238 VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3239 VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3240 VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3241 VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3242 VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3243 oldnum = rtlight->cached_numfrustumplanes;
3244 rtlight->cached_numfrustumplanes = 0;
3245 for (j = 0;j < oldnum;j++)
3247 // find the nearest point on the box to this plane
3248 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
3249 for (i = 1;i < 8;i++)
3251 dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
3252 if (bestdist > dist)
3255 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);
3256 // if the nearest point is near or behind the plane, we want this
3257 // plane, otherwise the plane is useless as it won't cull anything
3258 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
3260 PlaneClassify(&rtlight->cached_frustumplanes[j]);
3261 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
3268 void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
3272 RSurf_ActiveWorldEntity();
3274 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3277 GL_CullFace(GL_NONE);
3278 mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3279 for (;mesh;mesh = mesh->next)
3281 if (!mesh->sidetotals[r_shadow_shadowmapside])
3283 r_refdef.stats.lights_shadowtriangles += mesh->sidetotals[r_shadow_shadowmapside];
3284 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
3285 R_Mesh_Draw(0, mesh->numverts, mesh->sideoffsets[r_shadow_shadowmapside], mesh->sidetotals[r_shadow_shadowmapside], mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3289 else if (r_refdef.scene.worldentity->model)
3290 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);
3292 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3295 void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3297 qboolean zpass = false;
3300 int surfacelistindex;
3301 msurface_t *surface;
3303 RSurf_ActiveWorldEntity();
3305 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3308 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
3310 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
3311 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
3313 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
3314 for (;mesh;mesh = mesh->next)
3316 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
3317 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
3318 GL_LockArrays(0, mesh->numverts);
3319 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
3321 // increment stencil if frontface is infront of depthbuffer
3322 GL_CullFace(r_refdef.view.cullface_back);
3323 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
3324 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3325 // decrement stencil if backface is infront of depthbuffer
3326 GL_CullFace(r_refdef.view.cullface_front);
3327 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
3329 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
3331 // decrement stencil if backface is behind depthbuffer
3332 GL_CullFace(r_refdef.view.cullface_front);
3333 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
3334 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3335 // increment stencil if frontface is behind depthbuffer
3336 GL_CullFace(r_refdef.view.cullface_back);
3337 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
3339 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3340 GL_LockArrays(0, 0);
3344 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh && r_shadow_culltriangles.integer)
3346 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
3347 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
3349 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
3350 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
3351 if (CHECKPVSBIT(trispvs, t))
3352 shadowmarklist[numshadowmark++] = t;
3354 R_Shadow_VolumeFromList(r_refdef.scene.worldmodel->brush.shadowmesh->numverts, r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles, r_refdef.scene.worldmodel->brush.shadowmesh->vertex3f, r_refdef.scene.worldmodel->brush.shadowmesh->element3i, r_refdef.scene.worldmodel->brush.shadowmesh->neighbor3i, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius + r_refdef.scene.worldmodel->radius*2 + r_shadow_projectdistance.value, numshadowmark, shadowmarklist, r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
3356 else if (numsurfaces)
3357 r_refdef.scene.worldmodel->DrawShadowVolume(r_refdef.scene.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, rsurface.rtlight->cached_cullmins, rsurface.rtlight->cached_cullmaxs);
3359 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3362 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3364 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3365 vec_t relativeshadowradius;
3366 RSurf_ActiveModelEntity(ent, false, false, false);
3367 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3368 // we need to re-init the shader for each entity because the matrix changed
3369 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3370 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3371 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3372 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3373 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3374 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3375 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3376 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D)
3378 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
3381 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3382 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3385 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3387 // set up properties for rendering light onto this entity
3388 RSurf_ActiveModelEntity(ent, true, true, false);
3389 GL_AlphaTest(false);
3390 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3391 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3392 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3393 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3396 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3398 if (!r_refdef.scene.worldmodel->DrawLight)
3401 // set up properties for rendering light onto this entity
3402 RSurf_ActiveWorldEntity();
3403 GL_AlphaTest(false);
3404 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3405 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3406 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3407 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3409 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, trispvs);
3411 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3414 void R_Shadow_DrawEntityLight(entity_render_t *ent)
3416 dp_model_t *model = ent->model;
3417 if (!model->DrawLight)
3420 R_Shadow_SetupEntityLight(ent);
3422 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3424 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3427 void R_Shadow_PrepareLight(rtlight_t *rtlight)
3431 int numleafs, numsurfaces;
3432 int *leaflist, *surfacelist;
3433 unsigned char *leafpvs, *shadowtrispvs, *lighttrispvs, *surfacesides;
3434 int numlightentities;
3435 int numlightentities_noselfshadow;
3436 int numshadowentities;
3437 int numshadowentities_noselfshadow;
3438 static entity_render_t *lightentities[MAX_EDICTS];
3439 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3440 static entity_render_t *shadowentities[MAX_EDICTS];
3441 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3443 rtlight->draw = false;
3445 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3446 // skip lights that are basically invisible (color 0 0 0)
3447 if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
3450 // loading is done before visibility checks because loading should happen
3451 // all at once at the start of a level, not when it stalls gameplay.
3452 // (especially important to benchmarks)
3454 if (rtlight->isstatic && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
3456 if (rtlight->compiled)
3457 R_RTLight_Uncompile(rtlight);
3458 R_RTLight_Compile(rtlight);
3462 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
3464 // look up the light style value at this time
3465 f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3466 VectorScale(rtlight->color, f, rtlight->currentcolor);
3468 if (rtlight->selected)
3470 f = 2 + sin(realtime * M_PI * 4.0);
3471 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3475 // if lightstyle is currently off, don't draw the light
3476 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3479 // if the light box is offscreen, skip it
3480 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3483 VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
3484 VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
3486 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3488 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3490 // compiled light, world available and can receive realtime lighting
3491 // retrieve leaf information
3492 numleafs = rtlight->static_numleafs;
3493 leaflist = rtlight->static_leaflist;
3494 leafpvs = rtlight->static_leafpvs;
3495 numsurfaces = rtlight->static_numsurfaces;
3496 surfacelist = rtlight->static_surfacelist;
3497 surfacesides = NULL;
3498 shadowtrispvs = rtlight->static_shadowtrispvs;
3499 lighttrispvs = rtlight->static_lighttrispvs;
3501 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3503 // dynamic light, world available and can receive realtime lighting
3504 // calculate lit surfaces and leafs
3505 r_refdef.scene.worldmodel->GetLightInfo(r_refdef.scene.worldentity, rtlight->shadoworigin, rtlight->radius, rtlight->cached_cullmins, rtlight->cached_cullmaxs, r_shadow_buffer_leaflist, r_shadow_buffer_leafpvs, &numleafs, r_shadow_buffer_surfacelist, r_shadow_buffer_surfacepvs, &numsurfaces, r_shadow_buffer_shadowtrispvs, r_shadow_buffer_lighttrispvs, r_shadow_buffer_visitingleafpvs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes);
3506 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3507 leaflist = r_shadow_buffer_leaflist;
3508 leafpvs = r_shadow_buffer_leafpvs;
3509 surfacelist = r_shadow_buffer_surfacelist;
3510 surfacesides = r_shadow_buffer_surfacesides;
3511 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3512 lighttrispvs = r_shadow_buffer_lighttrispvs;
3513 // if the reduced leaf bounds are offscreen, skip it
3514 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3525 surfacesides = NULL;
3526 shadowtrispvs = NULL;
3527 lighttrispvs = NULL;
3529 // check if light is illuminating any visible leafs
3532 for (i = 0;i < numleafs;i++)
3533 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3539 // make a list of lit entities and shadow casting entities
3540 numlightentities = 0;
3541 numlightentities_noselfshadow = 0;
3542 numshadowentities = 0;
3543 numshadowentities_noselfshadow = 0;
3545 // add dynamic entities that are lit by the light
3546 for (i = 0;i < r_refdef.scene.numentities;i++)
3549 entity_render_t *ent = r_refdef.scene.entities[i];
3551 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3553 // skip the object entirely if it is not within the valid
3554 // shadow-casting region (which includes the lit region)
3555 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
3557 if (!(model = ent->model))
3559 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
3561 // this entity wants to receive light, is visible, and is
3562 // inside the light box
3563 // TODO: check if the surfaces in the model can receive light
3564 // so now check if it's in a leaf seen by the light
3565 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.BoxTouchingLeafPVS && !r_refdef.scene.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.scene.worldmodel, leafpvs, ent->mins, ent->maxs))
3567 if (ent->flags & RENDER_NOSELFSHADOW)
3568 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
3570 lightentities[numlightentities++] = ent;
3571 // since it is lit, it probably also casts a shadow...
3572 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3573 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3574 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3576 // note: exterior models without the RENDER_NOSELFSHADOW
3577 // flag still create a RENDER_NOSELFSHADOW shadow but
3578 // are lit normally, this means that they are
3579 // self-shadowing but do not shadow other
3580 // RENDER_NOSELFSHADOW entities such as the gun
3581 // (very weird, but keeps the player shadow off the gun)
3582 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3583 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3585 shadowentities[numshadowentities++] = ent;
3588 else if (ent->flags & RENDER_SHADOW)
3590 // this entity is not receiving light, but may still need to
3592 // TODO: check if the surfaces in the model can cast shadow
3593 // now check if it is in a leaf seen by the light
3594 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.BoxTouchingLeafPVS && !r_refdef.scene.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.scene.worldmodel, leafpvs, ent->mins, ent->maxs))
3596 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3597 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3598 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3600 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3601 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3603 shadowentities[numshadowentities++] = ent;
3608 // return if there's nothing at all to light
3609 if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
3612 // count this light in the r_speeds
3613 r_refdef.stats.lights++;
3615 // flag it as worth drawing later
3616 rtlight->draw = true;
3618 // cache all the animated entities that cast a shadow but are not visible
3619 for (i = 0;i < numshadowentities;i++)
3620 if (!shadowentities[i]->animcache_vertex3f)
3621 R_AnimCache_GetEntity(shadowentities[i], false, false);
3622 for (i = 0;i < numshadowentities_noselfshadow;i++)
3623 if (!shadowentities_noselfshadow[i]->animcache_vertex3f)
3624 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
3626 // allocate some temporary memory for rendering this light later in the frame
3627 // reusable buffers need to be copied, static data can be used as-is
3628 rtlight->cached_numlightentities = numlightentities;
3629 rtlight->cached_numlightentities_noselfshadow = numlightentities_noselfshadow;
3630 rtlight->cached_numshadowentities = numshadowentities;
3631 rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
3632 rtlight->cached_numsurfaces = numsurfaces;
3633 rtlight->cached_lightentities = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
3634 rtlight->cached_lightentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
3635 rtlight->cached_shadowentities = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
3636 rtlight->cached_shadowentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
3637 if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
3639 int numshadowtrispvsbytes = (((r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles) + 7) >> 3);
3640 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
3641 rtlight->cached_shadowtrispvs = (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
3642 rtlight->cached_lighttrispvs = (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
3643 rtlight->cached_surfacelist = (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
3647 // compiled light data
3648 rtlight->cached_shadowtrispvs = shadowtrispvs;
3649 rtlight->cached_lighttrispvs = lighttrispvs;
3650 rtlight->cached_surfacelist = surfacelist;
3654 void R_Shadow_DrawLight(rtlight_t *rtlight)
3658 unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
3659 int numlightentities;
3660 int numlightentities_noselfshadow;
3661 int numshadowentities;
3662 int numshadowentities_noselfshadow;
3663 entity_render_t **lightentities;
3664 entity_render_t **lightentities_noselfshadow;
3665 entity_render_t **shadowentities;
3666 entity_render_t **shadowentities_noselfshadow;
3668 static unsigned char entitysides[MAX_EDICTS];
3669 static unsigned char entitysides_noselfshadow[MAX_EDICTS];
3670 vec3_t nearestpoint;
3672 qboolean castshadows;
3675 // check if we cached this light this frame (meaning it is worth drawing)
3679 // if R_FrameData_Store ran out of space we skip anything dependent on it
3680 if (r_framedata_failed)
3683 numlightentities = rtlight->cached_numlightentities;
3684 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
3685 numshadowentities = rtlight->cached_numshadowentities;
3686 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
3687 numsurfaces = rtlight->cached_numsurfaces;
3688 lightentities = rtlight->cached_lightentities;
3689 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
3690 shadowentities = rtlight->cached_shadowentities;
3691 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
3692 shadowtrispvs = rtlight->cached_shadowtrispvs;
3693 lighttrispvs = rtlight->cached_lighttrispvs;
3694 surfacelist = rtlight->cached_surfacelist;
3696 // set up a scissor rectangle for this light
3697 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3700 // don't let sound skip if going slow
3701 if (r_refdef.scene.extraupdate)
3704 // make this the active rtlight for rendering purposes
3705 R_Shadow_RenderMode_ActiveLight(rtlight);
3707 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
3709 // optionally draw visible shape of the shadow volumes
3710 // for performance analysis by level designers
3711 R_Shadow_RenderMode_VisibleShadowVolumes();
3713 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
3714 for (i = 0;i < numshadowentities;i++)
3715 R_Shadow_DrawEntityShadow(shadowentities[i]);
3716 for (i = 0;i < numshadowentities_noselfshadow;i++)
3717 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3718 R_Shadow_RenderMode_VisibleLighting(false, false);
3721 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
3723 // optionally draw the illuminated areas
3724 // for performance analysis by level designers
3725 R_Shadow_RenderMode_VisibleLighting(false, false);
3727 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3728 for (i = 0;i < numlightentities;i++)
3729 R_Shadow_DrawEntityLight(lightentities[i]);
3730 for (i = 0;i < numlightentities_noselfshadow;i++)
3731 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3734 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
3736 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
3737 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
3738 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
3739 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
3741 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance/rtlight->radius));
3742 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
3743 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
3745 if (castshadows && (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE))
3751 int receivermask = 0;
3752 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
3753 Matrix4x4_Abs(&radiustolight);
3755 r_shadow_shadowmaplod = 0;
3756 for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
3757 if ((r_shadow_shadowmapmaxsize >> i) > lodlinear)
3758 r_shadow_shadowmaplod = i;
3760 if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
3761 size = max(1, r_shadow_shadowmapmaxsize >> r_shadow_shadowmaplod);
3763 size = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
3765 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
3767 surfacesides = NULL;
3770 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3772 castermask = rtlight->static_shadowmap_casters;
3773 receivermask = rtlight->static_shadowmap_receivers;
3777 surfacesides = r_shadow_buffer_surfacesides;
3778 for(i = 0;i < numsurfaces;i++)
3780 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
3781 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3782 castermask |= surfacesides[i];
3783 receivermask |= surfacesides[i];
3787 if (receivermask < 0x3F)
3789 for (i = 0;i < numlightentities;i++)
3790 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3791 if (receivermask < 0x3F)
3792 for(i = 0; i < numlightentities_noselfshadow;i++)
3793 receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3796 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
3800 for (i = 0;i < numshadowentities;i++)
3801 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3802 for (i = 0;i < numshadowentities_noselfshadow;i++)
3803 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3806 //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
3808 // render shadow casters into 6 sided depth texture
3809 for (side = 0;side < 6;side++) if (receivermask & (1 << side))
3811 R_Shadow_RenderMode_ShadowMap(side, true, size);
3812 if (! (castermask & (1 << side))) continue;
3814 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
3815 for (i = 0;i < numshadowentities;i++) if (entitysides[i] & (1 << side))
3816 R_Shadow_DrawEntityShadow(shadowentities[i]);
3819 if (numlightentities_noselfshadow)
3821 // render lighting using the depth texture as shadowmap
3822 // draw lighting in the unmasked areas
3823 R_Shadow_RenderMode_Lighting(false, false, true);
3824 for (i = 0;i < numlightentities_noselfshadow;i++)
3825 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3828 // render shadow casters into 6 sided depth texture
3829 if (numshadowentities_noselfshadow)
3831 for (side = 0;side < 6;side++) if ((receivermask & castermask) & (1 << side))
3833 R_Shadow_RenderMode_ShadowMap(side, false, size);
3834 for (i = 0;i < numshadowentities_noselfshadow;i++) if (entitysides_noselfshadow[i] & (1 << side))
3835 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3839 // render lighting using the depth texture as shadowmap
3840 // draw lighting in the unmasked areas
3841 R_Shadow_RenderMode_Lighting(false, false, true);
3842 // draw lighting in the unmasked areas
3844 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3845 for (i = 0;i < numlightentities;i++)
3846 R_Shadow_DrawEntityLight(lightentities[i]);
3848 else if (castshadows && vid.stencil)
3850 // draw stencil shadow volumes to mask off pixels that are in shadow
3851 // so that they won't receive lighting
3852 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
3853 R_Shadow_ClearStencil();
3856 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
3857 for (i = 0;i < numshadowentities;i++)
3858 R_Shadow_DrawEntityShadow(shadowentities[i]);
3860 // draw lighting in the unmasked areas
3861 R_Shadow_RenderMode_Lighting(true, false, false);
3862 for (i = 0;i < numlightentities_noselfshadow;i++)
3863 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3865 for (i = 0;i < numshadowentities_noselfshadow;i++)
3866 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3868 // draw lighting in the unmasked areas
3869 R_Shadow_RenderMode_Lighting(true, false, false);
3871 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3872 for (i = 0;i < numlightentities;i++)
3873 R_Shadow_DrawEntityLight(lightentities[i]);
3877 // draw lighting in the unmasked areas
3878 R_Shadow_RenderMode_Lighting(false, false, false);
3880 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3881 for (i = 0;i < numlightentities;i++)
3882 R_Shadow_DrawEntityLight(lightentities[i]);
3883 for (i = 0;i < numlightentities_noselfshadow;i++)
3884 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3887 if (r_shadow_usingdeferredprepass)
3889 // when rendering deferred lighting, we simply rasterize the box
3890 if (castshadows && (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE))
3891 R_Shadow_RenderMode_DrawDeferredLight(false, true);
3892 else if (castshadows && vid.stencil)
3893 R_Shadow_RenderMode_DrawDeferredLight(true, false);
3895 R_Shadow_RenderMode_DrawDeferredLight(false, false);
3899 static void R_Shadow_FreeDeferred(void)
3901 if (r_shadow_prepassgeometryfbo)
3902 qglDeleteFramebuffersEXT(1, &r_shadow_prepassgeometryfbo);CHECKGLERROR
3903 r_shadow_prepassgeometryfbo = 0;
3905 if (r_shadow_prepasslightingfbo)
3906 qglDeleteFramebuffersEXT(1, &r_shadow_prepasslightingfbo);CHECKGLERROR
3907 r_shadow_prepasslightingfbo = 0;
3909 if (r_shadow_prepassgeometrydepthtexture)
3910 R_FreeTexture(r_shadow_prepassgeometrydepthtexture);
3911 r_shadow_prepassgeometrydepthtexture = NULL;
3913 if (r_shadow_prepassgeometrynormalmaptexture)
3914 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
3915 r_shadow_prepassgeometrynormalmaptexture = NULL;
3917 if (r_shadow_prepasslightingdiffusetexture)
3918 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
3919 r_shadow_prepasslightingdiffusetexture = NULL;
3921 if (r_shadow_prepasslightingspeculartexture)
3922 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
3923 r_shadow_prepasslightingspeculartexture = NULL;
3926 void R_Shadow_DrawPrepass(void)
3934 entity_render_t *ent;
3936 GL_AlphaTest(false);
3937 R_Mesh_ColorPointer(NULL, 0, 0);
3938 R_Mesh_ResetTextureState();
3940 GL_ColorMask(1,1,1,1);
3941 GL_BlendFunc(GL_ONE, GL_ZERO);
3944 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepassgeometryfbo);CHECKGLERROR
3945 qglClearColor(0.5f,0.5f,0.5f,1.0f);CHECKGLERROR
3946 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);CHECKGLERROR
3948 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
3949 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
3950 if (r_timereport_active)
3951 R_TimeReport("prepassworld");
3953 for (i = 0;i < r_refdef.scene.numentities;i++)
3955 if (!r_refdef.viewcache.entityvisible[i])
3957 ent = r_refdef.scene.entities[i];
3958 if (ent->model && ent->model->DrawPrepass != NULL)
3959 ent->model->DrawPrepass(ent);
3962 if (r_timereport_active)
3963 R_TimeReport("prepassmodels");
3965 GL_DepthMask(false);
3966 GL_ColorMask(1,1,1,1);
3969 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepasslightingfbo);CHECKGLERROR
3970 qglClearColor(0.0f,0.0f,0.0f,0.0f);CHECKGLERROR
3971 GL_Clear(GL_COLOR_BUFFER_BIT);CHECKGLERROR
3972 if (r_refdef.fogenabled)
3973 qglClearColor(r_refdef.fogcolor[0],r_refdef.fogcolor[1],r_refdef.fogcolor[2],0);CHECKGLERROR
3975 R_Shadow_RenderMode_Begin();
3977 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3978 if (r_shadow_debuglight.integer >= 0)
3980 lightindex = r_shadow_debuglight.integer;
3981 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3982 if (light && (light->flags & flag))
3983 R_Shadow_DrawLight(&light->rtlight);
3987 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3988 for (lightindex = 0;lightindex < range;lightindex++)
3990 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3991 if (light && (light->flags & flag))
3992 R_Shadow_DrawLight(&light->rtlight);
3995 if (r_refdef.scene.rtdlight)
3996 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
3997 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
3999 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);CHECKGLERROR
4000 if (r_refdef.fogenabled)
4001 qglClearColor(r_refdef.fogcolor[0],r_refdef.fogcolor[1],r_refdef.fogcolor[2],0);CHECKGLERROR
4003 R_Shadow_RenderMode_End();
4005 if (r_timereport_active)
4006 R_TimeReport("prepasslights");
4009 void R_Shadow_DrawLightSprites(void);
4010 void R_Shadow_PrepareLights(void)
4020 if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4) ||
4021 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
4022 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0) ||
4023 r_shadow_shadowmaptexturetype != r_shadow_shadowmapping_texturetype.integer ||
4024 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
4025 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
4026 r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
4027 R_Shadow_FreeShadowMaps();
4029 switch (vid.renderpath)
4031 case RENDERPATH_GL20:
4032 case RENDERPATH_CGGL:
4033 if (!r_shadow_deferred.integer || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_STENCIL || !vid.support.ext_framebuffer_object || !vid.support.arb_texture_rectangle || vid.maxdrawbuffers < 2)
4035 r_shadow_usingdeferredprepass = false;
4036 if (r_shadow_prepass_width)
4037 R_Shadow_FreeDeferred();
4038 r_shadow_prepass_width = r_shadow_prepass_height = 0;
4042 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
4044 R_Shadow_FreeDeferred();
4046 r_shadow_usingdeferredprepass = true;
4047 r_shadow_prepass_width = vid.width;
4048 r_shadow_prepass_height = vid.height;
4049 r_shadow_prepassgeometrydepthtexture = R_LoadTextureShadowMapRectangle(r_shadow_texturepool, "prepassgeometrydepthmap", vid.width, vid.height, 24, false);
4050 r_shadow_prepassgeometrynormalmaptexture = R_LoadTextureRectangle(r_shadow_texturepool, "prepassgeometrynormalmap", vid.width, vid.height, NULL, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, NULL);
4051 r_shadow_prepasslightingdiffusetexture = R_LoadTextureRectangle(r_shadow_texturepool, "prepasslightingdiffuse", vid.width, vid.height, NULL, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, NULL);
4052 r_shadow_prepasslightingspeculartexture = R_LoadTextureRectangle(r_shadow_texturepool, "prepasslightingspecular", vid.width, vid.height, NULL, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, NULL);
4054 // set up the geometry pass fbo (depth + normalmap)
4055 qglGenFramebuffersEXT(1, &r_shadow_prepassgeometryfbo);CHECKGLERROR
4056 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepassgeometryfbo);CHECKGLERROR
4057 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, R_GetTexture(r_shadow_prepassgeometrydepthtexture), 0);CHECKGLERROR
4058 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, R_GetTexture(r_shadow_prepassgeometrynormalmaptexture), 0);CHECKGLERROR
4059 // render depth into one texture and normalmap into the other
4060 qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);CHECKGLERROR
4061 qglReadBuffer(GL_NONE);CHECKGLERROR
4062 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4063 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4065 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4066 Cvar_SetValueQuick(&r_shadow_deferred, 0);
4067 r_shadow_usingdeferredprepass = false;
4070 // set up the lighting pass fbo (diffuse + specular)
4071 qglGenFramebuffersEXT(1, &r_shadow_prepasslightingfbo);CHECKGLERROR
4072 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepasslightingfbo);CHECKGLERROR
4073 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, R_GetTexture(r_shadow_prepassgeometrydepthtexture), 0);CHECKGLERROR
4074 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, R_GetTexture(r_shadow_prepasslightingdiffusetexture), 0);CHECKGLERROR
4075 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_RECTANGLE_ARB, R_GetTexture(r_shadow_prepasslightingspeculartexture), 0);CHECKGLERROR
4076 // render diffuse into one texture and specular into another,
4077 // with depth and normalmap bound as textures,
4078 // with depth bound as attachment as well
4079 qglDrawBuffersARB(2, r_shadow_prepasslightingdrawbuffers);CHECKGLERROR
4080 qglReadBuffer(GL_NONE);CHECKGLERROR
4081 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4082 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4084 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4085 Cvar_SetValueQuick(&r_shadow_deferred, 0);
4086 r_shadow_usingdeferredprepass = false;
4090 case RENDERPATH_GL13:
4091 case RENDERPATH_GL11:
4092 r_shadow_usingdeferredprepass = false;
4096 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);
4098 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4099 if (r_shadow_debuglight.integer >= 0)
4101 lightindex = r_shadow_debuglight.integer;
4102 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4103 if (light && (light->flags & flag))
4104 R_Shadow_PrepareLight(&light->rtlight);
4108 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4109 for (lightindex = 0;lightindex < range;lightindex++)
4111 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4112 if (light && (light->flags & flag))
4113 R_Shadow_PrepareLight(&light->rtlight);
4116 if (r_refdef.scene.rtdlight)
4118 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4119 R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
4121 else if(gl_flashblend.integer)
4123 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4125 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
4126 f = (rtlight->style >= 0 ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4127 VectorScale(rtlight->color, f, rtlight->currentcolor);
4131 if (r_editlights.integer)
4132 R_Shadow_DrawLightSprites();
4135 void R_Shadow_DrawLights(void)
4143 R_Shadow_RenderMode_Begin();
4145 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4146 if (r_shadow_debuglight.integer >= 0)
4148 lightindex = r_shadow_debuglight.integer;
4149 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4150 if (light && (light->flags & flag))
4151 R_Shadow_DrawLight(&light->rtlight);
4155 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4156 for (lightindex = 0;lightindex < range;lightindex++)
4158 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4159 if (light && (light->flags & flag))
4160 R_Shadow_DrawLight(&light->rtlight);
4163 if (r_refdef.scene.rtdlight)
4164 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4165 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4167 R_Shadow_RenderMode_End();
4170 extern const float r_screenvertex3f[12];
4171 extern void R_SetupView(qboolean allowwaterclippingplane);
4172 extern void R_ResetViewRendering3D(void);
4173 extern void R_ResetViewRendering2D(void);
4174 extern cvar_t r_shadows;
4175 extern cvar_t r_shadows_darken;
4176 extern cvar_t r_shadows_drawafterrtlighting;
4177 extern cvar_t r_shadows_castfrombmodels;
4178 extern cvar_t r_shadows_throwdistance;
4179 extern cvar_t r_shadows_throwdirection;
4180 void R_DrawModelShadows(void)
4183 float relativethrowdistance;
4184 entity_render_t *ent;
4185 vec3_t relativelightorigin;
4186 vec3_t relativelightdirection;
4187 vec3_t relativeshadowmins, relativeshadowmaxs;
4188 vec3_t tmp, shadowdir;
4190 if (!r_refdef.scene.numentities || !vid.stencil)
4194 R_ResetViewRendering3D();
4195 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4196 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4197 R_Shadow_RenderMode_Begin();
4198 R_Shadow_RenderMode_ActiveLight(NULL);
4199 r_shadow_lightscissor[0] = r_refdef.view.x;
4200 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
4201 r_shadow_lightscissor[2] = r_refdef.view.width;
4202 r_shadow_lightscissor[3] = r_refdef.view.height;
4203 R_Shadow_RenderMode_StencilShadowVolumes(false);
4206 if (r_shadows.integer == 2)
4208 Math_atov(r_shadows_throwdirection.string, shadowdir);
4209 VectorNormalize(shadowdir);
4212 R_Shadow_ClearStencil();
4214 for (i = 0;i < r_refdef.scene.numentities;i++)
4216 ent = r_refdef.scene.entities[i];
4218 // cast shadows from anything of the map (submodels are optional)
4219 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4221 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4222 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
4223 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
4224 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
4225 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4228 if(ent->entitynumber != 0)
4230 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
4231 int entnum, entnum2, recursion;
4232 entnum = entnum2 = ent->entitynumber;
4233 for(recursion = 32; recursion > 0; --recursion)
4235 entnum2 = cl.entities[entnum].state_current.tagentity;
4236 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
4241 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
4243 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
4244 // transform into modelspace of OUR entity
4245 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
4246 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
4249 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4252 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4255 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
4256 RSurf_ActiveModelEntity(ent, false, false, false);
4257 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4258 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4262 // not really the right mode, but this will disable any silly stencil features
4263 R_Shadow_RenderMode_End();
4265 // set up ortho view for rendering this pass
4266 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4267 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4268 //GL_ScissorTest(true);
4269 //R_EntityMatrix(&identitymatrix);
4270 //R_Mesh_ResetTextureState();
4271 R_ResetViewRendering2D();
4272 R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
4273 R_Mesh_ColorPointer(NULL, 0, 0);
4274 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
4276 // set up a darkening blend on shadowed areas
4277 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4278 //GL_DepthRange(0, 1);
4279 //GL_DepthTest(false);
4280 //GL_DepthMask(false);
4281 //GL_PolygonOffset(0, 0);CHECKGLERROR
4282 GL_Color(0, 0, 0, r_shadows_darken.value);
4283 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4284 //qglDepthFunc(GL_ALWAYS);CHECKGLERROR
4285 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
4286 qglStencilMask(~0);CHECKGLERROR
4287 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
4288 qglStencilFunc(GL_NOTEQUAL, 128, ~0);CHECKGLERROR
4290 // apply the blend to the shadowed areas
4291 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
4293 // restore the viewport
4294 R_SetViewport(&r_refdef.view.viewport);
4296 // restore other state to normal
4297 //R_Shadow_RenderMode_End();
4300 void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4303 vec3_t centerorigin;
4305 // if it's too close, skip it
4306 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
4308 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4311 if (usequery && r_numqueries + 2 <= r_maxqueries)
4313 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4314 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4315 // 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
4316 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4319 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use qglDepthFunc instead
4320 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
4321 qglDepthFunc(GL_ALWAYS);
4322 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4323 R_Mesh_VertexPointer(vertex3f, 0, 0);
4324 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
4325 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4326 qglDepthFunc(GL_LEQUAL);
4327 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
4328 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4329 R_Mesh_VertexPointer(vertex3f, 0, 0);
4330 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
4331 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4334 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4337 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
4339 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4342 GLint allpixels = 0, visiblepixels = 0;
4343 // now we have to check the query result
4344 if (rtlight->corona_queryindex_visiblepixels)
4347 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
4348 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
4350 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
4351 if (visiblepixels < 1 || allpixels < 1)
4353 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
4354 cscale *= rtlight->corona_visibility;
4358 // FIXME: these traces should scan all render entities instead of cl.world
4359 if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
4362 VectorScale(rtlight->currentcolor, cscale, color);
4363 if (VectorLength(color) > (1.0f / 256.0f))
4366 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
4369 VectorNegate(color, color);
4370 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
4372 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4373 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);
4374 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4376 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
4380 void R_Shadow_DrawCoronas(void)
4388 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4390 if (r_waterstate.renderingscene)
4392 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4393 R_EntityMatrix(&identitymatrix);
4395 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4397 // check occlusion of coronas
4398 // use GL_ARB_occlusion_query if available
4399 // otherwise use raytraces
4401 usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
4404 GL_ColorMask(0,0,0,0);
4405 if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
4406 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
4409 r_maxqueries = (range + r_refdef.scene.numlights) * 4;
4410 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
4412 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
4415 RSurf_ActiveWorldEntity();
4416 GL_BlendFunc(GL_ONE, GL_ZERO);
4417 GL_CullFace(GL_NONE);
4418 GL_DepthMask(false);
4419 GL_DepthRange(0, 1);
4420 GL_PolygonOffset(0, 0);
4422 R_Mesh_ColorPointer(NULL, 0, 0);
4423 R_Mesh_ResetTextureState();
4424 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
4426 for (lightindex = 0;lightindex < range;lightindex++)
4428 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4431 rtlight = &light->rtlight;
4432 rtlight->corona_visibility = 0;
4433 rtlight->corona_queryindex_visiblepixels = 0;
4434 rtlight->corona_queryindex_allpixels = 0;
4435 if (!(rtlight->flags & flag))
4437 if (rtlight->corona <= 0)
4439 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4441 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4443 for (i = 0;i < r_refdef.scene.numlights;i++)
4445 rtlight = r_refdef.scene.lights[i];
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 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4456 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4458 // now draw the coronas using the query data for intensity info
4459 for (lightindex = 0;lightindex < range;lightindex++)
4461 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4464 rtlight = &light->rtlight;
4465 if (rtlight->corona_visibility <= 0)
4467 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4469 for (i = 0;i < r_refdef.scene.numlights;i++)
4471 rtlight = r_refdef.scene.lights[i];
4472 if (rtlight->corona_visibility <= 0)
4474 if (gl_flashblend.integer)
4475 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4477 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4483 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
4484 typedef struct suffixinfo_s
4487 qboolean flipx, flipy, flipdiagonal;
4490 static suffixinfo_t suffix[3][6] =
4493 {"px", false, false, false},
4494 {"nx", false, false, false},
4495 {"py", false, false, false},
4496 {"ny", false, false, false},
4497 {"pz", false, false, false},
4498 {"nz", false, false, false}
4501 {"posx", false, false, false},
4502 {"negx", false, false, false},
4503 {"posy", false, false, false},
4504 {"negy", false, false, false},
4505 {"posz", false, false, false},
4506 {"negz", false, false, false}
4509 {"rt", true, false, true},
4510 {"lf", false, true, true},
4511 {"ft", true, true, false},
4512 {"bk", false, false, false},
4513 {"up", true, false, true},
4514 {"dn", true, false, true}
4518 static int componentorder[4] = {0, 1, 2, 3};
4520 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
4522 int i, j, cubemapsize;
4523 unsigned char *cubemappixels, *image_buffer;
4524 rtexture_t *cubemaptexture;
4526 // must start 0 so the first loadimagepixels has no requested width/height
4528 cubemappixels = NULL;
4529 cubemaptexture = NULL;
4530 // keep trying different suffix groups (posx, px, rt) until one loads
4531 for (j = 0;j < 3 && !cubemappixels;j++)
4533 // load the 6 images in the suffix group
4534 for (i = 0;i < 6;i++)
4536 // generate an image name based on the base and and suffix
4537 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
4539 if ((image_buffer = loadimagepixelsbgra(name, false, false)))
4541 // an image loaded, make sure width and height are equal
4542 if (image_width == image_height && (!cubemappixels || image_width == cubemapsize))
4544 // if this is the first image to load successfully, allocate the cubemap memory
4545 if (!cubemappixels && image_width >= 1)
4547 cubemapsize = image_width;
4548 // note this clears to black, so unavailable sides are black
4549 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
4551 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
4553 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);
4556 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
4558 Mem_Free(image_buffer);
4562 // if a cubemap loaded, upload it
4565 if (developer_loading.integer)
4566 Con_Printf("loading cubemap \"%s\"\n", basename);
4568 if (!r_shadow_filters_texturepool)
4569 r_shadow_filters_texturepool = R_AllocTexturePool();
4570 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_BGRA, (gl_texturecompression_lightcubemaps.integer ? TEXF_COMPRESS : 0) | TEXF_FORCELINEAR, NULL);
4571 Mem_Free(cubemappixels);
4575 Con_DPrintf("failed to load cubemap \"%s\"\n", basename);
4576 if (developer_loading.integer)
4578 Con_Printf("(tried tried images ");
4579 for (j = 0;j < 3;j++)
4580 for (i = 0;i < 6;i++)
4581 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
4582 Con_Print(" and was unable to find any of them).\n");
4585 return cubemaptexture;
4588 rtexture_t *R_Shadow_Cubemap(const char *basename)
4591 for (i = 0;i < numcubemaps;i++)
4592 if (!strcasecmp(cubemaps[i].basename, basename))
4593 return cubemaps[i].texture ? cubemaps[i].texture : r_texture_whitecube;
4594 if (i >= MAX_CUBEMAPS)
4595 return r_texture_whitecube;
4597 strlcpy(cubemaps[i].basename, basename, sizeof(cubemaps[i].basename));
4598 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
4599 return cubemaps[i].texture;
4602 void R_Shadow_FreeCubemaps(void)
4605 for (i = 0;i < numcubemaps;i++)
4607 if (developer_loading.integer)
4608 Con_Printf("unloading cubemap \"%s\"\n", cubemaps[i].basename);
4609 if (cubemaps[i].texture)
4610 R_FreeTexture(cubemaps[i].texture);
4614 R_FreeTexturePool(&r_shadow_filters_texturepool);
4617 dlight_t *R_Shadow_NewWorldLight(void)
4619 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4622 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)
4625 // validate parameters
4626 if (style < 0 || style >= MAX_LIGHTSTYLES)
4628 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
4634 // copy to light properties
4635 VectorCopy(origin, light->origin);
4636 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4637 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4638 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4640 light->color[0] = max(color[0], 0);
4641 light->color[1] = max(color[1], 0);
4642 light->color[2] = max(color[2], 0);
4644 light->color[0] = color[0];
4645 light->color[1] = color[1];
4646 light->color[2] = color[2];
4647 light->radius = max(radius, 0);
4648 light->style = style;
4649 light->shadow = shadowenable;
4650 light->corona = corona;
4651 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4652 light->coronasizescale = coronasizescale;
4653 light->ambientscale = ambientscale;
4654 light->diffusescale = diffusescale;
4655 light->specularscale = specularscale;
4656 light->flags = flags;
4658 // update renderable light data
4659 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4660 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);
4663 void R_Shadow_FreeWorldLight(dlight_t *light)
4665 if (r_shadow_selectedlight == light)
4666 r_shadow_selectedlight = NULL;
4667 R_RTLight_Uncompile(&light->rtlight);
4668 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4671 void R_Shadow_ClearWorldLights(void)
4675 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4676 for (lightindex = 0;lightindex < range;lightindex++)
4678 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4680 R_Shadow_FreeWorldLight(light);
4682 r_shadow_selectedlight = NULL;
4683 R_Shadow_FreeCubemaps();
4686 void R_Shadow_SelectLight(dlight_t *light)
4688 if (r_shadow_selectedlight)
4689 r_shadow_selectedlight->selected = false;
4690 r_shadow_selectedlight = light;
4691 if (r_shadow_selectedlight)
4692 r_shadow_selectedlight->selected = true;
4695 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4697 // this is never batched (there can be only one)
4699 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
4700 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4701 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4704 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4709 skinframe_t *skinframe;
4712 // this is never batched (due to the ent parameter changing every time)
4713 // so numsurfaces == 1 and surfacelist[0] == lightnumber
4714 const dlight_t *light = (dlight_t *)ent;
4717 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
4720 VectorScale(light->color, intensity, spritecolor);
4721 if (VectorLength(spritecolor) < 0.1732f)
4722 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
4723 if (VectorLength(spritecolor) > 1.0f)
4724 VectorNormalize(spritecolor);
4726 // draw light sprite
4727 if (light->cubemapname[0] && !light->shadow)
4728 skinframe = r_editlights_sprcubemapnoshadowlight;
4729 else if (light->cubemapname[0])
4730 skinframe = r_editlights_sprcubemaplight;
4731 else if (!light->shadow)
4732 skinframe = r_editlights_sprnoshadowlight;
4734 skinframe = r_editlights_sprlight;
4736 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);
4737 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4739 // draw selection sprite if light is selected
4740 if (light->selected)
4742 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4743 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4744 // VorteX todo: add normalmode/realtime mode light overlay sprites?
4748 void R_Shadow_DrawLightSprites(void)
4752 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4753 for (lightindex = 0;lightindex < range;lightindex++)
4755 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4757 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
4759 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
4762 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
4767 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
4768 if (lightindex >= range)
4770 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4773 rtlight = &light->rtlight;
4774 //if (!(rtlight->flags & flag))
4776 VectorCopy(rtlight->shadoworigin, origin);
4777 *radius = rtlight->radius;
4778 VectorCopy(rtlight->color, color);
4782 void R_Shadow_SelectLightInView(void)
4784 float bestrating, rating, temp[3];
4788 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4791 for (lightindex = 0;lightindex < range;lightindex++)
4793 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4796 VectorSubtract(light->origin, r_refdef.view.origin, temp);
4797 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
4800 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
4801 if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1.0f)
4803 bestrating = rating;
4808 R_Shadow_SelectLight(best);
4811 void R_Shadow_LoadWorldLights(void)
4813 int n, a, style, shadow, flags;
4814 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
4815 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
4816 if (cl.worldmodel == NULL)
4818 Con_Print("No map loaded.\n");
4821 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4822 strlcat (name, ".rtlights", sizeof (name));
4823 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4833 for (;COM_Parse(t, true) && strcmp(
4834 if (COM_Parse(t, true))
4836 if (com_token[0] == '!')
4839 origin[0] = atof(com_token+1);
4842 origin[0] = atof(com_token);
4847 while (*s && *s != '\n' && *s != '\r')
4853 // check for modifier flags
4860 #if _MSC_VER >= 1400
4861 #define sscanf sscanf_s
4863 cubemapname[sizeof(cubemapname)-1] = 0;
4864 #if MAX_QPATH != 128
4865 #error update this code if MAX_QPATH changes
4867 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
4868 #if _MSC_VER >= 1400
4869 , sizeof(cubemapname)
4871 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
4874 flags = LIGHTFLAG_REALTIMEMODE;
4882 coronasizescale = 0.25f;
4884 VectorClear(angles);
4887 if (a < 9 || !strcmp(cubemapname, "\"\""))
4889 // remove quotes on cubemapname
4890 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
4893 namelen = strlen(cubemapname) - 2;
4894 memmove(cubemapname, cubemapname + 1, namelen);
4895 cubemapname[namelen] = '\0';
4899 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);
4902 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4910 Con_Printf("invalid rtlights file \"%s\"\n", name);
4911 Mem_Free(lightsstring);
4915 void R_Shadow_SaveWorldLights(void)
4919 size_t bufchars, bufmaxchars;
4921 char name[MAX_QPATH];
4922 char line[MAX_INPUTLINE];
4923 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
4924 // I hate lines which are 3 times my screen size :( --blub
4927 if (cl.worldmodel == NULL)
4929 Con_Print("No map loaded.\n");
4932 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4933 strlcat (name, ".rtlights", sizeof (name));
4934 bufchars = bufmaxchars = 0;
4936 for (lightindex = 0;lightindex < range;lightindex++)
4938 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4941 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
4942 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);
4943 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
4944 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]);
4946 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);
4947 if (bufchars + strlen(line) > bufmaxchars)
4949 bufmaxchars = bufchars + strlen(line) + 2048;
4951 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
4955 memcpy(buf, oldbuf, bufchars);
4961 memcpy(buf + bufchars, line, strlen(line));
4962 bufchars += strlen(line);
4966 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
4971 void R_Shadow_LoadLightsFile(void)
4974 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
4975 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
4976 if (cl.worldmodel == NULL)
4978 Con_Print("No map loaded.\n");
4981 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4982 strlcat (name, ".lights", sizeof (name));
4983 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4991 while (*s && *s != '\n' && *s != '\r')
4997 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);
5001 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);
5004 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
5005 radius = bound(15, radius, 4096);
5006 VectorScale(color, (2.0f / (8388608.0f)), color);
5007 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5015 Con_Printf("invalid lights file \"%s\"\n", name);
5016 Mem_Free(lightsstring);
5020 // tyrlite/hmap2 light types in the delay field
5021 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
5023 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
5025 int entnum, style, islight, skin, pflags, effects, type, n;
5028 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
5029 char key[256], value[MAX_INPUTLINE];
5031 if (cl.worldmodel == NULL)
5033 Con_Print("No map loaded.\n");
5036 // try to load a .ent file first
5037 FS_StripExtension (cl.worldmodel->name, key, sizeof (key));
5038 strlcat (key, ".ent", sizeof (key));
5039 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
5040 // and if that is not found, fall back to the bsp file entity string
5042 data = cl.worldmodel->brush.entities;
5045 for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
5047 type = LIGHTTYPE_MINUSX;
5048 origin[0] = origin[1] = origin[2] = 0;
5049 originhack[0] = originhack[1] = originhack[2] = 0;
5050 angles[0] = angles[1] = angles[2] = 0;
5051 color[0] = color[1] = color[2] = 1;
5052 light[0] = light[1] = light[2] = 1;light[3] = 300;
5053 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
5063 if (!COM_ParseToken_Simple(&data, false, false))
5065 if (com_token[0] == '}')
5066 break; // end of entity
5067 if (com_token[0] == '_')
5068 strlcpy(key, com_token + 1, sizeof(key));
5070 strlcpy(key, com_token, sizeof(key));
5071 while (key[strlen(key)-1] == ' ') // remove trailing spaces
5072 key[strlen(key)-1] = 0;
5073 if (!COM_ParseToken_Simple(&data, false, false))
5075 strlcpy(value, com_token, sizeof(value));
5077 // now that we have the key pair worked out...
5078 if (!strcmp("light", key))
5080 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5084 light[0] = vec[0] * (1.0f / 256.0f);
5085 light[1] = vec[0] * (1.0f / 256.0f);
5086 light[2] = vec[0] * (1.0f / 256.0f);
5092 light[0] = vec[0] * (1.0f / 255.0f);
5093 light[1] = vec[1] * (1.0f / 255.0f);
5094 light[2] = vec[2] * (1.0f / 255.0f);
5098 else if (!strcmp("delay", key))
5100 else if (!strcmp("origin", key))
5101 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5102 else if (!strcmp("angle", key))
5103 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5104 else if (!strcmp("angles", key))
5105 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5106 else if (!strcmp("color", key))
5107 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5108 else if (!strcmp("wait", key))
5109 fadescale = atof(value);
5110 else if (!strcmp("classname", key))
5112 if (!strncmp(value, "light", 5))
5115 if (!strcmp(value, "light_fluoro"))
5120 overridecolor[0] = 1;
5121 overridecolor[1] = 1;
5122 overridecolor[2] = 1;
5124 if (!strcmp(value, "light_fluorospark"))
5129 overridecolor[0] = 1;
5130 overridecolor[1] = 1;
5131 overridecolor[2] = 1;
5133 if (!strcmp(value, "light_globe"))
5138 overridecolor[0] = 1;
5139 overridecolor[1] = 0.8;
5140 overridecolor[2] = 0.4;
5142 if (!strcmp(value, "light_flame_large_yellow"))
5147 overridecolor[0] = 1;
5148 overridecolor[1] = 0.5;
5149 overridecolor[2] = 0.1;
5151 if (!strcmp(value, "light_flame_small_yellow"))
5156 overridecolor[0] = 1;
5157 overridecolor[1] = 0.5;
5158 overridecolor[2] = 0.1;
5160 if (!strcmp(value, "light_torch_small_white"))
5165 overridecolor[0] = 1;
5166 overridecolor[1] = 0.5;
5167 overridecolor[2] = 0.1;
5169 if (!strcmp(value, "light_torch_small_walltorch"))
5174 overridecolor[0] = 1;
5175 overridecolor[1] = 0.5;
5176 overridecolor[2] = 0.1;
5180 else if (!strcmp("style", key))
5181 style = atoi(value);
5182 else if (!strcmp("skin", key))
5183 skin = (int)atof(value);
5184 else if (!strcmp("pflags", key))
5185 pflags = (int)atof(value);
5186 else if (!strcmp("effects", key))
5187 effects = (int)atof(value);
5188 else if (cl.worldmodel->type == mod_brushq3)
5190 if (!strcmp("scale", key))
5191 lightscale = atof(value);
5192 if (!strcmp("fade", key))
5193 fadescale = atof(value);
5198 if (lightscale <= 0)
5202 if (color[0] == color[1] && color[0] == color[2])
5204 color[0] *= overridecolor[0];
5205 color[1] *= overridecolor[1];
5206 color[2] *= overridecolor[2];
5208 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5209 color[0] = color[0] * light[0];
5210 color[1] = color[1] * light[1];
5211 color[2] = color[2] * light[2];
5214 case LIGHTTYPE_MINUSX:
5216 case LIGHTTYPE_RECIPX:
5218 VectorScale(color, (1.0f / 16.0f), color);
5220 case LIGHTTYPE_RECIPXX:
5222 VectorScale(color, (1.0f / 16.0f), color);
5225 case LIGHTTYPE_NONE:
5229 case LIGHTTYPE_MINUSXX:
5232 VectorAdd(origin, originhack, origin);
5234 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);
5237 Mem_Free(entfiledata);
5241 void R_Shadow_SetCursorLocationForView(void)
5244 vec3_t dest, endpos;
5246 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5247 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
5248 if (trace.fraction < 1)
5250 dist = trace.fraction * r_editlights_cursordistance.value;
5251 push = r_editlights_cursorpushback.value;
5255 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5256 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5260 VectorClear( endpos );
5262 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5263 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5264 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5267 void R_Shadow_UpdateWorldLightSelection(void)
5269 if (r_editlights.integer)
5271 R_Shadow_SetCursorLocationForView();
5272 R_Shadow_SelectLightInView();
5275 R_Shadow_SelectLight(NULL);
5278 void R_Shadow_EditLights_Clear_f(void)
5280 R_Shadow_ClearWorldLights();
5283 void R_Shadow_EditLights_Reload_f(void)
5287 strlcpy(r_shadow_mapname, cl.worldmodel->name, sizeof(r_shadow_mapname));
5288 R_Shadow_ClearWorldLights();
5289 R_Shadow_LoadWorldLights();
5290 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5292 R_Shadow_LoadLightsFile();
5293 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5294 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5298 void R_Shadow_EditLights_Save_f(void)
5302 R_Shadow_SaveWorldLights();
5305 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
5307 R_Shadow_ClearWorldLights();
5308 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5311 void R_Shadow_EditLights_ImportLightsFile_f(void)
5313 R_Shadow_ClearWorldLights();
5314 R_Shadow_LoadLightsFile();
5317 void R_Shadow_EditLights_Spawn_f(void)
5320 if (!r_editlights.integer)
5322 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5325 if (Cmd_Argc() != 1)
5327 Con_Print("r_editlights_spawn does not take parameters\n");
5330 color[0] = color[1] = color[2] = 1;
5331 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5334 void R_Shadow_EditLights_Edit_f(void)
5336 vec3_t origin, angles, color;
5337 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5338 int style, shadows, flags, normalmode, realtimemode;
5339 char cubemapname[MAX_INPUTLINE];
5340 if (!r_editlights.integer)
5342 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5345 if (!r_shadow_selectedlight)
5347 Con_Print("No selected light.\n");
5350 VectorCopy(r_shadow_selectedlight->origin, origin);
5351 VectorCopy(r_shadow_selectedlight->angles, angles);
5352 VectorCopy(r_shadow_selectedlight->color, color);
5353 radius = r_shadow_selectedlight->radius;
5354 style = r_shadow_selectedlight->style;
5355 if (r_shadow_selectedlight->cubemapname)
5356 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5359 shadows = r_shadow_selectedlight->shadow;
5360 corona = r_shadow_selectedlight->corona;
5361 coronasizescale = r_shadow_selectedlight->coronasizescale;
5362 ambientscale = r_shadow_selectedlight->ambientscale;
5363 diffusescale = r_shadow_selectedlight->diffusescale;
5364 specularscale = r_shadow_selectedlight->specularscale;
5365 flags = r_shadow_selectedlight->flags;
5366 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5367 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5368 if (!strcmp(Cmd_Argv(1), "origin"))
5370 if (Cmd_Argc() != 5)
5372 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5375 origin[0] = atof(Cmd_Argv(2));
5376 origin[1] = atof(Cmd_Argv(3));
5377 origin[2] = atof(Cmd_Argv(4));
5379 else if (!strcmp(Cmd_Argv(1), "originx"))
5381 if (Cmd_Argc() != 3)
5383 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5386 origin[0] = atof(Cmd_Argv(2));
5388 else if (!strcmp(Cmd_Argv(1), "originy"))
5390 if (Cmd_Argc() != 3)
5392 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5395 origin[1] = atof(Cmd_Argv(2));
5397 else if (!strcmp(Cmd_Argv(1), "originz"))
5399 if (Cmd_Argc() != 3)
5401 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5404 origin[2] = atof(Cmd_Argv(2));
5406 else if (!strcmp(Cmd_Argv(1), "move"))
5408 if (Cmd_Argc() != 5)
5410 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5413 origin[0] += atof(Cmd_Argv(2));
5414 origin[1] += atof(Cmd_Argv(3));
5415 origin[2] += atof(Cmd_Argv(4));
5417 else if (!strcmp(Cmd_Argv(1), "movex"))
5419 if (Cmd_Argc() != 3)
5421 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5424 origin[0] += atof(Cmd_Argv(2));
5426 else if (!strcmp(Cmd_Argv(1), "movey"))
5428 if (Cmd_Argc() != 3)
5430 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5433 origin[1] += atof(Cmd_Argv(2));
5435 else if (!strcmp(Cmd_Argv(1), "movez"))
5437 if (Cmd_Argc() != 3)
5439 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5442 origin[2] += atof(Cmd_Argv(2));
5444 else if (!strcmp(Cmd_Argv(1), "angles"))
5446 if (Cmd_Argc() != 5)
5448 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5451 angles[0] = atof(Cmd_Argv(2));
5452 angles[1] = atof(Cmd_Argv(3));
5453 angles[2] = atof(Cmd_Argv(4));
5455 else if (!strcmp(Cmd_Argv(1), "anglesx"))
5457 if (Cmd_Argc() != 3)
5459 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5462 angles[0] = atof(Cmd_Argv(2));
5464 else if (!strcmp(Cmd_Argv(1), "anglesy"))
5466 if (Cmd_Argc() != 3)
5468 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5471 angles[1] = atof(Cmd_Argv(2));
5473 else if (!strcmp(Cmd_Argv(1), "anglesz"))
5475 if (Cmd_Argc() != 3)
5477 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5480 angles[2] = atof(Cmd_Argv(2));
5482 else if (!strcmp(Cmd_Argv(1), "color"))
5484 if (Cmd_Argc() != 5)
5486 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
5489 color[0] = atof(Cmd_Argv(2));
5490 color[1] = atof(Cmd_Argv(3));
5491 color[2] = atof(Cmd_Argv(4));
5493 else if (!strcmp(Cmd_Argv(1), "radius"))
5495 if (Cmd_Argc() != 3)
5497 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5500 radius = atof(Cmd_Argv(2));
5502 else if (!strcmp(Cmd_Argv(1), "colorscale"))
5504 if (Cmd_Argc() == 3)
5506 double scale = atof(Cmd_Argv(2));
5513 if (Cmd_Argc() != 5)
5515 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
5518 color[0] *= atof(Cmd_Argv(2));
5519 color[1] *= atof(Cmd_Argv(3));
5520 color[2] *= atof(Cmd_Argv(4));
5523 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
5525 if (Cmd_Argc() != 3)
5527 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5530 radius *= atof(Cmd_Argv(2));
5532 else if (!strcmp(Cmd_Argv(1), "style"))
5534 if (Cmd_Argc() != 3)
5536 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5539 style = atoi(Cmd_Argv(2));
5541 else if (!strcmp(Cmd_Argv(1), "cubemap"))
5545 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5548 if (Cmd_Argc() == 3)
5549 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
5553 else if (!strcmp(Cmd_Argv(1), "shadows"))
5555 if (Cmd_Argc() != 3)
5557 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5560 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5562 else if (!strcmp(Cmd_Argv(1), "corona"))
5564 if (Cmd_Argc() != 3)
5566 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5569 corona = atof(Cmd_Argv(2));
5571 else if (!strcmp(Cmd_Argv(1), "coronasize"))
5573 if (Cmd_Argc() != 3)
5575 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5578 coronasizescale = atof(Cmd_Argv(2));
5580 else if (!strcmp(Cmd_Argv(1), "ambient"))
5582 if (Cmd_Argc() != 3)
5584 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5587 ambientscale = atof(Cmd_Argv(2));
5589 else if (!strcmp(Cmd_Argv(1), "diffuse"))
5591 if (Cmd_Argc() != 3)
5593 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5596 diffusescale = atof(Cmd_Argv(2));
5598 else if (!strcmp(Cmd_Argv(1), "specular"))
5600 if (Cmd_Argc() != 3)
5602 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5605 specularscale = atof(Cmd_Argv(2));
5607 else if (!strcmp(Cmd_Argv(1), "normalmode"))
5609 if (Cmd_Argc() != 3)
5611 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5614 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5616 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
5618 if (Cmd_Argc() != 3)
5620 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5623 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5627 Con_Print("usage: r_editlights_edit [property] [value]\n");
5628 Con_Print("Selected light's properties:\n");
5629 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5630 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5631 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5632 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
5633 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
5634 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
5635 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5636 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
5637 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
5638 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
5639 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
5640 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
5641 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5642 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5645 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5646 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5649 void R_Shadow_EditLights_EditAll_f(void)
5655 if (!r_editlights.integer)
5657 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5661 // EditLights doesn't seem to have a "remove" command or something so:
5662 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5663 for (lightindex = 0;lightindex < range;lightindex++)
5665 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5668 R_Shadow_SelectLight(light);
5669 R_Shadow_EditLights_Edit_f();
5673 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
5675 int lightnumber, lightcount;
5676 size_t lightindex, range;
5680 if (!r_editlights.integer)
5682 x = vid_conwidth.value - 240;
5684 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
5687 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5688 for (lightindex = 0;lightindex < range;lightindex++)
5690 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5693 if (light == r_shadow_selectedlight)
5694 lightnumber = lightindex;
5697 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);y += 8;
5698 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);y += 8;
5700 if (r_shadow_selectedlight == NULL)
5702 dpsnprintf(temp, sizeof(temp), "Light #%i properties:", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
5703 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);y += 8;
5704 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);y += 8;
5705 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);y += 8;
5706 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);y += 8;
5707 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);y += 8;
5708 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);y += 8;
5709 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);y += 8;
5710 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);y += 8;
5711 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);y += 8;
5712 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);y += 8;
5713 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);y += 8;
5714 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);y += 8;
5715 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);y += 8;
5716 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);y += 8;
5719 void R_Shadow_EditLights_ToggleShadow_f(void)
5721 if (!r_editlights.integer)
5723 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5726 if (!r_shadow_selectedlight)
5728 Con_Print("No selected light.\n");
5731 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);
5734 void R_Shadow_EditLights_ToggleCorona_f(void)
5736 if (!r_editlights.integer)
5738 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5741 if (!r_shadow_selectedlight)
5743 Con_Print("No selected light.\n");
5746 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);
5749 void R_Shadow_EditLights_Remove_f(void)
5751 if (!r_editlights.integer)
5753 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
5756 if (!r_shadow_selectedlight)
5758 Con_Print("No selected light.\n");
5761 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
5762 r_shadow_selectedlight = NULL;
5765 void R_Shadow_EditLights_Help_f(void)
5768 "Documentation on r_editlights system:\n"
5770 "r_editlights : enable/disable editing mode\n"
5771 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
5772 "r_editlights_cursorpushback : push back cursor this far from surface\n"
5773 "r_editlights_cursorpushoff : push cursor off surface this far\n"
5774 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
5775 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
5777 "r_editlights_help : this help\n"
5778 "r_editlights_clear : remove all lights\n"
5779 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
5780 "r_editlights_save : save to .rtlights file\n"
5781 "r_editlights_spawn : create a light with default settings\n"
5782 "r_editlights_edit command : edit selected light - more documentation below\n"
5783 "r_editlights_remove : remove selected light\n"
5784 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
5785 "r_editlights_importlightentitiesfrommap : reload light entities\n"
5786 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
5788 "origin x y z : set light location\n"
5789 "originx x: set x component of light location\n"
5790 "originy y: set y component of light location\n"
5791 "originz z: set z component of light location\n"
5792 "move x y z : adjust light location\n"
5793 "movex x: adjust x component of light location\n"
5794 "movey y: adjust y component of light location\n"
5795 "movez z: adjust z component of light location\n"
5796 "angles x y z : set light angles\n"
5797 "anglesx x: set x component of light angles\n"
5798 "anglesy y: set y component of light angles\n"
5799 "anglesz z: set z component of light angles\n"
5800 "color r g b : set color of light (can be brighter than 1 1 1)\n"
5801 "radius radius : set radius (size) of light\n"
5802 "colorscale grey : multiply color of light (1 does nothing)\n"
5803 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
5804 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
5805 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
5806 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
5807 "cubemap basename : set filter cubemap of light (not yet supported)\n"
5808 "shadows 1/0 : turn on/off shadows\n"
5809 "corona n : set corona intensity\n"
5810 "coronasize n : set corona size (0-1)\n"
5811 "ambient n : set ambient intensity (0-1)\n"
5812 "diffuse n : set diffuse intensity (0-1)\n"
5813 "specular n : set specular intensity (0-1)\n"
5814 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
5815 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
5816 "<nothing> : print light properties to console\n"
5820 void R_Shadow_EditLights_CopyInfo_f(void)
5822 if (!r_editlights.integer)
5824 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
5827 if (!r_shadow_selectedlight)
5829 Con_Print("No selected light.\n");
5832 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
5833 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
5834 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
5835 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
5836 if (r_shadow_selectedlight->cubemapname)
5837 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
5839 r_shadow_bufferlight.cubemapname[0] = 0;
5840 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
5841 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
5842 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
5843 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
5844 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
5845 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
5846 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
5849 void R_Shadow_EditLights_PasteInfo_f(void)
5851 if (!r_editlights.integer)
5853 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
5856 if (!r_shadow_selectedlight)
5858 Con_Print("No selected light.\n");
5861 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);
5864 void R_Shadow_EditLights_Init(void)
5866 Cvar_RegisterVariable(&r_editlights);
5867 Cvar_RegisterVariable(&r_editlights_cursordistance);
5868 Cvar_RegisterVariable(&r_editlights_cursorpushback);
5869 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
5870 Cvar_RegisterVariable(&r_editlights_cursorgrid);
5871 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
5872 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
5873 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
5874 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)");
5875 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
5876 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
5877 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
5878 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)");
5879 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
5880 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
5881 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
5882 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
5883 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
5884 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
5885 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)");
5891 =============================================================================
5895 =============================================================================
5898 void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, int dynamic)
5900 VectorClear(diffusecolor);
5901 VectorClear(diffusenormal);
5903 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
5905 ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_refdef.scene.ambient;
5906 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
5909 VectorSet(ambientcolor, 1, 1, 1);
5916 for (i = 0;i < r_refdef.scene.numlights;i++)
5918 light = r_refdef.scene.lights[i];
5919 Matrix4x4_Transform(&light->matrix_worldtolight, p, v);
5920 f = 1 - VectorLength2(v);
5921 if (f > 0 && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
5922 VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);