3 Terminology: Stencil Shadow Volume (sometimes called Stencil Shadows)
4 An extrusion of the lit faces, beginning at the original geometry and ending
5 further from the light source than the original geometry (presumably at least
6 as far as the light's radius, if the light has a radius at all), capped at
7 both front and back to avoid any problems (extrusion from dark faces also
8 works but has a different set of problems)
10 This is normally rendered using Carmack's Reverse technique, in which
11 backfaces behind zbuffer (zfail) increment the stencil, and frontfaces behind
12 zbuffer (zfail) decrement the stencil, the result is a stencil value of zero
13 where shadows did not intersect the visible geometry, suitable as a stencil
14 mask for rendering lighting everywhere but shadow.
16 In our case to hopefully avoid the Creative Labs patent, we draw the backfaces
17 as decrement and the frontfaces as increment, and we redefine the DepthFunc to
18 GL_LESS (the patent uses GL_GEQUAL) which causes zfail when behind surfaces
19 and zpass when infront (the patent draws where zpass with a GL_GEQUAL test),
20 additionally we clear stencil to 128 to avoid the need for the unclamped
21 incr/decr extension (not related to patent).
24 This algorithm may be covered by Creative's patent (US Patent #6384822),
25 however that patent is quite specific about increment on backfaces and
26 decrement on frontfaces where zpass with GL_GEQUAL depth test, which is
27 opposite this implementation and partially opposite Carmack's Reverse paper
28 (which uses GL_LESS, but increments on backfaces and decrements on frontfaces).
32 Terminology: Stencil Light Volume (sometimes called Light Volumes)
33 Similar to a Stencil Shadow Volume, but inverted; rather than containing the
34 areas in shadow it contains the areas in light, this can only be built
35 quickly for certain limited cases (such as portal visibility from a point),
36 but is quite useful for some effects (sunlight coming from sky polygons is
37 one possible example, translucent occluders is another example).
41 Terminology: Optimized Stencil Shadow Volume
42 A Stencil Shadow Volume that has been processed sufficiently to ensure it has
43 no duplicate coverage of areas (no need to shadow an area twice), often this
44 greatly improves performance but is an operation too costly to use on moving
45 lights (however completely optimal Stencil Light Volumes can be constructed
50 Terminology: Per Pixel Lighting (sometimes abbreviated PPL)
51 Per pixel evaluation of lighting equations, at a bare minimum this involves
52 DOT3 shading of diffuse lighting (per pixel dotproduct of negated incidence
53 vector and surface normal, using a texture of the surface bumps, called a
54 NormalMap) if supported by hardware; in our case there is support for cards
55 which are incapable of DOT3, the quality is quite poor however. Additionally
56 it is desirable to have specular evaluation per pixel, per vertex
57 normalization of specular halfangle vectors causes noticable distortion but
58 is unavoidable on hardware without GL_ARB_fragment_program or
59 GL_ARB_fragment_shader.
63 Terminology: Normalization CubeMap
64 A cubemap containing normalized dot3-encoded (vectors of length 1 or less
65 encoded as RGB colors) for any possible direction, this technique allows per
66 pixel calculation of incidence vector for per pixel lighting purposes, which
67 would not otherwise be possible per pixel without GL_ARB_fragment_program or
68 GL_ARB_fragment_shader.
72 Terminology: 2D+1D Attenuation Texturing
73 A very crude approximation of light attenuation with distance which results
74 in cylindrical light shapes which fade vertically as a streak (some games
75 such as Doom3 allow this to be rotated to be less noticable in specific
76 cases), the technique is simply modulating lighting by two 2D textures (which
77 can be the same) on different axes of projection (XY and Z, typically), this
78 is the second best technique available without 3D Attenuation Texturing,
79 GL_ARB_fragment_program or GL_ARB_fragment_shader technology.
83 Terminology: 2D+1D Inverse Attenuation Texturing
84 A clever method described in papers on the Abducted engine, this has a squared
85 distance texture (bright on the outside, black in the middle), which is used
86 twice using GL_ADD blending, the result of this is used in an inverse modulate
87 (GL_ONE_MINUS_DST_ALPHA, GL_ZERO) to implement the equation
88 lighting*=(1-((X*X+Y*Y)+(Z*Z))) which is spherical (unlike 2D+1D attenuation
93 Terminology: 3D Attenuation Texturing
94 A slightly crude approximation of light attenuation with distance, its flaws
95 are limited radius and resolution (performance tradeoffs).
99 Terminology: 3D Attenuation-Normalization Texturing
100 A 3D Attenuation Texture merged with a Normalization CubeMap, by making the
101 vectors shorter the lighting becomes darker, a very effective optimization of
102 diffuse lighting if 3D Attenuation Textures are already used.
106 Terminology: Light Cubemap Filtering
107 A technique for modeling non-uniform light distribution according to
108 direction, for example a lantern may use a cubemap to describe the light
109 emission pattern of the cage around the lantern (as well as soot buildup
110 discoloring the light in certain areas), often also used for softened grate
111 shadows and light shining through a stained glass window (done crudely by
112 texturing the lighting with a cubemap), another good example would be a disco
113 light. This technique is used heavily in many games (Doom3 does not support
118 Terminology: Light Projection Filtering
119 A technique for modeling shadowing of light passing through translucent
120 surfaces, allowing stained glass windows and other effects to be done more
121 elegantly than possible with Light Cubemap Filtering by applying an occluder
122 texture to the lighting combined with a stencil light volume to limit the lit
123 area, this technique is used by Doom3 for spotlights and flashlights, among
124 other things, this can also be used more generally to render light passing
125 through multiple translucent occluders in a scene (using a light volume to
126 describe the area beyond the occluder, and thus mask off rendering of all
131 Terminology: Doom3 Lighting
132 A combination of Stencil Shadow Volume, Per Pixel Lighting, Normalization
133 CubeMap, 2D+1D Attenuation Texturing, and Light Projection Filtering, as
134 demonstrated by the game Doom3.
137 #include "quakedef.h"
138 #include "r_shadow.h"
139 #include "cl_collision.h"
143 extern void R_Shadow_EditLights_Init(void);
145 typedef enum r_shadow_rendermode_e
147 R_SHADOW_RENDERMODE_NONE,
148 R_SHADOW_RENDERMODE_ZPASS_STENCIL,
149 R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL,
150 R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE,
151 R_SHADOW_RENDERMODE_ZFAIL_STENCIL,
152 R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL,
153 R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE,
154 R_SHADOW_RENDERMODE_LIGHT_VERTEX,
155 R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN,
156 R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN,
157 R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN,
158 R_SHADOW_RENDERMODE_LIGHT_GLSL,
159 R_SHADOW_RENDERMODE_VISIBLEVOLUMES,
160 R_SHADOW_RENDERMODE_VISIBLELIGHTING,
161 R_SHADOW_RENDERMODE_SHADOWMAP2D,
162 R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE,
163 R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE,
165 r_shadow_rendermode_t;
167 typedef enum r_shadow_shadowmode_e
169 R_SHADOW_SHADOWMODE_STENCIL,
170 R_SHADOW_SHADOWMODE_SHADOWMAP2D,
171 R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE,
172 R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE
174 r_shadow_shadowmode_t;
176 r_shadow_rendermode_t r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
177 r_shadow_rendermode_t r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_NONE;
178 r_shadow_rendermode_t r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_NONE;
179 r_shadow_rendermode_t r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_NONE;
180 qboolean r_shadow_usingshadowmaprect;
181 qboolean r_shadow_usingshadowmap2d;
182 qboolean r_shadow_usingshadowmapcube;
183 qboolean r_shadow_usingshadowmaportho;
184 int r_shadow_shadowmapside;
185 float r_shadow_shadowmap_texturescale[2];
186 float r_shadow_shadowmap_parameters[4];
188 int r_shadow_drawbuffer;
189 int r_shadow_readbuffer;
191 int r_shadow_cullface_front, r_shadow_cullface_back;
192 GLuint r_shadow_fborectangle;
193 GLuint r_shadow_fbocubeside[R_SHADOW_SHADOWMAP_NUMCUBEMAPS];
194 GLuint r_shadow_fbo2d;
195 r_shadow_shadowmode_t r_shadow_shadowmode;
196 int r_shadow_shadowmapfilterquality;
197 int r_shadow_shadowmaptexturetype;
198 int r_shadow_shadowmapdepthbits;
199 int r_shadow_shadowmapmaxsize;
200 qboolean r_shadow_shadowmapvsdct;
201 qboolean r_shadow_shadowmapsampler;
202 int r_shadow_shadowmappcf;
203 int r_shadow_shadowmapborder;
204 matrix4x4_t r_shadow_shadowmapmatrix;
205 int r_shadow_lightscissor[4];
206 qboolean r_shadow_usingdeferredprepass;
208 int maxshadowtriangles;
211 int maxshadowvertices;
212 float *shadowvertex3f;
222 unsigned char *shadowsides;
223 int *shadowsideslist;
230 int r_shadow_buffer_numleafpvsbytes;
231 unsigned char *r_shadow_buffer_visitingleafpvs;
232 unsigned char *r_shadow_buffer_leafpvs;
233 int *r_shadow_buffer_leaflist;
235 int r_shadow_buffer_numsurfacepvsbytes;
236 unsigned char *r_shadow_buffer_surfacepvs;
237 int *r_shadow_buffer_surfacelist;
238 unsigned char *r_shadow_buffer_surfacesides;
240 int r_shadow_buffer_numshadowtrispvsbytes;
241 unsigned char *r_shadow_buffer_shadowtrispvs;
242 int r_shadow_buffer_numlighttrispvsbytes;
243 unsigned char *r_shadow_buffer_lighttrispvs;
245 rtexturepool_t *r_shadow_texturepool;
246 rtexture_t *r_shadow_attenuationgradienttexture;
247 rtexture_t *r_shadow_attenuation2dtexture;
248 rtexture_t *r_shadow_attenuation3dtexture;
249 skinframe_t *r_shadow_lightcorona;
250 rtexture_t *r_shadow_shadowmaprectangletexture;
251 rtexture_t *r_shadow_shadowmap2dtexture;
252 rtexture_t *r_shadow_shadowmapcubetexture[R_SHADOW_SHADOWMAP_NUMCUBEMAPS];
253 rtexture_t *r_shadow_shadowmapvsdcttexture;
254 int r_shadow_shadowmapsize; // changes for each light based on distance
255 int r_shadow_shadowmaplod; // changes for each light based on distance
257 GLuint r_shadow_prepassgeometryfbo;
258 GLuint r_shadow_prepasslightingfbo;
259 int r_shadow_prepass_width;
260 int r_shadow_prepass_height;
261 rtexture_t *r_shadow_prepassgeometrydepthtexture;
262 rtexture_t *r_shadow_prepassgeometrynormalmaptexture;
263 rtexture_t *r_shadow_prepasslightingdiffusetexture;
264 rtexture_t *r_shadow_prepasslightingspeculartexture;
266 // lights are reloaded when this changes
267 char r_shadow_mapname[MAX_QPATH];
269 // used only for light filters (cubemaps)
270 rtexturepool_t *r_shadow_filters_texturepool;
272 static const GLenum r_shadow_prepasslightingdrawbuffers[2] = {GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT};
274 cvar_t r_shadow_bumpscale_basetexture = {0, "r_shadow_bumpscale_basetexture", "0", "generate fake bumpmaps from diffuse textures at this bumpyness, try 4 to match tenebrae, higher values increase depth, requires r_restart to take effect"};
275 cvar_t r_shadow_bumpscale_bumpmap = {0, "r_shadow_bumpscale_bumpmap", "4", "what magnitude to interpret _bump.tga textures as, higher values increase depth, requires r_restart to take effect"};
276 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
277 cvar_t r_shadow_deferred = {CVAR_SAVE, "r_shadow_deferred", "0", "uses image-based lighting instead of geometry-based lighting, the method used renders a depth image and a normalmap image, renders lights into separate diffuse and specular images, and then combines this into the normal rendering, requires r_shadow_shadowmapping"};
278 cvar_t r_shadow_deferred_8bitrange = {CVAR_SAVE, "r_shadow_deferred_8bitrange", "2", "dynamic range of image-based lighting when using 32bit color (does not apply to fp)"};
279 //cvar_t r_shadow_deferred_fp = {CVAR_SAVE, "r_shadow_deferred_fp", "0", "use 16bit (1) or 32bit (2) floating point for accumulation of image-based lighting"};
280 cvar_t r_shadow_usenormalmap = {CVAR_SAVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"};
281 cvar_t r_shadow_gloss = {CVAR_SAVE, "r_shadow_gloss", "1", "0 disables gloss (specularity) rendering, 1 uses gloss if textures are found, 2 forces a flat metallic specular effect on everything without textures (similar to tenebrae)"};
282 cvar_t r_shadow_gloss2intensity = {0, "r_shadow_gloss2intensity", "0.125", "how bright the forced flat gloss should look if r_shadow_gloss is 2"};
283 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
284 cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
285 cvar_t r_shadow_gloss2exponent = {0, "r_shadow_gloss2exponent", "32", "same as r_shadow_glossexponent but for forced gloss (gloss 2) surfaces"};
286 cvar_t r_shadow_glossexact = {0, "r_shadow_glossexact", "0", "use exact reflection math for gloss (slightly slower, but should look a tad better)"};
287 cvar_t r_shadow_lightattenuationdividebias = {0, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"};
288 cvar_t r_shadow_lightattenuationlinearscale = {0, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"};
289 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
290 cvar_t r_shadow_lightradiusscale = {0, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
291 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "0", "how far to cast shadows"};
292 cvar_t r_shadow_frontsidecasting = {0, "r_shadow_frontsidecasting", "1", "whether to cast shadows from illuminated triangles (front side of model) or unlit triangles (back side of model)"};
293 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
294 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
295 cvar_t r_shadow_realtime_dlight_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
296 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
297 cvar_t r_shadow_realtime_world = {CVAR_SAVE, "r_shadow_realtime_world", "0", "enables rendering of full world lighting (whether loaded from the map, or a .rtlights file, or a .ent file, or a .lights file produced by hlight)"};
298 cvar_t r_shadow_realtime_world_lightmaps = {CVAR_SAVE, "r_shadow_realtime_world_lightmaps", "0", "brightness to render lightmaps when using full world lighting, try 0.5 for a tenebrae-like appearance"};
299 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
300 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
301 cvar_t r_shadow_realtime_world_compileshadow = {0, "r_shadow_realtime_world_compileshadow", "1", "enables compilation of shadows from world lights for higher performance rendering"};
302 cvar_t r_shadow_realtime_world_compilesvbsp = {0, "r_shadow_realtime_world_compilesvbsp", "1", "enables svbsp optimization during compilation (slower than compileportalculling but more exact)"};
303 cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "0", "enables portal-based culling optimization during compilation (overrides compilesvbsp)"};
304 cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1", "use scissor optimization of light rendering (restricts rendering to the portion of the screen affected by the light)"};
305 cvar_t r_shadow_shadowmapping = {CVAR_SAVE, "r_shadow_shadowmapping", "0", "enables use of shadowmapping (depth texture sampling) instead of stencil shadow volumes, requires gl_fbo 1"};
306 cvar_t r_shadow_shadowmapping_texturetype = {CVAR_SAVE, "r_shadow_shadowmapping_texturetype", "-1", "shadowmap texture types: -1 = auto-select, 0 = 2D, 1 = rectangle, 2 = cubemap"};
307 cvar_t r_shadow_shadowmapping_filterquality = {CVAR_SAVE, "r_shadow_shadowmapping_filterquality", "-1", "shadowmap filter modes: -1 = auto-select, 0 = no filtering, 1 = bilinear, 2 = bilinear 2x2 blur (fast), 3 = 3x3 blur (moderate), 4 = 4x4 blur (slow)"};
308 cvar_t r_shadow_shadowmapping_depthbits = {CVAR_SAVE, "r_shadow_shadowmapping_depthbits", "24", "requested minimum shadowmap texture depth bits"};
309 cvar_t r_shadow_shadowmapping_vsdct = {CVAR_SAVE, "r_shadow_shadowmapping_vsdct", "1", "enables use of virtual shadow depth cube texture"};
310 cvar_t r_shadow_shadowmapping_minsize = {CVAR_SAVE, "r_shadow_shadowmapping_minsize", "32", "shadowmap size limit"};
311 cvar_t r_shadow_shadowmapping_maxsize = {CVAR_SAVE, "r_shadow_shadowmapping_maxsize", "512", "shadowmap size limit"};
312 cvar_t r_shadow_shadowmapping_precision = {CVAR_SAVE, "r_shadow_shadowmapping_precision", "1", "makes shadowmaps have a maximum resolution of this number of pixels per light source radius unit such that, for example, at precision 0.5 a light with radius 200 will have a maximum resolution of 100 pixels"};
313 //cvar_t r_shadow_shadowmapping_lod_bias = {CVAR_SAVE, "r_shadow_shadowmapping_lod_bias", "16", "shadowmap size bias"};
314 //cvar_t r_shadow_shadowmapping_lod_scale = {CVAR_SAVE, "r_shadow_shadowmapping_lod_scale", "128", "shadowmap size scaling parameter"};
315 cvar_t r_shadow_shadowmapping_bordersize = {CVAR_SAVE, "r_shadow_shadowmapping_bordersize", "4", "shadowmap size bias for filtering"};
316 cvar_t r_shadow_shadowmapping_nearclip = {CVAR_SAVE, "r_shadow_shadowmapping_nearclip", "1", "shadowmap nearclip in world units"};
317 cvar_t r_shadow_shadowmapping_bias = {CVAR_SAVE, "r_shadow_shadowmapping_bias", "0.03", "shadowmap bias parameter (this is multiplied by nearclip * 1024 / lodsize)"};
318 cvar_t r_shadow_shadowmapping_polygonfactor = {CVAR_SAVE, "r_shadow_shadowmapping_polygonfactor", "2", "slope-dependent shadowmapping bias"};
319 cvar_t r_shadow_shadowmapping_polygonoffset = {CVAR_SAVE, "r_shadow_shadowmapping_polygonoffset", "0", "constant shadowmapping bias"};
320 cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
321 cvar_t r_shadow_polygonoffset = {0, "r_shadow_polygonoffset", "1", "how much to push shadow volumes into the distance when rendering, to reduce chances of zfighting artifacts (should not be less than 0)"};
322 cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "1", "use 3D voxel textures for spherical attenuation rather than cylindrical (does not affect OpenGL 2.0 render path)"};
323 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "1", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
324 cvar_t r_coronas_occlusionsizescale = {CVAR_SAVE, "r_coronas_occlusionsizescale", "0.1", "size of light source for corona occlusion checksm the proportion of hidden pixels controls corona intensity"};
325 cvar_t r_coronas_occlusionquery = {CVAR_SAVE, "r_coronas_occlusionquery", "1", "use GL_ARB_occlusion_query extension if supported (fades coronas according to visibility)"};
326 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
327 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
328 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
329 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
330 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
331 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
332 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
333 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
334 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
336 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
337 #define ATTENTABLESIZE 256
338 // 1D gradient, 2D circle and 3D sphere attenuation textures
339 #define ATTEN1DSIZE 32
340 #define ATTEN2DSIZE 64
341 #define ATTEN3DSIZE 32
343 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
344 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
345 static float r_shadow_attentable[ATTENTABLESIZE+1];
347 rtlight_t *r_shadow_compilingrtlight;
348 static memexpandablearray_t r_shadow_worldlightsarray;
349 dlight_t *r_shadow_selectedlight;
350 dlight_t r_shadow_bufferlight;
351 vec3_t r_editlights_cursorlocation;
353 extern int con_vislines;
355 void R_Shadow_UncompileWorldLights(void);
356 void R_Shadow_ClearWorldLights(void);
357 void R_Shadow_SaveWorldLights(void);
358 void R_Shadow_LoadWorldLights(void);
359 void R_Shadow_LoadLightsFile(void);
360 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
361 void R_Shadow_EditLights_Reload_f(void);
362 void R_Shadow_ValidateCvars(void);
363 static void R_Shadow_MakeTextures(void);
365 #define EDLIGHTSPRSIZE 8
366 skinframe_t *r_editlights_sprcursor;
367 skinframe_t *r_editlights_sprlight;
368 skinframe_t *r_editlights_sprnoshadowlight;
369 skinframe_t *r_editlights_sprcubemaplight;
370 skinframe_t *r_editlights_sprcubemapnoshadowlight;
371 skinframe_t *r_editlights_sprselection;
373 void R_Shadow_SetShadowMode(void)
375 r_shadow_shadowmapmaxsize = bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4);
376 r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer != 0;
377 r_shadow_shadowmapfilterquality = r_shadow_shadowmapping_filterquality.integer;
378 r_shadow_shadowmaptexturetype = r_shadow_shadowmapping_texturetype.integer;
379 r_shadow_shadowmapdepthbits = r_shadow_shadowmapping_depthbits.integer;
380 r_shadow_shadowmapborder = bound(0, r_shadow_shadowmapping_bordersize.integer, 16);
381 r_shadow_shadowmaplod = -1;
382 r_shadow_shadowmapsize = 0;
383 r_shadow_shadowmapsampler = false;
384 r_shadow_shadowmappcf = 0;
385 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
386 switch(vid.renderpath)
388 case RENDERPATH_GL20:
389 case RENDERPATH_CGGL:
390 if ((r_shadow_shadowmapping.integer || r_shadow_deferred.integer) && vid.support.ext_framebuffer_object)
392 if(r_shadow_shadowmapfilterquality < 0)
394 if(vid.support.amd_texture_texture4 || vid.support.arb_texture_gather)
395 r_shadow_shadowmappcf = 1;
396 else if(strstr(gl_vendor, "NVIDIA") || strstr(gl_renderer, "Radeon HD"))
398 r_shadow_shadowmapsampler = vid.support.arb_shadow;
399 r_shadow_shadowmappcf = 1;
401 else if(strstr(gl_vendor, "ATI"))
402 r_shadow_shadowmappcf = 1;
404 r_shadow_shadowmapsampler = vid.support.arb_shadow;
408 switch (r_shadow_shadowmapfilterquality)
411 r_shadow_shadowmapsampler = vid.support.arb_shadow;
414 r_shadow_shadowmapsampler = vid.support.arb_shadow;
415 r_shadow_shadowmappcf = 1;
418 r_shadow_shadowmappcf = 1;
421 r_shadow_shadowmappcf = 2;
425 switch (r_shadow_shadowmaptexturetype)
428 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
431 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE;
434 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE;
437 if((vid.support.amd_texture_texture4 || vid.support.arb_texture_gather) && r_shadow_shadowmappcf && !r_shadow_shadowmapsampler)
438 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
439 else if(vid.support.arb_texture_rectangle)
440 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE;
442 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
447 case RENDERPATH_GL13:
449 case RENDERPATH_GL11:
454 qboolean R_Shadow_ShadowMappingEnabled(void)
456 switch (r_shadow_shadowmode)
458 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
459 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
460 case R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE:
467 void R_Shadow_FreeShadowMaps(void)
471 R_Shadow_SetShadowMode();
473 if (!vid.support.ext_framebuffer_object || !vid.support.arb_fragment_shader)
478 if (r_shadow_fborectangle)
479 qglDeleteFramebuffersEXT(1, &r_shadow_fborectangle);CHECKGLERROR
480 r_shadow_fborectangle = 0;
483 qglDeleteFramebuffersEXT(1, &r_shadow_fbo2d);CHECKGLERROR
485 for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
486 if (r_shadow_fbocubeside[i])
487 qglDeleteFramebuffersEXT(1, &r_shadow_fbocubeside[i]);CHECKGLERROR
488 memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
490 if (r_shadow_shadowmaprectangletexture)
491 R_FreeTexture(r_shadow_shadowmaprectangletexture);
492 r_shadow_shadowmaprectangletexture = NULL;
494 if (r_shadow_shadowmap2dtexture)
495 R_FreeTexture(r_shadow_shadowmap2dtexture);
496 r_shadow_shadowmap2dtexture = NULL;
498 for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
499 if (r_shadow_shadowmapcubetexture[i])
500 R_FreeTexture(r_shadow_shadowmapcubetexture[i]);
501 memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
503 if (r_shadow_shadowmapvsdcttexture)
504 R_FreeTexture(r_shadow_shadowmapvsdcttexture);
505 r_shadow_shadowmapvsdcttexture = NULL;
510 void r_shadow_start(void)
512 // allocate vertex processing arrays
513 r_shadow_attenuationgradienttexture = NULL;
514 r_shadow_attenuation2dtexture = NULL;
515 r_shadow_attenuation3dtexture = NULL;
516 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
517 r_shadow_shadowmaprectangletexture = NULL;
518 r_shadow_shadowmap2dtexture = NULL;
519 memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
520 r_shadow_shadowmapvsdcttexture = NULL;
521 r_shadow_shadowmapmaxsize = 0;
522 r_shadow_shadowmapsize = 0;
523 r_shadow_shadowmaplod = 0;
524 r_shadow_shadowmapfilterquality = -1;
525 r_shadow_shadowmaptexturetype = -1;
526 r_shadow_shadowmapdepthbits = 0;
527 r_shadow_shadowmapvsdct = false;
528 r_shadow_shadowmapsampler = false;
529 r_shadow_shadowmappcf = 0;
530 r_shadow_fborectangle = 0;
532 memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
534 R_Shadow_FreeShadowMaps();
536 r_shadow_texturepool = NULL;
537 r_shadow_filters_texturepool = NULL;
538 R_Shadow_ValidateCvars();
539 R_Shadow_MakeTextures();
540 maxshadowtriangles = 0;
541 shadowelements = NULL;
542 maxshadowvertices = 0;
543 shadowvertex3f = NULL;
551 shadowmarklist = NULL;
556 shadowsideslist = NULL;
557 r_shadow_buffer_numleafpvsbytes = 0;
558 r_shadow_buffer_visitingleafpvs = NULL;
559 r_shadow_buffer_leafpvs = NULL;
560 r_shadow_buffer_leaflist = NULL;
561 r_shadow_buffer_numsurfacepvsbytes = 0;
562 r_shadow_buffer_surfacepvs = NULL;
563 r_shadow_buffer_surfacelist = NULL;
564 r_shadow_buffer_surfacesides = NULL;
565 r_shadow_buffer_numshadowtrispvsbytes = 0;
566 r_shadow_buffer_shadowtrispvs = NULL;
567 r_shadow_buffer_numlighttrispvsbytes = 0;
568 r_shadow_buffer_lighttrispvs = NULL;
570 r_shadow_usingdeferredprepass = false;
571 r_shadow_prepass_width = r_shadow_prepass_height = 0;
574 static void R_Shadow_FreeDeferred(void);
575 void r_shadow_shutdown(void)
578 R_Shadow_UncompileWorldLights();
580 R_Shadow_FreeShadowMaps();
582 r_shadow_usingdeferredprepass = false;
583 if (r_shadow_prepass_width)
584 R_Shadow_FreeDeferred();
585 r_shadow_prepass_width = r_shadow_prepass_height = 0;
588 r_shadow_attenuationgradienttexture = NULL;
589 r_shadow_attenuation2dtexture = NULL;
590 r_shadow_attenuation3dtexture = NULL;
591 R_FreeTexturePool(&r_shadow_texturepool);
592 R_FreeTexturePool(&r_shadow_filters_texturepool);
593 maxshadowtriangles = 0;
595 Mem_Free(shadowelements);
596 shadowelements = NULL;
598 Mem_Free(shadowvertex3f);
599 shadowvertex3f = NULL;
602 Mem_Free(vertexupdate);
605 Mem_Free(vertexremap);
611 Mem_Free(shadowmark);
614 Mem_Free(shadowmarklist);
615 shadowmarklist = NULL;
620 Mem_Free(shadowsides);
623 Mem_Free(shadowsideslist);
624 shadowsideslist = NULL;
625 r_shadow_buffer_numleafpvsbytes = 0;
626 if (r_shadow_buffer_visitingleafpvs)
627 Mem_Free(r_shadow_buffer_visitingleafpvs);
628 r_shadow_buffer_visitingleafpvs = NULL;
629 if (r_shadow_buffer_leafpvs)
630 Mem_Free(r_shadow_buffer_leafpvs);
631 r_shadow_buffer_leafpvs = NULL;
632 if (r_shadow_buffer_leaflist)
633 Mem_Free(r_shadow_buffer_leaflist);
634 r_shadow_buffer_leaflist = NULL;
635 r_shadow_buffer_numsurfacepvsbytes = 0;
636 if (r_shadow_buffer_surfacepvs)
637 Mem_Free(r_shadow_buffer_surfacepvs);
638 r_shadow_buffer_surfacepvs = NULL;
639 if (r_shadow_buffer_surfacelist)
640 Mem_Free(r_shadow_buffer_surfacelist);
641 r_shadow_buffer_surfacelist = NULL;
642 if (r_shadow_buffer_surfacesides)
643 Mem_Free(r_shadow_buffer_surfacesides);
644 r_shadow_buffer_surfacesides = NULL;
645 r_shadow_buffer_numshadowtrispvsbytes = 0;
646 if (r_shadow_buffer_shadowtrispvs)
647 Mem_Free(r_shadow_buffer_shadowtrispvs);
648 r_shadow_buffer_numlighttrispvsbytes = 0;
649 if (r_shadow_buffer_lighttrispvs)
650 Mem_Free(r_shadow_buffer_lighttrispvs);
653 void r_shadow_newmap(void)
655 if (r_shadow_lightcorona) R_SkinFrame_MarkUsed(r_shadow_lightcorona);
656 if (r_editlights_sprcursor) R_SkinFrame_MarkUsed(r_editlights_sprcursor);
657 if (r_editlights_sprlight) R_SkinFrame_MarkUsed(r_editlights_sprlight);
658 if (r_editlights_sprnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprnoshadowlight);
659 if (r_editlights_sprcubemaplight) R_SkinFrame_MarkUsed(r_editlights_sprcubemaplight);
660 if (r_editlights_sprcubemapnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprcubemapnoshadowlight);
661 if (r_editlights_sprselection) R_SkinFrame_MarkUsed(r_editlights_sprselection);
662 if (cl.worldmodel && strncmp(cl.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
663 R_Shadow_EditLights_Reload_f();
666 void R_Shadow_Init(void)
668 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
669 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
670 Cvar_RegisterVariable(&r_shadow_usenormalmap);
671 Cvar_RegisterVariable(&r_shadow_debuglight);
672 Cvar_RegisterVariable(&r_shadow_deferred);
673 Cvar_RegisterVariable(&r_shadow_deferred_8bitrange);
674 // Cvar_RegisterVariable(&r_shadow_deferred_fp);
675 Cvar_RegisterVariable(&r_shadow_gloss);
676 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
677 Cvar_RegisterVariable(&r_shadow_glossintensity);
678 Cvar_RegisterVariable(&r_shadow_glossexponent);
679 Cvar_RegisterVariable(&r_shadow_gloss2exponent);
680 Cvar_RegisterVariable(&r_shadow_glossexact);
681 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
682 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
683 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
684 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
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_polygonfactor);
715 Cvar_RegisterVariable(&r_shadow_polygonoffset);
716 Cvar_RegisterVariable(&r_shadow_texture3d);
717 Cvar_RegisterVariable(&r_coronas);
718 Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
719 Cvar_RegisterVariable(&r_coronas_occlusionquery);
720 Cvar_RegisterVariable(&gl_flashblend);
721 Cvar_RegisterVariable(&gl_ext_separatestencil);
722 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
723 if (gamemode == GAME_TENEBRAE)
725 Cvar_SetValue("r_shadow_gloss", 2);
726 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
728 R_Shadow_EditLights_Init();
729 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
730 maxshadowtriangles = 0;
731 shadowelements = NULL;
732 maxshadowvertices = 0;
733 shadowvertex3f = NULL;
741 shadowmarklist = NULL;
746 shadowsideslist = NULL;
747 r_shadow_buffer_numleafpvsbytes = 0;
748 r_shadow_buffer_visitingleafpvs = NULL;
749 r_shadow_buffer_leafpvs = NULL;
750 r_shadow_buffer_leaflist = NULL;
751 r_shadow_buffer_numsurfacepvsbytes = 0;
752 r_shadow_buffer_surfacepvs = NULL;
753 r_shadow_buffer_surfacelist = NULL;
754 r_shadow_buffer_surfacesides = NULL;
755 r_shadow_buffer_shadowtrispvs = NULL;
756 r_shadow_buffer_lighttrispvs = NULL;
757 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
760 matrix4x4_t matrix_attenuationxyz =
763 {0.5, 0.0, 0.0, 0.5},
764 {0.0, 0.5, 0.0, 0.5},
765 {0.0, 0.0, 0.5, 0.5},
770 matrix4x4_t matrix_attenuationz =
773 {0.0, 0.0, 0.5, 0.5},
774 {0.0, 0.0, 0.0, 0.5},
775 {0.0, 0.0, 0.0, 0.5},
780 void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles, int vertscale, int triscale)
782 numvertices = ((numvertices + 255) & ~255) * vertscale;
783 numtriangles = ((numtriangles + 255) & ~255) * triscale;
784 // make sure shadowelements is big enough for this volume
785 if (maxshadowtriangles < numtriangles)
787 maxshadowtriangles = numtriangles;
789 Mem_Free(shadowelements);
790 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[3]));
792 // make sure shadowvertex3f is big enough for this volume
793 if (maxshadowvertices < numvertices)
795 maxshadowvertices = numvertices;
797 Mem_Free(shadowvertex3f);
798 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[3]));
802 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
804 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
805 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
806 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
807 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
808 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
810 if (r_shadow_buffer_visitingleafpvs)
811 Mem_Free(r_shadow_buffer_visitingleafpvs);
812 if (r_shadow_buffer_leafpvs)
813 Mem_Free(r_shadow_buffer_leafpvs);
814 if (r_shadow_buffer_leaflist)
815 Mem_Free(r_shadow_buffer_leaflist);
816 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
817 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
818 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
819 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
821 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
823 if (r_shadow_buffer_surfacepvs)
824 Mem_Free(r_shadow_buffer_surfacepvs);
825 if (r_shadow_buffer_surfacelist)
826 Mem_Free(r_shadow_buffer_surfacelist);
827 if (r_shadow_buffer_surfacesides)
828 Mem_Free(r_shadow_buffer_surfacesides);
829 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
830 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
831 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
832 r_shadow_buffer_surfacesides = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
834 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
836 if (r_shadow_buffer_shadowtrispvs)
837 Mem_Free(r_shadow_buffer_shadowtrispvs);
838 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
839 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
841 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
843 if (r_shadow_buffer_lighttrispvs)
844 Mem_Free(r_shadow_buffer_lighttrispvs);
845 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
846 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
850 void R_Shadow_PrepareShadowMark(int numtris)
852 // make sure shadowmark is big enough for this volume
853 if (maxshadowmark < numtris)
855 maxshadowmark = numtris;
857 Mem_Free(shadowmark);
859 Mem_Free(shadowmarklist);
860 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
861 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
865 // if shadowmarkcount wrapped we clear the array and adjust accordingly
866 if (shadowmarkcount == 0)
869 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
874 void R_Shadow_PrepareShadowSides(int numtris)
876 if (maxshadowsides < numtris)
878 maxshadowsides = numtris;
880 Mem_Free(shadowsides);
882 Mem_Free(shadowsideslist);
883 shadowsides = (unsigned char *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsides));
884 shadowsideslist = (int *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsideslist));
889 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)
892 int outtriangles = 0, outvertices = 0;
895 float ratio, direction[3], projectvector[3];
897 if (projectdirection)
898 VectorScale(projectdirection, projectdistance, projectvector);
900 VectorClear(projectvector);
902 // create the vertices
903 if (projectdirection)
905 for (i = 0;i < numshadowmarktris;i++)
907 element = inelement3i + shadowmarktris[i] * 3;
908 for (j = 0;j < 3;j++)
910 if (vertexupdate[element[j]] != vertexupdatenum)
912 vertexupdate[element[j]] = vertexupdatenum;
913 vertexremap[element[j]] = outvertices;
914 vertex = invertex3f + element[j] * 3;
915 // project one copy of the vertex according to projectvector
916 VectorCopy(vertex, outvertex3f);
917 VectorAdd(vertex, projectvector, (outvertex3f + 3));
926 for (i = 0;i < numshadowmarktris;i++)
928 element = inelement3i + shadowmarktris[i] * 3;
929 for (j = 0;j < 3;j++)
931 if (vertexupdate[element[j]] != vertexupdatenum)
933 vertexupdate[element[j]] = vertexupdatenum;
934 vertexremap[element[j]] = outvertices;
935 vertex = invertex3f + element[j] * 3;
936 // project one copy of the vertex to the sphere radius of the light
937 // (FIXME: would projecting it to the light box be better?)
938 VectorSubtract(vertex, projectorigin, direction);
939 ratio = projectdistance / VectorLength(direction);
940 VectorCopy(vertex, outvertex3f);
941 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
949 if (r_shadow_frontsidecasting.integer)
951 for (i = 0;i < numshadowmarktris;i++)
953 int remappedelement[3];
955 const int *neighbortriangle;
957 markindex = shadowmarktris[i] * 3;
958 element = inelement3i + markindex;
959 neighbortriangle = inneighbor3i + markindex;
960 // output the front and back triangles
961 outelement3i[0] = vertexremap[element[0]];
962 outelement3i[1] = vertexremap[element[1]];
963 outelement3i[2] = vertexremap[element[2]];
964 outelement3i[3] = vertexremap[element[2]] + 1;
965 outelement3i[4] = vertexremap[element[1]] + 1;
966 outelement3i[5] = vertexremap[element[0]] + 1;
970 // output the sides (facing outward from this triangle)
971 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
973 remappedelement[0] = vertexremap[element[0]];
974 remappedelement[1] = vertexremap[element[1]];
975 outelement3i[0] = remappedelement[1];
976 outelement3i[1] = remappedelement[0];
977 outelement3i[2] = remappedelement[0] + 1;
978 outelement3i[3] = remappedelement[1];
979 outelement3i[4] = remappedelement[0] + 1;
980 outelement3i[5] = remappedelement[1] + 1;
985 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
987 remappedelement[1] = vertexremap[element[1]];
988 remappedelement[2] = vertexremap[element[2]];
989 outelement3i[0] = remappedelement[2];
990 outelement3i[1] = remappedelement[1];
991 outelement3i[2] = remappedelement[1] + 1;
992 outelement3i[3] = remappedelement[2];
993 outelement3i[4] = remappedelement[1] + 1;
994 outelement3i[5] = remappedelement[2] + 1;
999 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1001 remappedelement[0] = vertexremap[element[0]];
1002 remappedelement[2] = vertexremap[element[2]];
1003 outelement3i[0] = remappedelement[0];
1004 outelement3i[1] = remappedelement[2];
1005 outelement3i[2] = remappedelement[2] + 1;
1006 outelement3i[3] = remappedelement[0];
1007 outelement3i[4] = remappedelement[2] + 1;
1008 outelement3i[5] = remappedelement[0] + 1;
1017 for (i = 0;i < numshadowmarktris;i++)
1019 int remappedelement[3];
1021 const int *neighbortriangle;
1023 markindex = shadowmarktris[i] * 3;
1024 element = inelement3i + markindex;
1025 neighbortriangle = inneighbor3i + markindex;
1026 // output the front and back triangles
1027 outelement3i[0] = vertexremap[element[2]];
1028 outelement3i[1] = vertexremap[element[1]];
1029 outelement3i[2] = vertexremap[element[0]];
1030 outelement3i[3] = vertexremap[element[0]] + 1;
1031 outelement3i[4] = vertexremap[element[1]] + 1;
1032 outelement3i[5] = vertexremap[element[2]] + 1;
1036 // output the sides (facing outward from this triangle)
1037 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
1039 remappedelement[0] = vertexremap[element[0]];
1040 remappedelement[1] = vertexremap[element[1]];
1041 outelement3i[0] = remappedelement[0];
1042 outelement3i[1] = remappedelement[1];
1043 outelement3i[2] = remappedelement[1] + 1;
1044 outelement3i[3] = remappedelement[0];
1045 outelement3i[4] = remappedelement[1] + 1;
1046 outelement3i[5] = remappedelement[0] + 1;
1051 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1053 remappedelement[1] = vertexremap[element[1]];
1054 remappedelement[2] = vertexremap[element[2]];
1055 outelement3i[0] = remappedelement[1];
1056 outelement3i[1] = remappedelement[2];
1057 outelement3i[2] = remappedelement[2] + 1;
1058 outelement3i[3] = remappedelement[1];
1059 outelement3i[4] = remappedelement[2] + 1;
1060 outelement3i[5] = remappedelement[1] + 1;
1065 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1067 remappedelement[0] = vertexremap[element[0]];
1068 remappedelement[2] = vertexremap[element[2]];
1069 outelement3i[0] = remappedelement[2];
1070 outelement3i[1] = remappedelement[0];
1071 outelement3i[2] = remappedelement[0] + 1;
1072 outelement3i[3] = remappedelement[2];
1073 outelement3i[4] = remappedelement[0] + 1;
1074 outelement3i[5] = remappedelement[2] + 1;
1082 *outnumvertices = outvertices;
1083 return outtriangles;
1086 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)
1089 int outtriangles = 0, outvertices = 0;
1091 const float *vertex;
1092 float ratio, direction[3], projectvector[3];
1095 if (projectdirection)
1096 VectorScale(projectdirection, projectdistance, projectvector);
1098 VectorClear(projectvector);
1100 for (i = 0;i < numshadowmarktris;i++)
1102 int remappedelement[3];
1104 const int *neighbortriangle;
1106 markindex = shadowmarktris[i] * 3;
1107 neighbortriangle = inneighbor3i + markindex;
1108 side[0] = shadowmark[neighbortriangle[0]] == shadowmarkcount;
1109 side[1] = shadowmark[neighbortriangle[1]] == shadowmarkcount;
1110 side[2] = shadowmark[neighbortriangle[2]] == shadowmarkcount;
1111 if (side[0] + side[1] + side[2] == 0)
1115 element = inelement3i + markindex;
1117 // create the vertices
1118 for (j = 0;j < 3;j++)
1120 if (side[j] + side[j+1] == 0)
1123 if (vertexupdate[k] != vertexupdatenum)
1125 vertexupdate[k] = vertexupdatenum;
1126 vertexremap[k] = outvertices;
1127 vertex = invertex3f + k * 3;
1128 VectorCopy(vertex, outvertex3f);
1129 if (projectdirection)
1131 // project one copy of the vertex according to projectvector
1132 VectorAdd(vertex, projectvector, (outvertex3f + 3));
1136 // project one copy of the vertex to the sphere radius of the light
1137 // (FIXME: would projecting it to the light box be better?)
1138 VectorSubtract(vertex, projectorigin, direction);
1139 ratio = projectdistance / VectorLength(direction);
1140 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1147 // output the sides (facing outward from this triangle)
1150 remappedelement[0] = vertexremap[element[0]];
1151 remappedelement[1] = vertexremap[element[1]];
1152 outelement3i[0] = remappedelement[1];
1153 outelement3i[1] = remappedelement[0];
1154 outelement3i[2] = remappedelement[0] + 1;
1155 outelement3i[3] = remappedelement[1];
1156 outelement3i[4] = remappedelement[0] + 1;
1157 outelement3i[5] = remappedelement[1] + 1;
1164 remappedelement[1] = vertexremap[element[1]];
1165 remappedelement[2] = vertexremap[element[2]];
1166 outelement3i[0] = remappedelement[2];
1167 outelement3i[1] = remappedelement[1];
1168 outelement3i[2] = remappedelement[1] + 1;
1169 outelement3i[3] = remappedelement[2];
1170 outelement3i[4] = remappedelement[1] + 1;
1171 outelement3i[5] = remappedelement[2] + 1;
1178 remappedelement[0] = vertexremap[element[0]];
1179 remappedelement[2] = vertexremap[element[2]];
1180 outelement3i[0] = remappedelement[0];
1181 outelement3i[1] = remappedelement[2];
1182 outelement3i[2] = remappedelement[2] + 1;
1183 outelement3i[3] = remappedelement[0];
1184 outelement3i[4] = remappedelement[2] + 1;
1185 outelement3i[5] = remappedelement[0] + 1;
1192 *outnumvertices = outvertices;
1193 return outtriangles;
1196 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)
1202 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1204 tend = firsttriangle + numtris;
1205 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1207 // surface box entirely inside light box, no box cull
1208 if (projectdirection)
1210 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1212 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
1213 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1214 shadowmarklist[numshadowmark++] = t;
1219 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1220 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
1221 shadowmarklist[numshadowmark++] = t;
1226 // surface box not entirely inside light box, cull each triangle
1227 if (projectdirection)
1229 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1231 v[0] = invertex3f + e[0] * 3;
1232 v[1] = invertex3f + e[1] * 3;
1233 v[2] = invertex3f + e[2] * 3;
1234 TriangleNormal(v[0], v[1], v[2], normal);
1235 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1236 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1237 shadowmarklist[numshadowmark++] = t;
1242 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1244 v[0] = invertex3f + e[0] * 3;
1245 v[1] = invertex3f + e[1] * 3;
1246 v[2] = invertex3f + e[2] * 3;
1247 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1248 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1249 shadowmarklist[numshadowmark++] = t;
1255 qboolean R_Shadow_UseZPass(vec3_t mins, vec3_t maxs)
1260 if (r_shadow_compilingrtlight || !r_shadow_frontsidecasting.integer || !r_shadow_usezpassifpossible.integer)
1262 // check if the shadow volume intersects the near plane
1264 // a ray between the eye and light origin may intersect the caster,
1265 // indicating that the shadow may touch the eye location, however we must
1266 // test the near plane (a polygon), not merely the eye location, so it is
1267 // easiest to enlarge the caster bounding shape slightly for this.
1273 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)
1275 int i, tris, outverts;
1276 if (projectdistance < 0.1)
1278 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
1281 if (!numverts || !nummarktris)
1283 // make sure shadowelements is big enough for this volume
1284 if (maxshadowtriangles < nummarktris*8 || maxshadowvertices < numverts*2)
1285 R_Shadow_ResizeShadowArrays(numverts, nummarktris, 2, 8);
1287 if (maxvertexupdate < numverts)
1289 maxvertexupdate = numverts;
1291 Mem_Free(vertexupdate);
1293 Mem_Free(vertexremap);
1294 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1295 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1296 vertexupdatenum = 0;
1299 if (vertexupdatenum == 0)
1301 vertexupdatenum = 1;
1302 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
1303 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
1306 for (i = 0;i < nummarktris;i++)
1307 shadowmark[marktris[i]] = shadowmarkcount;
1309 if (r_shadow_compilingrtlight)
1311 // if we're compiling an rtlight, capture the mesh
1312 //tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1313 //Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zpass, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1314 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1315 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zfail, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1317 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
1319 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1320 R_Mesh_VertexPointer(shadowvertex3f, 0, 0);
1321 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1325 // decide which type of shadow to generate and set stencil mode
1326 R_Shadow_RenderMode_StencilShadowVolumes(R_Shadow_UseZPass(trismins, trismaxs));
1327 // generate the sides or a solid volume, depending on type
1328 if (r_shadow_rendermode >= R_SHADOW_RENDERMODE_ZPASS_STENCIL && r_shadow_rendermode <= R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE)
1329 tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1331 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1332 r_refdef.stats.lights_dynamicshadowtriangles += tris;
1333 r_refdef.stats.lights_shadowtriangles += tris;
1335 R_Mesh_VertexPointer(shadowvertex3f, 0, 0);
1336 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
1338 // increment stencil if frontface is infront of depthbuffer
1339 GL_CullFace(r_refdef.view.cullface_front);
1340 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1341 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1342 // decrement stencil if backface is infront of depthbuffer
1343 GL_CullFace(r_refdef.view.cullface_back);
1344 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1346 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
1348 // decrement stencil if backface is behind depthbuffer
1349 GL_CullFace(r_refdef.view.cullface_front);
1350 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1351 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1352 // increment stencil if frontface is behind depthbuffer
1353 GL_CullFace(r_refdef.view.cullface_back);
1354 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1356 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1361 int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias)
1363 // p1, p2, p3 are in the cubemap's local coordinate system
1364 // bias = border/(size - border)
1367 float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1368 dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2),
1369 dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3);
1370 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1372 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1373 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1374 | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1375 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1377 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1378 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1379 | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1381 dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1382 dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2),
1383 dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3);
1384 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1386 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1387 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1388 | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1389 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1391 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1392 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1393 | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1395 dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1396 dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2),
1397 dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3);
1398 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1400 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1401 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1402 | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1403 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1405 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1406 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1407 | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1412 int R_Shadow_CalcBBoxSideMask(const vec3_t mins, const vec3_t maxs, const matrix4x4_t *worldtolight, const matrix4x4_t *radiustolight, float bias)
1414 vec3_t center, radius, lightcenter, lightradius, pmin, pmax;
1415 float dp1, dn1, ap1, an1, dp2, dn2, ap2, an2;
1418 VectorSubtract(maxs, mins, radius);
1419 VectorScale(radius, 0.5f, radius);
1420 VectorAdd(mins, radius, center);
1421 Matrix4x4_Transform(worldtolight, center, lightcenter);
1422 Matrix4x4_Transform3x3(radiustolight, radius, lightradius);
1423 VectorSubtract(lightcenter, lightradius, pmin);
1424 VectorAdd(lightcenter, lightradius, pmax);
1426 dp1 = pmax[0] + pmax[1], dn1 = pmax[0] - pmin[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1427 dp2 = pmin[0] + pmin[1], dn2 = pmin[0] - pmax[1], ap2 = fabs(dp2), an2 = fabs(dn2);
1428 if(ap1 > bias*an1 && ap2 > bias*an2)
1430 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1431 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1432 if(an1 > bias*ap1 && an2 > bias*ap2)
1434 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1435 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1437 dp1 = pmax[1] + pmax[2], dn1 = pmax[1] - pmin[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1438 dp2 = pmin[1] + pmin[2], dn2 = pmin[1] - pmax[2], ap2 = fabs(dp2), an2 = fabs(dn2);
1439 if(ap1 > bias*an1 && ap2 > bias*an2)
1441 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1442 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1443 if(an1 > bias*ap1 && an2 > bias*ap2)
1445 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1446 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1448 dp1 = pmax[2] + pmax[0], dn1 = pmax[2] - pmin[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1449 dp2 = pmin[2] + pmin[0], dn2 = pmin[2] - pmax[0], ap2 = fabs(dp2), an2 = fabs(dn2);
1450 if(ap1 > bias*an1 && ap2 > bias*an2)
1452 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1453 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1454 if(an1 > bias*ap1 && an2 > bias*ap2)
1456 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1457 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1462 #define R_Shadow_CalcEntitySideMask(ent, worldtolight, radiustolight, bias) R_Shadow_CalcBBoxSideMask((ent)->mins, (ent)->maxs, worldtolight, radiustolight, bias)
1464 int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
1466 // p is in the cubemap's local coordinate system
1467 // bias = border/(size - border)
1468 float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn);
1469 float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn);
1470 float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn);
1472 if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
1473 if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
1474 if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
1475 if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
1476 if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
1477 if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
1481 int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
1485 int sides = 0x3F, masks[6] = { 3<<4, 3<<4, 3<<0, 3<<0, 3<<2, 3<<2 };
1486 float scale = (size - 2*border)/size, len;
1487 float bias = border / (float)(size - border), dp, dn, ap, an;
1488 // check if cone enclosing side would cross frustum plane
1489 scale = 2 / (scale*scale + 2);
1490 for (i = 0;i < 5;i++)
1492 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) > -0.03125)
1494 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[i].normal, n);
1495 len = scale*VectorLength2(n);
1496 if(n[0]*n[0] > len) sides &= n[0] < 0 ? ~(1<<0) : ~(2 << 0);
1497 if(n[1]*n[1] > len) sides &= n[1] < 0 ? ~(1<<2) : ~(2 << 2);
1498 if(n[2]*n[2] > len) sides &= n[2] < 0 ? ~(1<<4) : ~(2 << 4);
1500 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[4]) >= r_refdef.farclip - r_refdef.nearclip + 0.03125)
1502 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[4].normal, n);
1503 len = scale*VectorLength(n);
1504 if(n[0]*n[0] > len) sides &= n[0] >= 0 ? ~(1<<0) : ~(2 << 0);
1505 if(n[1]*n[1] > len) sides &= n[1] >= 0 ? ~(1<<2) : ~(2 << 2);
1506 if(n[2]*n[2] > len) sides &= n[2] >= 0 ? ~(1<<4) : ~(2 << 4);
1508 // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results
1509 // check if frustum corners/origin cross plane sides
1510 for (i = 0;i < 5;i++)
1512 Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p);
1513 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn),
1514 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1515 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1516 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn),
1517 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1518 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1519 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn),
1520 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1521 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1523 return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5];
1526 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)
1534 int mask, surfacemask = 0;
1535 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1537 bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
1538 tend = firsttriangle + numtris;
1539 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1541 // surface box entirely inside light box, no box cull
1542 if (projectdirection)
1544 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1546 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1547 TriangleNormal(v[0], v[1], v[2], normal);
1548 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1550 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1551 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1552 surfacemask |= mask;
1555 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;
1556 shadowsides[numshadowsides] = mask;
1557 shadowsideslist[numshadowsides++] = t;
1564 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1566 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1567 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]))
1569 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1570 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1571 surfacemask |= mask;
1574 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;
1575 shadowsides[numshadowsides] = mask;
1576 shadowsideslist[numshadowsides++] = t;
1584 // surface box not entirely inside light box, cull each triangle
1585 if (projectdirection)
1587 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1589 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1590 TriangleNormal(v[0], v[1], v[2], normal);
1591 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1592 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1594 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1595 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1596 surfacemask |= mask;
1599 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;
1600 shadowsides[numshadowsides] = mask;
1601 shadowsideslist[numshadowsides++] = t;
1608 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1610 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1611 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1612 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1614 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1615 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1616 surfacemask |= mask;
1619 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;
1620 shadowsides[numshadowsides] = mask;
1621 shadowsideslist[numshadowsides++] = t;
1630 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)
1632 int i, j, outtriangles = 0;
1633 int *outelement3i[6];
1634 if (!numverts || !numsidetris || !r_shadow_compilingrtlight)
1636 outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5];
1637 // make sure shadowelements is big enough for this mesh
1638 if (maxshadowtriangles < outtriangles)
1639 R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1);
1641 // compute the offset and size of the separate index lists for each cubemap side
1643 for (i = 0;i < 6;i++)
1645 outelement3i[i] = shadowelements + outtriangles * 3;
1646 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles;
1647 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i];
1648 outtriangles += sidetotals[i];
1651 // gather up the (sparse) triangles into separate index lists for each cubemap side
1652 for (i = 0;i < numsidetris;i++)
1654 const int *element = elements + sidetris[i] * 3;
1655 for (j = 0;j < 6;j++)
1657 if (sides[i] & (1 << j))
1659 outelement3i[j][0] = element[0];
1660 outelement3i[j][1] = element[1];
1661 outelement3i[j][2] = element[2];
1662 outelement3i[j] += 3;
1667 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, outtriangles, shadowelements);
1670 static void R_Shadow_MakeTextures_MakeCorona(void)
1674 unsigned char pixels[32][32][4];
1675 for (y = 0;y < 32;y++)
1677 dy = (y - 15.5f) * (1.0f / 16.0f);
1678 for (x = 0;x < 32;x++)
1680 dx = (x - 15.5f) * (1.0f / 16.0f);
1681 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1682 a = bound(0, a, 255);
1683 pixels[y][x][0] = a;
1684 pixels[y][x][1] = a;
1685 pixels[y][x][2] = a;
1686 pixels[y][x][3] = 255;
1689 r_shadow_lightcorona = R_SkinFrame_LoadInternalBGRA("lightcorona", TEXF_FORCELINEAR, &pixels[0][0][0], 32, 32);
1692 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1694 float dist = sqrt(x*x+y*y+z*z);
1695 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1696 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1697 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1700 static void R_Shadow_MakeTextures(void)
1703 float intensity, dist;
1705 R_Shadow_FreeShadowMaps();
1706 R_FreeTexturePool(&r_shadow_texturepool);
1707 r_shadow_texturepool = R_AllocTexturePool();
1708 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1709 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1710 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1711 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1712 for (x = 0;x <= ATTENTABLESIZE;x++)
1714 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1715 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1716 r_shadow_attentable[x] = bound(0, intensity, 1);
1718 // 1D gradient texture
1719 for (x = 0;x < ATTEN1DSIZE;x++)
1720 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1721 r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, NULL);
1722 // 2D circle texture
1723 for (y = 0;y < ATTEN2DSIZE;y++)
1724 for (x = 0;x < ATTEN2DSIZE;x++)
1725 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);
1726 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, NULL);
1727 // 3D sphere texture
1728 if (r_shadow_texture3d.integer && vid.support.ext_texture_3d)
1730 for (z = 0;z < ATTEN3DSIZE;z++)
1731 for (y = 0;y < ATTEN3DSIZE;y++)
1732 for (x = 0;x < ATTEN3DSIZE;x++)
1733 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));
1734 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, NULL);
1737 r_shadow_attenuation3dtexture = NULL;
1740 R_Shadow_MakeTextures_MakeCorona();
1742 // Editor light sprites
1743 r_editlights_sprcursor = R_SkinFrame_LoadInternal8bit("gfx/editlights/cursor", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1760 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1761 r_editlights_sprlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/light", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1778 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1779 r_editlights_sprnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/noshadow", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1796 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1797 r_editlights_sprcubemaplight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemaplight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1814 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1815 r_editlights_sprcubemapnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemapnoshadowlight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1832 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1833 r_editlights_sprselection = R_SkinFrame_LoadInternal8bit("gfx/editlights/selection", TEXF_ALPHA | TEXF_CLAMP, (unsigned char *)
1850 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1853 void R_Shadow_ValidateCvars(void)
1855 if (r_shadow_texture3d.integer && !vid.support.ext_texture_3d)
1856 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1857 if (gl_ext_separatestencil.integer && !vid.support.ati_separate_stencil)
1858 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
1859 if (gl_ext_stenciltwoside.integer && !vid.support.ext_stencil_two_side)
1860 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1863 void R_Shadow_RenderMode_Begin(void)
1869 R_Shadow_ValidateCvars();
1871 if (!r_shadow_attenuation2dtexture
1872 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1873 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1874 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1875 R_Shadow_MakeTextures();
1878 R_Mesh_ColorPointer(NULL, 0, 0);
1879 R_Mesh_ResetTextureState();
1880 GL_BlendFunc(GL_ONE, GL_ZERO);
1881 GL_DepthRange(0, 1);
1882 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1884 GL_DepthMask(false);
1885 GL_Color(0, 0, 0, 1);
1886 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1888 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1890 if (gl_ext_separatestencil.integer && vid.support.ati_separate_stencil)
1892 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
1893 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
1895 else if (gl_ext_stenciltwoside.integer && vid.support.ext_stencil_two_side)
1897 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
1898 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
1902 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
1903 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
1906 switch(vid.renderpath)
1908 case RENDERPATH_GL20:
1909 case RENDERPATH_CGGL:
1910 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1912 case RENDERPATH_GL13:
1913 case RENDERPATH_GL11:
1914 if (r_textureunits.integer >= 2 && vid.texunits >= 2 && r_shadow_texture3d.integer && r_shadow_attenuation3dtexture)
1915 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN;
1916 else if (r_textureunits.integer >= 3 && vid.texunits >= 3)
1917 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN;
1918 else if (r_textureunits.integer >= 2 && vid.texunits >= 2)
1919 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN;
1921 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1927 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
1928 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
1929 r_shadow_drawbuffer = drawbuffer;
1930 r_shadow_readbuffer = readbuffer;
1932 r_shadow_cullface_front = r_refdef.view.cullface_front;
1933 r_shadow_cullface_back = r_refdef.view.cullface_back;
1936 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
1938 rsurface.rtlight = rtlight;
1941 void R_Shadow_RenderMode_Reset(void)
1944 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE)
1946 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1948 if (vid.support.ext_framebuffer_object)
1950 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);CHECKGLERROR
1953 qglDrawBuffer(r_shadow_drawbuffer);CHECKGLERROR
1954 qglReadBuffer(r_shadow_readbuffer);CHECKGLERROR
1956 R_SetViewport(&r_refdef.view.viewport);
1957 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
1958 R_Mesh_ColorPointer(NULL, 0, 0);
1959 R_Mesh_ResetTextureState();
1960 GL_DepthRange(0, 1);
1962 GL_DepthMask(false);
1963 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1964 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1965 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
1966 qglStencilMask(255);CHECKGLERROR
1967 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
1968 qglStencilFunc(GL_ALWAYS, 128, 255);CHECKGLERROR
1969 r_refdef.view.cullface_front = r_shadow_cullface_front;
1970 r_refdef.view.cullface_back = r_shadow_cullface_back;
1971 GL_CullFace(r_refdef.view.cullface_back);
1972 GL_Color(1, 1, 1, 1);
1973 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
1974 GL_BlendFunc(GL_ONE, GL_ZERO);
1975 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
1976 r_shadow_usingshadowmaprect = false;
1977 r_shadow_usingshadowmapcube = false;
1978 r_shadow_usingshadowmap2d = false;
1979 r_shadow_usingshadowmaportho = false;
1983 void R_Shadow_ClearStencil(void)
1986 GL_Clear(GL_STENCIL_BUFFER_BIT);
1987 r_refdef.stats.lights_clears++;
1990 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
1992 r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
1993 if (r_shadow_rendermode == mode)
1996 R_Shadow_RenderMode_Reset();
1997 GL_ColorMask(0, 0, 0, 0);
1998 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1999 R_SetupShader_DepthOrShadow();
2000 qglDepthFunc(GL_LESS);CHECKGLERROR
2001 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2002 r_shadow_rendermode = mode;
2007 case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
2008 GL_CullFace(GL_NONE);
2009 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
2010 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
2012 case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
2013 GL_CullFace(GL_NONE);
2014 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
2015 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
2017 case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
2018 GL_CullFace(GL_NONE);
2019 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
2020 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
2021 qglStencilMask(255);CHECKGLERROR
2022 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
2023 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
2024 qglStencilMask(255);CHECKGLERROR
2025 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
2027 case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
2028 GL_CullFace(GL_NONE);
2029 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
2030 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
2031 qglStencilMask(255);CHECKGLERROR
2032 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
2033 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
2034 qglStencilMask(255);CHECKGLERROR
2035 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
2040 static void R_Shadow_MakeVSDCT(void)
2042 // maps to a 2x3 texture rectangle with normalized coordinates
2047 // stores abs(dir.xy), offset.xy/2.5
2048 unsigned char data[4*6] =
2050 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
2051 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
2052 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
2053 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
2054 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
2055 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
2057 r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, NULL);
2060 static void R_Shadow_MakeShadowMap(int side, int size)
2063 switch (r_shadow_shadowmode)
2065 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2066 if (r_shadow_shadowmap2dtexture) return;
2067 r_shadow_shadowmap2dtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "shadowmap", size*2, size*(vid.support.arb_texture_non_power_of_two ? 3 : 4), r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
2068 qglGenFramebuffersEXT(1, &r_shadow_fbo2d);CHECKGLERROR
2069 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbo2d);CHECKGLERROR
2070 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_shadowmap2dtexture), 0);CHECKGLERROR
2072 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
2073 if (r_shadow_shadowmaprectangletexture) return;
2074 r_shadow_shadowmaprectangletexture = R_LoadTextureShadowMapRectangle(r_shadow_texturepool, "shadowmap", size*2, size*3, r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
2075 qglGenFramebuffersEXT(1, &r_shadow_fborectangle);CHECKGLERROR
2076 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fborectangle);CHECKGLERROR
2077 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, R_GetTexture(r_shadow_shadowmaprectangletexture), 0);CHECKGLERROR
2079 case R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE:
2080 if (r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]) return;
2081 r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod] = R_LoadTextureShadowMapCube(r_shadow_texturepool, "shadowmapcube", size, r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
2082 qglGenFramebuffersEXT(1, &r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR
2083 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR
2084 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
2089 // render depth into the fbo, do not render color at all
2090 qglDrawBuffer(GL_NONE);CHECKGLERROR
2091 qglReadBuffer(GL_NONE);CHECKGLERROR
2092 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2093 if (status != GL_FRAMEBUFFER_COMPLETE_EXT && (r_shadow_shadowmapping.integer || r_shadow_deferred.integer))
2095 Con_Printf("R_Shadow_MakeShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2096 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2097 Cvar_SetValueQuick(&r_shadow_deferred, 0);
2101 void R_Shadow_RenderMode_ShadowMap(int side, int clear, int size)
2103 float nearclip, farclip, bias;
2104 r_viewport_t viewport;
2108 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
2110 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
2111 r_shadow_shadowmap_parameters[2] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
2112 r_shadow_shadowmap_parameters[3] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
2113 r_shadow_shadowmapside = side;
2114 r_shadow_shadowmapsize = size;
2115 switch (r_shadow_shadowmode)
2117 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2118 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2119 r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2120 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
2121 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D) goto init_done;
2123 // complex unrolled cube approach (more flexible)
2124 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2125 R_Shadow_MakeVSDCT();
2126 if (!r_shadow_shadowmap2dtexture)
2127 R_Shadow_MakeShadowMap(side, r_shadow_shadowmapmaxsize);
2129 if (r_shadow_shadowmap2dtexture) fbo = r_shadow_fbo2d;
2130 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
2131 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
2132 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
2134 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
2135 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2136 r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2137 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
2138 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE) goto init_done;
2140 // complex unrolled cube approach (more flexible)
2141 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2142 R_Shadow_MakeVSDCT();
2143 if (!r_shadow_shadowmaprectangletexture)
2144 R_Shadow_MakeShadowMap(side, r_shadow_shadowmapmaxsize);
2146 if(r_shadow_shadowmaprectangletexture) fbo = r_shadow_fborectangle;
2147 r_shadow_shadowmap_texturescale[0] = 1.0f;
2148 r_shadow_shadowmap_texturescale[1] = 1.0f;
2149 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE;
2151 case R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE:
2152 r_shadow_shadowmap_parameters[0] = 1.0f;
2153 r_shadow_shadowmap_parameters[1] = 1.0f;
2154 R_Viewport_InitCubeSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, nearclip, farclip, NULL);
2155 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE) goto init_done;
2157 // simple cube approach
2158 if (!r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod])
2159 R_Shadow_MakeShadowMap(side, size);
2161 if (r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]) fbo = r_shadow_fbocubeside[r_shadow_shadowmaplod];
2162 r_shadow_shadowmap_texturescale[0] = 0.0f;
2163 r_shadow_shadowmap_texturescale[1] = 0.0f;
2164 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE;
2170 R_Shadow_RenderMode_Reset();
2173 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);CHECKGLERROR
2174 R_SetupShader_DepthOrShadow();
2178 R_SetupShader_ShowDepth();
2179 qglClearColor(1,1,1,1);CHECKGLERROR
2182 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
2189 R_SetViewport(&viewport);
2190 switch (r_shadow_rendermode)
2192 case R_SHADOW_RENDERMODE_SHADOWMAP2D:
2193 case R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE:
2194 flipped = (side & 1) ^ (side >> 2);
2195 r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
2196 r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
2197 GL_CullFace(r_refdef.view.cullface_back);
2198 if ((clear & ((2 << side) - 1)) == (1 << side)) // only clear if the side is the first in the mask
2200 // get tightest scissor rectangle that encloses all viewports in the clear mask
2201 int x1 = clear & 0x15 ? 0 : size;
2202 int x2 = clear & 0x2A ? 2 * size : size;
2203 int y1 = clear & 0x03 ? 0 : (clear & 0xC ? size : 2 * size);
2204 int y2 = clear & 0x30 ? 3 * size : (clear & 0xC ? 2 * size : size);
2205 GL_Scissor(x1, y1, x2 - x1, y2 - y1);
2206 GL_Clear(GL_DEPTH_BUFFER_BIT);
2208 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2210 case R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE:
2211 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
2212 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2214 GL_Clear(GL_DEPTH_BUFFER_BIT);
2222 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
2226 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2227 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2228 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2229 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2232 R_Shadow_RenderMode_Reset();
2233 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2236 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2240 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2241 // only draw light where this geometry was already rendered AND the
2242 // stencil is 128 (values other than this mean shadow)
2243 qglStencilFunc(GL_EQUAL, 128, 255);CHECKGLERROR
2245 r_shadow_rendermode = r_shadow_lightingrendermode;
2246 // do global setup needed for the chosen lighting mode
2247 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2249 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2254 switch (r_shadow_shadowmode)
2256 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2257 r_shadow_usingshadowmap2d = true;
2259 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
2260 r_shadow_usingshadowmaprect = true;
2262 case R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE:
2263 r_shadow_usingshadowmapcube = true;
2269 R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
2273 static const unsigned short bboxelements[36] =
2283 static const float bboxpoints[8][3] =
2295 void R_Shadow_RenderMode_DrawDeferredLight(qboolean stenciltest, qboolean shadowmapping)
2298 float vertex3f[8*3];
2299 const matrix4x4_t *matrix = &rsurface.rtlight->matrix_lighttoworld;
2301 R_Shadow_RenderMode_Reset();
2302 r_shadow_rendermode = r_shadow_lightingrendermode;
2303 // do global setup needed for the chosen lighting mode
2305 R_EntityMatrix(&identitymatrix);
2306 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2309 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2310 // only draw light where this geometry was already rendered AND the
2311 // stencil is 128 (values other than this mean shadow)
2312 qglStencilFunc(GL_EQUAL, 128, 255);CHECKGLERROR
2314 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepasslightingfbo);CHECKGLERROR
2317 switch (r_shadow_shadowmode)
2319 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2320 r_shadow_usingshadowmap2d = true;
2322 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
2323 r_shadow_usingshadowmaprect = true;
2325 case R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE:
2326 r_shadow_usingshadowmapcube = true;
2333 // render the lighting
2334 R_SetupShader_DeferredLight(rsurface.rtlight);
2335 for (i = 0;i < 8;i++)
2336 Matrix4x4_Transform(matrix, bboxpoints[i], vertex3f + i*3);
2338 R_Mesh_VertexPointer(vertex3f, 0, 0);
2339 R_Mesh_ColorPointer(NULL, 0, 0);
2340 GL_ColorMask(1,1,1,1);
2341 GL_DepthMask(false);
2342 GL_DepthRange(0, 1);
2343 GL_PolygonOffset(0, 0);
2345 qglDepthFunc(GL_GREATER);CHECKGLERROR
2346 GL_CullFace(r_refdef.view.cullface_back);
2347 R_Mesh_Draw(0, 8, 0, 12, NULL, bboxelements, 0, 0);
2351 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
2354 R_Shadow_RenderMode_Reset();
2355 GL_BlendFunc(GL_ONE, GL_ONE);
2356 GL_DepthRange(0, 1);
2357 GL_DepthTest(r_showshadowvolumes.integer < 2);
2358 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
2359 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2360 GL_CullFace(GL_NONE);
2361 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
2364 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
2367 R_Shadow_RenderMode_Reset();
2368 GL_BlendFunc(GL_ONE, GL_ONE);
2369 GL_DepthRange(0, 1);
2370 GL_DepthTest(r_showlighting.integer < 2);
2371 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2374 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2378 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2379 qglStencilFunc(GL_EQUAL, 128, 255);CHECKGLERROR
2381 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2384 void R_Shadow_RenderMode_End(void)
2387 R_Shadow_RenderMode_Reset();
2388 R_Shadow_RenderMode_ActiveLight(NULL);
2390 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2391 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2394 int bboxedges[12][2] =
2413 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2415 int i, ix1, iy1, ix2, iy2;
2416 float x1, y1, x2, y2;
2418 float vertex[20][3];
2427 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2428 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2429 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2430 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2432 if (!r_shadow_scissor.integer)
2435 // if view is inside the light box, just say yes it's visible
2436 if (BoxesOverlap(r_refdef.view.origin, r_refdef.view.origin, mins, maxs))
2439 x1 = y1 = x2 = y2 = 0;
2441 // transform all corners that are infront of the nearclip plane
2442 VectorNegate(r_refdef.view.frustum[4].normal, plane4f);
2443 plane4f[3] = r_refdef.view.frustum[4].dist;
2445 for (i = 0;i < 8;i++)
2447 Vector4Set(corner[i], (i & 1) ? maxs[0] : mins[0], (i & 2) ? maxs[1] : mins[1], (i & 4) ? maxs[2] : mins[2], 1);
2448 dist[i] = DotProduct4(corner[i], plane4f);
2449 sign[i] = dist[i] > 0;
2452 VectorCopy(corner[i], vertex[numvertices]);
2456 // if some points are behind the nearclip, add clipped edge points to make
2457 // sure that the scissor boundary is complete
2458 if (numvertices > 0 && numvertices < 8)
2460 // add clipped edge points
2461 for (i = 0;i < 12;i++)
2463 j = bboxedges[i][0];
2464 k = bboxedges[i][1];
2465 if (sign[j] != sign[k])
2467 f = dist[j] / (dist[j] - dist[k]);
2468 VectorLerp(corner[j], f, corner[k], vertex[numvertices]);
2474 // if we have no points to check, the light is behind the view plane
2478 // if we have some points to transform, check what screen area is covered
2479 x1 = y1 = x2 = y2 = 0;
2481 //Con_Printf("%i vertices to transform...\n", numvertices);
2482 for (i = 0;i < numvertices;i++)
2484 VectorCopy(vertex[i], v);
2485 R_Viewport_TransformToScreen(&r_refdef.view.viewport, v, v2);
2486 //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]);
2489 if (x1 > v2[0]) x1 = v2[0];
2490 if (x2 < v2[0]) x2 = v2[0];
2491 if (y1 > v2[1]) y1 = v2[1];
2492 if (y2 < v2[1]) y2 = v2[1];
2501 // now convert the scissor rectangle to integer screen coordinates
2502 ix1 = (int)(x1 - 1.0f);
2503 iy1 = vid.height - (int)(y2 - 1.0f);
2504 ix2 = (int)(x2 + 1.0f);
2505 iy2 = vid.height - (int)(y1 + 1.0f);
2506 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
2508 // clamp it to the screen
2509 if (ix1 < r_refdef.view.viewport.x) ix1 = r_refdef.view.viewport.x;
2510 if (iy1 < r_refdef.view.viewport.y) iy1 = r_refdef.view.viewport.y;
2511 if (ix2 > r_refdef.view.viewport.x + r_refdef.view.viewport.width) ix2 = r_refdef.view.viewport.x + r_refdef.view.viewport.width;
2512 if (iy2 > r_refdef.view.viewport.y + r_refdef.view.viewport.height) iy2 = r_refdef.view.viewport.y + r_refdef.view.viewport.height;
2514 // if it is inside out, it's not visible
2515 if (ix2 <= ix1 || iy2 <= iy1)
2518 // the light area is visible, set up the scissor rectangle
2519 r_shadow_lightscissor[0] = ix1;
2520 r_shadow_lightscissor[1] = iy1;
2521 r_shadow_lightscissor[2] = ix2 - ix1;
2522 r_shadow_lightscissor[3] = iy2 - iy1;
2524 r_refdef.stats.lights_scissored++;
2528 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, int numtriangles, const int *element3i, const float *diffusecolor, const float *ambientcolor)
2530 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
2531 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
2532 float *color4f = rsurface.array_color4f + 4 * firstvertex;
2533 float dist, dot, distintensity, shadeintensity, v[3], n[3];
2534 switch (r_shadow_rendermode)
2536 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2537 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2538 if (VectorLength2(diffusecolor) > 0)
2540 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2542 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2543 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2544 if ((dot = DotProduct(n, v)) < 0)
2546 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2547 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
2550 VectorCopy(ambientcolor, color4f);
2551 if (r_refdef.fogenabled)
2554 f = RSurf_FogVertex(vertex3f);
2555 VectorScale(color4f, f, color4f);
2562 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2564 VectorCopy(ambientcolor, color4f);
2565 if (r_refdef.fogenabled)
2568 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2569 f = RSurf_FogVertex(vertex3f);
2570 VectorScale(color4f, f, color4f);
2576 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2577 if (VectorLength2(diffusecolor) > 0)
2579 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2581 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2582 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2584 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2585 if ((dot = DotProduct(n, v)) < 0)
2587 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2588 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2589 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2590 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2594 color4f[0] = ambientcolor[0] * distintensity;
2595 color4f[1] = ambientcolor[1] * distintensity;
2596 color4f[2] = ambientcolor[2] * distintensity;
2598 if (r_refdef.fogenabled)
2601 f = RSurf_FogVertex(vertex3f);
2602 VectorScale(color4f, f, color4f);
2606 VectorClear(color4f);
2612 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2614 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2615 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2617 color4f[0] = ambientcolor[0] * distintensity;
2618 color4f[1] = ambientcolor[1] * distintensity;
2619 color4f[2] = ambientcolor[2] * distintensity;
2620 if (r_refdef.fogenabled)
2623 f = RSurf_FogVertex(vertex3f);
2624 VectorScale(color4f, f, color4f);
2628 VectorClear(color4f);
2633 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2634 if (VectorLength2(diffusecolor) > 0)
2636 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2638 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2639 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2641 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2642 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2643 if ((dot = DotProduct(n, v)) < 0)
2645 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2646 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2647 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2648 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2652 color4f[0] = ambientcolor[0] * distintensity;
2653 color4f[1] = ambientcolor[1] * distintensity;
2654 color4f[2] = ambientcolor[2] * distintensity;
2656 if (r_refdef.fogenabled)
2659 f = RSurf_FogVertex(vertex3f);
2660 VectorScale(color4f, f, color4f);
2664 VectorClear(color4f);
2670 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2672 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2673 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2675 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2676 color4f[0] = ambientcolor[0] * distintensity;
2677 color4f[1] = ambientcolor[1] * distintensity;
2678 color4f[2] = ambientcolor[2] * distintensity;
2679 if (r_refdef.fogenabled)
2682 f = RSurf_FogVertex(vertex3f);
2683 VectorScale(color4f, f, color4f);
2687 VectorClear(color4f);
2697 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)
2699 // used to display how many times a surface is lit for level design purposes
2700 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2703 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)
2705 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2706 R_SetupShader_Surface(lightcolor, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT);
2707 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2709 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2711 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2712 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2714 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
2718 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
2725 int newnumtriangles;
2729 int maxtriangles = 4096;
2730 static int newelements[4096*3];
2731 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, numtriangles, element3i, diffusecolor2, ambientcolor2);
2732 for (renders = 0;renders < 4;renders++)
2737 newnumtriangles = 0;
2739 // due to low fillrate on the cards this vertex lighting path is
2740 // designed for, we manually cull all triangles that do not
2741 // contain a lit vertex
2742 // this builds batches of triangles from multiple surfaces and
2743 // renders them at once
2744 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
2746 if (VectorLength2(rsurface.array_color4f + e[0] * 4) + VectorLength2(rsurface.array_color4f + e[1] * 4) + VectorLength2(rsurface.array_color4f + e[2] * 4) >= 0.01)
2748 if (newnumtriangles)
2750 newfirstvertex = min(newfirstvertex, e[0]);
2751 newlastvertex = max(newlastvertex, e[0]);
2755 newfirstvertex = e[0];
2756 newlastvertex = e[0];
2758 newfirstvertex = min(newfirstvertex, e[1]);
2759 newlastvertex = max(newlastvertex, e[1]);
2760 newfirstvertex = min(newfirstvertex, e[2]);
2761 newlastvertex = max(newlastvertex, e[2]);
2767 if (newnumtriangles >= maxtriangles)
2769 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
2770 newnumtriangles = 0;
2776 if (newnumtriangles >= 1)
2778 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
2781 // if we couldn't find any lit triangles, exit early
2784 // now reduce the intensity for the next overbright pass
2785 // we have to clamp to 0 here incase the drivers have improper
2786 // handling of negative colors
2787 // (some old drivers even have improper handling of >1 color)
2789 for (i = 0, c = rsurface.array_color4f + 4 * firstvertex;i < numvertices;i++, c += 4)
2791 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
2793 c[0] = max(0, c[0] - 1);
2794 c[1] = max(0, c[1] - 1);
2795 c[2] = max(0, c[2] - 1);
2807 static void R_Shadow_RenderLighting_Light_Vertex(int firstvertex, int numvertices, int numtriangles, const int *element3i, const vec3_t lightcolor, float ambientscale, float diffusescale)
2809 // OpenGL 1.1 path (anything)
2810 float ambientcolorbase[3], diffusecolorbase[3];
2811 float ambientcolorpants[3], diffusecolorpants[3];
2812 float ambientcolorshirt[3], diffusecolorshirt[3];
2813 const float *surfacecolor = rsurface.texture->dlightcolor;
2814 const float *surfacepants = rsurface.colormap_pantscolor;
2815 const float *surfaceshirt = rsurface.colormap_shirtcolor;
2816 rtexture_t *basetexture = rsurface.texture->basetexture;
2817 rtexture_t *pantstexture = rsurface.texture->pantstexture;
2818 rtexture_t *shirttexture = rsurface.texture->shirttexture;
2819 qboolean dopants = pantstexture && VectorLength2(surfacepants) >= (1.0f / 1048576.0f);
2820 qboolean doshirt = shirttexture && VectorLength2(surfaceshirt) >= (1.0f / 1048576.0f);
2821 ambientscale *= 2 * r_refdef.view.colorscale;
2822 diffusescale *= 2 * r_refdef.view.colorscale;
2823 ambientcolorbase[0] = lightcolor[0] * ambientscale * surfacecolor[0];ambientcolorbase[1] = lightcolor[1] * ambientscale * surfacecolor[1];ambientcolorbase[2] = lightcolor[2] * ambientscale * surfacecolor[2];
2824 diffusecolorbase[0] = lightcolor[0] * diffusescale * surfacecolor[0];diffusecolorbase[1] = lightcolor[1] * diffusescale * surfacecolor[1];diffusecolorbase[2] = lightcolor[2] * diffusescale * surfacecolor[2];
2825 ambientcolorpants[0] = ambientcolorbase[0] * surfacepants[0];ambientcolorpants[1] = ambientcolorbase[1] * surfacepants[1];ambientcolorpants[2] = ambientcolorbase[2] * surfacepants[2];
2826 diffusecolorpants[0] = diffusecolorbase[0] * surfacepants[0];diffusecolorpants[1] = diffusecolorbase[1] * surfacepants[1];diffusecolorpants[2] = diffusecolorbase[2] * surfacepants[2];
2827 ambientcolorshirt[0] = ambientcolorbase[0] * surfaceshirt[0];ambientcolorshirt[1] = ambientcolorbase[1] * surfaceshirt[1];ambientcolorshirt[2] = ambientcolorbase[2] * surfaceshirt[2];
2828 diffusecolorshirt[0] = diffusecolorbase[0] * surfaceshirt[0];diffusecolorshirt[1] = diffusecolorbase[1] * surfaceshirt[1];diffusecolorshirt[2] = diffusecolorbase[2] * surfaceshirt[2];
2829 R_Mesh_TexBind(0, basetexture);
2830 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
2831 R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
2832 R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
2833 switch(r_shadow_rendermode)
2835 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2836 R_Mesh_TexBind(1, r_shadow_attenuation3dtexture);
2837 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
2838 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
2839 R_Mesh_TexCoordPointer(1, 3, rsurface.vertex3f, rsurface.vertex3f_bufferobject, rsurface.vertex3f_bufferoffset);
2841 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2842 R_Mesh_TexBind(2, r_shadow_attenuation2dtexture);
2843 R_Mesh_TexMatrix(2, &rsurface.entitytoattenuationz);
2844 R_Mesh_TexCombine(2, GL_MODULATE, GL_MODULATE, 1, 1);
2845 R_Mesh_TexCoordPointer(2, 3, rsurface.vertex3f, rsurface.vertex3f_bufferobject, rsurface.vertex3f_bufferoffset);
2847 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2848 R_Mesh_TexBind(1, r_shadow_attenuation2dtexture);
2849 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
2850 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
2851 R_Mesh_TexCoordPointer(1, 3, rsurface.vertex3f, rsurface.vertex3f_bufferobject, rsurface.vertex3f_bufferoffset);
2853 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2858 //R_Mesh_TexBind(0, basetexture);
2859 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorbase, ambientcolorbase);
2862 R_Mesh_TexBind(0, pantstexture);
2863 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorpants, ambientcolorpants);
2867 R_Mesh_TexBind(0, shirttexture);
2868 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorshirt, ambientcolorshirt);
2872 extern cvar_t gl_lightmaps;
2873 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)
2875 float ambientscale, diffusescale, specularscale;
2877 float lightcolor[3];
2878 VectorCopy(rsurface.rtlight->currentcolor, lightcolor);
2879 ambientscale = rsurface.rtlight->ambientscale;
2880 diffusescale = rsurface.rtlight->diffusescale;
2881 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
2882 if (!r_shadow_usenormalmap.integer)
2884 ambientscale += 1.0f * diffusescale;
2888 if ((ambientscale + diffusescale) * VectorLength2(lightcolor) + specularscale * VectorLength2(lightcolor) < (1.0f / 1048576.0f))
2890 negated = (lightcolor[0] + lightcolor[1] + lightcolor[2] < 0) && vid.support.ext_blend_subtract;
2893 VectorNegate(lightcolor, lightcolor);
2894 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
2896 RSurf_SetupDepthAndCulling();
2897 switch (r_shadow_rendermode)
2899 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2900 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2901 R_Shadow_RenderLighting_VisibleLighting(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2903 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2904 R_Shadow_RenderLighting_Light_GLSL(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolor, ambientscale, diffusescale, specularscale);
2906 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2907 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2908 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2909 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2910 R_Shadow_RenderLighting_Light_Vertex(firstvertex, numvertices, numtriangles, element3i + firsttriangle * 3, lightcolor, ambientscale, diffusescale);
2913 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2917 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
2920 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)
2922 matrix4x4_t tempmatrix = *matrix;
2923 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
2925 // if this light has been compiled before, free the associated data
2926 R_RTLight_Uncompile(rtlight);
2928 // clear it completely to avoid any lingering data
2929 memset(rtlight, 0, sizeof(*rtlight));
2931 // copy the properties
2932 rtlight->matrix_lighttoworld = tempmatrix;
2933 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
2934 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
2935 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
2936 VectorCopy(color, rtlight->color);
2937 rtlight->cubemapname[0] = 0;
2938 if (cubemapname && cubemapname[0])
2939 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
2940 rtlight->shadow = shadow;
2941 rtlight->corona = corona;
2942 rtlight->style = style;
2943 rtlight->isstatic = isstatic;
2944 rtlight->coronasizescale = coronasizescale;
2945 rtlight->ambientscale = ambientscale;
2946 rtlight->diffusescale = diffusescale;
2947 rtlight->specularscale = specularscale;
2948 rtlight->flags = flags;
2950 // compute derived data
2951 //rtlight->cullradius = rtlight->radius;
2952 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2953 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2954 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2955 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2956 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2957 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2958 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2961 // compiles rtlight geometry
2962 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2963 void R_RTLight_Compile(rtlight_t *rtlight)
2966 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
2967 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
2968 entity_render_t *ent = r_refdef.scene.worldentity;
2969 dp_model_t *model = r_refdef.scene.worldmodel;
2970 unsigned char *data;
2973 // compile the light
2974 rtlight->compiled = true;
2975 rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
2976 rtlight->static_numleafs = 0;
2977 rtlight->static_numleafpvsbytes = 0;
2978 rtlight->static_leaflist = NULL;
2979 rtlight->static_leafpvs = NULL;
2980 rtlight->static_numsurfaces = 0;
2981 rtlight->static_surfacelist = NULL;
2982 rtlight->static_shadowmap_receivers = 0x3F;
2983 rtlight->static_shadowmap_casters = 0x3F;
2984 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2985 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2986 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2987 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2988 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2989 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2991 if (model && model->GetLightInfo)
2993 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
2994 r_shadow_compilingrtlight = rtlight;
2995 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);
2996 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2997 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
2998 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
2999 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
3000 rtlight->static_numsurfaces = numsurfaces;
3001 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
3002 rtlight->static_numleafs = numleafs;
3003 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
3004 rtlight->static_numleafpvsbytes = numleafpvsbytes;
3005 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
3006 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
3007 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
3008 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
3009 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3010 if (rtlight->static_numsurfaces)
3011 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3012 if (rtlight->static_numleafs)
3013 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3014 if (rtlight->static_numleafpvsbytes)
3015 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3016 if (rtlight->static_numshadowtrispvsbytes)
3017 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3018 if (rtlight->static_numlighttrispvsbytes)
3019 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3020 switch (rtlight->shadowmode)
3022 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
3023 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
3024 case R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE:
3025 if (model->CompileShadowMap && rtlight->shadow)
3026 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3029 if (model->CompileShadowVolume && rtlight->shadow)
3030 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3033 // now we're done compiling the rtlight
3034 r_shadow_compilingrtlight = NULL;
3038 // use smallest available cullradius - box radius or light radius
3039 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3040 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3042 shadowzpasstris = 0;
3043 if (rtlight->static_meshchain_shadow_zpass)
3044 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
3045 shadowzpasstris += mesh->numtriangles;
3047 shadowzfailtris = 0;
3048 if (rtlight->static_meshchain_shadow_zfail)
3049 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
3050 shadowzfailtris += mesh->numtriangles;
3053 if (rtlight->static_numlighttrispvsbytes)
3054 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3055 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3059 if (rtlight->static_numlighttrispvsbytes)
3060 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3061 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3064 if (developer_extra.integer)
3065 Con_DPrintf("static light built: %f %f %f : %f %f %f box, %i light triangles, %i shadow triangles, %i zpass/%i zfail compiled shadow volume triangles\n", rtlight->cullmins[0], rtlight->cullmins[1], rtlight->cullmins[2], rtlight->cullmaxs[0], rtlight->cullmaxs[1], rtlight->cullmaxs[2], lighttris, shadowtris, shadowzpasstris, shadowzfailtris);
3068 void R_RTLight_Uncompile(rtlight_t *rtlight)
3070 if (rtlight->compiled)
3072 if (rtlight->static_meshchain_shadow_zpass)
3073 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
3074 rtlight->static_meshchain_shadow_zpass = NULL;
3075 if (rtlight->static_meshchain_shadow_zfail)
3076 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
3077 rtlight->static_meshchain_shadow_zfail = NULL;
3078 if (rtlight->static_meshchain_shadow_shadowmap)
3079 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
3080 rtlight->static_meshchain_shadow_shadowmap = NULL;
3081 // these allocations are grouped
3082 if (rtlight->static_surfacelist)
3083 Mem_Free(rtlight->static_surfacelist);
3084 rtlight->static_numleafs = 0;
3085 rtlight->static_numleafpvsbytes = 0;
3086 rtlight->static_leaflist = NULL;
3087 rtlight->static_leafpvs = NULL;
3088 rtlight->static_numsurfaces = 0;
3089 rtlight->static_surfacelist = NULL;
3090 rtlight->static_numshadowtrispvsbytes = 0;
3091 rtlight->static_shadowtrispvs = NULL;
3092 rtlight->static_numlighttrispvsbytes = 0;
3093 rtlight->static_lighttrispvs = NULL;
3094 rtlight->compiled = false;
3098 void R_Shadow_UncompileWorldLights(void)
3102 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3103 for (lightindex = 0;lightindex < range;lightindex++)
3105 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3108 R_RTLight_Uncompile(&light->rtlight);
3112 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3116 // reset the count of frustum planes
3117 // see rtlight->cached_frustumplanes definition for how much this array
3119 rtlight->cached_numfrustumplanes = 0;
3121 // haven't implemented a culling path for ortho rendering
3122 if (!r_refdef.view.useperspective)
3124 // check if the light is on screen and copy the 4 planes if it is
3125 for (i = 0;i < 4;i++)
3126 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3129 for (i = 0;i < 4;i++)
3130 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3135 // generate a deformed frustum that includes the light origin, this is
3136 // used to cull shadow casting surfaces that can not possibly cast a
3137 // shadow onto the visible light-receiving surfaces, which can be a
3140 // if the light origin is onscreen the result will be 4 planes exactly
3141 // if the light origin is offscreen on only one axis the result will
3142 // be exactly 5 planes (split-side case)
3143 // if the light origin is offscreen on two axes the result will be
3144 // exactly 4 planes (stretched corner case)
3145 for (i = 0;i < 4;i++)
3147 // quickly reject standard frustum planes that put the light
3148 // origin outside the frustum
3149 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3152 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3154 // if all the standard frustum planes were accepted, the light is onscreen
3155 // otherwise we need to generate some more planes below...
3156 if (rtlight->cached_numfrustumplanes < 4)
3158 // at least one of the stock frustum planes failed, so we need to
3159 // create one or two custom planes to enclose the light origin
3160 for (i = 0;i < 4;i++)
3162 // create a plane using the view origin and light origin, and a
3163 // single point from the frustum corner set
3164 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3165 VectorNormalize(plane.normal);
3166 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3167 // see if this plane is backwards and flip it if so
3168 for (j = 0;j < 4;j++)
3169 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3173 VectorNegate(plane.normal, plane.normal);
3175 // flipped plane, test again to see if it is now valid
3176 for (j = 0;j < 4;j++)
3177 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3179 // if the plane is still not valid, then it is dividing the
3180 // frustum and has to be rejected
3184 // we have created a valid plane, compute extra info
3185 PlaneClassify(&plane);
3187 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3189 // if we've found 5 frustum planes then we have constructed a
3190 // proper split-side case and do not need to keep searching for
3191 // planes to enclose the light origin
3192 if (rtlight->cached_numfrustumplanes == 5)
3200 for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
3202 plane = rtlight->cached_frustumplanes[i];
3203 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));
3208 // now add the light-space box planes if the light box is rotated, as any
3209 // caster outside the oriented light box is irrelevant (even if it passed
3210 // the worldspace light box, which is axial)
3211 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3213 for (i = 0;i < 6;i++)
3217 v[i >> 1] = (i & 1) ? -1 : 1;
3218 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3219 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3220 plane.dist = VectorNormalizeLength(plane.normal);
3221 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3222 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3228 // add the world-space reduced box planes
3229 for (i = 0;i < 6;i++)
3231 VectorClear(plane.normal);
3232 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3233 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
3234 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3243 // reduce all plane distances to tightly fit the rtlight cull box, which
3245 VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3246 VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3247 VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3248 VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3249 VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3250 VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3251 VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3252 VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3253 oldnum = rtlight->cached_numfrustumplanes;
3254 rtlight->cached_numfrustumplanes = 0;
3255 for (j = 0;j < oldnum;j++)
3257 // find the nearest point on the box to this plane
3258 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
3259 for (i = 1;i < 8;i++)
3261 dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
3262 if (bestdist > dist)
3265 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);
3266 // if the nearest point is near or behind the plane, we want this
3267 // plane, otherwise the plane is useless as it won't cull anything
3268 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
3270 PlaneClassify(&rtlight->cached_frustumplanes[j]);
3271 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
3278 void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
3282 RSurf_ActiveWorldEntity();
3284 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3287 GL_CullFace(GL_NONE);
3288 mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3289 for (;mesh;mesh = mesh->next)
3291 if (!mesh->sidetotals[r_shadow_shadowmapside])
3293 r_refdef.stats.lights_shadowtriangles += mesh->sidetotals[r_shadow_shadowmapside];
3294 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
3295 R_Mesh_Draw(0, mesh->numverts, mesh->sideoffsets[r_shadow_shadowmapside], mesh->sidetotals[r_shadow_shadowmapside], mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3299 else if (r_refdef.scene.worldentity->model)
3300 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);
3302 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3305 void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3307 qboolean zpass = false;
3310 int surfacelistindex;
3311 msurface_t *surface;
3313 RSurf_ActiveWorldEntity();
3315 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3318 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
3320 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
3321 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
3323 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
3324 for (;mesh;mesh = mesh->next)
3326 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
3327 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
3328 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
3330 // increment stencil if frontface is infront of depthbuffer
3331 GL_CullFace(r_refdef.view.cullface_back);
3332 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
3333 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3334 // decrement stencil if backface is infront of depthbuffer
3335 GL_CullFace(r_refdef.view.cullface_front);
3336 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
3338 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
3340 // decrement stencil if backface is behind depthbuffer
3341 GL_CullFace(r_refdef.view.cullface_front);
3342 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
3343 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3344 // increment stencil if frontface is behind depthbuffer
3345 GL_CullFace(r_refdef.view.cullface_back);
3346 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
3348 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3352 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh)
3354 // use the shadow trispvs calculated earlier by GetLightInfo to cull world triangles on this dynamic light
3355 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
3356 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
3358 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
3359 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
3360 if (CHECKPVSBIT(trispvs, t))
3361 shadowmarklist[numshadowmark++] = t;
3363 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);
3365 else if (numsurfaces)
3366 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);
3368 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3371 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3373 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3374 vec_t relativeshadowradius;
3375 RSurf_ActiveModelEntity(ent, false, false, false);
3376 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3377 // we need to re-init the shader for each entity because the matrix changed
3378 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3379 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3380 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3381 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3382 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3383 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3384 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3385 switch (r_shadow_rendermode)
3387 case R_SHADOW_RENDERMODE_SHADOWMAP2D:
3388 case R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE:
3389 case R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE:
3390 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
3393 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3396 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3399 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3401 // set up properties for rendering light onto this entity
3402 RSurf_ActiveModelEntity(ent, true, true, false);
3403 GL_AlphaTest(false);
3404 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3405 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3406 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3407 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3410 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
3412 if (!r_refdef.scene.worldmodel->DrawLight)
3415 // set up properties for rendering light onto this entity
3416 RSurf_ActiveWorldEntity();
3417 GL_AlphaTest(false);
3418 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3419 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3420 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3421 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3423 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
3425 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3428 void R_Shadow_DrawEntityLight(entity_render_t *ent)
3430 dp_model_t *model = ent->model;
3431 if (!model->DrawLight)
3434 R_Shadow_SetupEntityLight(ent);
3436 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3438 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3441 void R_Shadow_PrepareLight(rtlight_t *rtlight)
3445 int numleafs, numsurfaces;
3446 int *leaflist, *surfacelist;
3447 unsigned char *leafpvs;
3448 unsigned char *shadowtrispvs;
3449 unsigned char *lighttrispvs;
3450 //unsigned char *surfacesides;
3451 int numlightentities;
3452 int numlightentities_noselfshadow;
3453 int numshadowentities;
3454 int numshadowentities_noselfshadow;
3455 static entity_render_t *lightentities[MAX_EDICTS];
3456 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3457 static entity_render_t *shadowentities[MAX_EDICTS];
3458 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3460 rtlight->draw = false;
3462 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3463 // skip lights that are basically invisible (color 0 0 0)
3464 if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
3467 // loading is done before visibility checks because loading should happen
3468 // all at once at the start of a level, not when it stalls gameplay.
3469 // (especially important to benchmarks)
3471 if (rtlight->isstatic && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
3473 if (rtlight->compiled)
3474 R_RTLight_Uncompile(rtlight);
3475 R_RTLight_Compile(rtlight);
3479 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
3481 // look up the light style value at this time
3482 f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3483 VectorScale(rtlight->color, f, rtlight->currentcolor);
3485 if (rtlight->selected)
3487 f = 2 + sin(realtime * M_PI * 4.0);
3488 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3492 // if lightstyle is currently off, don't draw the light
3493 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3496 // if the light box is offscreen, skip it
3497 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3500 VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
3501 VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
3503 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3505 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3507 // compiled light, world available and can receive realtime lighting
3508 // retrieve leaf information
3509 numleafs = rtlight->static_numleafs;
3510 leaflist = rtlight->static_leaflist;
3511 leafpvs = rtlight->static_leafpvs;
3512 numsurfaces = rtlight->static_numsurfaces;
3513 surfacelist = rtlight->static_surfacelist;
3514 //surfacesides = NULL;
3515 shadowtrispvs = rtlight->static_shadowtrispvs;
3516 lighttrispvs = rtlight->static_lighttrispvs;
3518 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3520 // dynamic light, world available and can receive realtime lighting
3521 // calculate lit surfaces and leafs
3522 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);
3523 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3524 leaflist = r_shadow_buffer_leaflist;
3525 leafpvs = r_shadow_buffer_leafpvs;
3526 surfacelist = r_shadow_buffer_surfacelist;
3527 //surfacesides = r_shadow_buffer_surfacesides;
3528 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3529 lighttrispvs = r_shadow_buffer_lighttrispvs;
3530 // if the reduced leaf bounds are offscreen, skip it
3531 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3542 //surfacesides = NULL;
3543 shadowtrispvs = NULL;
3544 lighttrispvs = NULL;
3546 // check if light is illuminating any visible leafs
3549 for (i = 0;i < numleafs;i++)
3550 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3556 // make a list of lit entities and shadow casting entities
3557 numlightentities = 0;
3558 numlightentities_noselfshadow = 0;
3559 numshadowentities = 0;
3560 numshadowentities_noselfshadow = 0;
3562 // add dynamic entities that are lit by the light
3563 for (i = 0;i < r_refdef.scene.numentities;i++)
3566 entity_render_t *ent = r_refdef.scene.entities[i];
3568 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3570 // skip the object entirely if it is not within the valid
3571 // shadow-casting region (which includes the lit region)
3572 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
3574 if (!(model = ent->model))
3576 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
3578 // this entity wants to receive light, is visible, and is
3579 // inside the light box
3580 // TODO: check if the surfaces in the model can receive light
3581 // so now check if it's in a leaf seen by the light
3582 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))
3584 if (ent->flags & RENDER_NOSELFSHADOW)
3585 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
3587 lightentities[numlightentities++] = ent;
3588 // since it is lit, it probably also casts a shadow...
3589 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3590 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3591 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3593 // note: exterior models without the RENDER_NOSELFSHADOW
3594 // flag still create a RENDER_NOSELFSHADOW shadow but
3595 // are lit normally, this means that they are
3596 // self-shadowing but do not shadow other
3597 // RENDER_NOSELFSHADOW entities such as the gun
3598 // (very weird, but keeps the player shadow off the gun)
3599 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3600 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3602 shadowentities[numshadowentities++] = ent;
3605 else if (ent->flags & RENDER_SHADOW)
3607 // this entity is not receiving light, but may still need to
3609 // TODO: check if the surfaces in the model can cast shadow
3610 // now check if it is in a leaf seen by the light
3611 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))
3613 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3614 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3615 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3617 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3618 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3620 shadowentities[numshadowentities++] = ent;
3625 // return if there's nothing at all to light
3626 if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
3629 // count this light in the r_speeds
3630 r_refdef.stats.lights++;
3632 // flag it as worth drawing later
3633 rtlight->draw = true;
3635 // cache all the animated entities that cast a shadow but are not visible
3636 for (i = 0;i < numshadowentities;i++)
3637 if (!shadowentities[i]->animcache_vertex3f)
3638 R_AnimCache_GetEntity(shadowentities[i], false, false);
3639 for (i = 0;i < numshadowentities_noselfshadow;i++)
3640 if (!shadowentities_noselfshadow[i]->animcache_vertex3f)
3641 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
3643 // allocate some temporary memory for rendering this light later in the frame
3644 // reusable buffers need to be copied, static data can be used as-is
3645 rtlight->cached_numlightentities = numlightentities;
3646 rtlight->cached_numlightentities_noselfshadow = numlightentities_noselfshadow;
3647 rtlight->cached_numshadowentities = numshadowentities;
3648 rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
3649 rtlight->cached_numsurfaces = numsurfaces;
3650 rtlight->cached_lightentities = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
3651 rtlight->cached_lightentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
3652 rtlight->cached_shadowentities = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
3653 rtlight->cached_shadowentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
3654 if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
3656 int numshadowtrispvsbytes = (((r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles) + 7) >> 3);
3657 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
3658 rtlight->cached_shadowtrispvs = (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
3659 rtlight->cached_lighttrispvs = (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
3660 rtlight->cached_surfacelist = (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
3664 // compiled light data
3665 rtlight->cached_shadowtrispvs = shadowtrispvs;
3666 rtlight->cached_lighttrispvs = lighttrispvs;
3667 rtlight->cached_surfacelist = surfacelist;
3671 void R_Shadow_DrawLight(rtlight_t *rtlight)
3675 unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
3676 int numlightentities;
3677 int numlightentities_noselfshadow;
3678 int numshadowentities;
3679 int numshadowentities_noselfshadow;
3680 entity_render_t **lightentities;
3681 entity_render_t **lightentities_noselfshadow;
3682 entity_render_t **shadowentities;
3683 entity_render_t **shadowentities_noselfshadow;
3685 static unsigned char entitysides[MAX_EDICTS];
3686 static unsigned char entitysides_noselfshadow[MAX_EDICTS];
3687 vec3_t nearestpoint;
3689 qboolean castshadows;
3692 // check if we cached this light this frame (meaning it is worth drawing)
3696 // if R_FrameData_Store ran out of space we skip anything dependent on it
3697 if (r_framedata_failed)
3700 numlightentities = rtlight->cached_numlightentities;
3701 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
3702 numshadowentities = rtlight->cached_numshadowentities;
3703 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
3704 numsurfaces = rtlight->cached_numsurfaces;
3705 lightentities = rtlight->cached_lightentities;
3706 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
3707 shadowentities = rtlight->cached_shadowentities;
3708 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
3709 shadowtrispvs = rtlight->cached_shadowtrispvs;
3710 lighttrispvs = rtlight->cached_lighttrispvs;
3711 surfacelist = rtlight->cached_surfacelist;
3713 // set up a scissor rectangle for this light
3714 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3717 // don't let sound skip if going slow
3718 if (r_refdef.scene.extraupdate)
3721 // make this the active rtlight for rendering purposes
3722 R_Shadow_RenderMode_ActiveLight(rtlight);
3724 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
3726 // optionally draw visible shape of the shadow volumes
3727 // for performance analysis by level designers
3728 R_Shadow_RenderMode_VisibleShadowVolumes();
3730 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
3731 for (i = 0;i < numshadowentities;i++)
3732 R_Shadow_DrawEntityShadow(shadowentities[i]);
3733 for (i = 0;i < numshadowentities_noselfshadow;i++)
3734 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3735 R_Shadow_RenderMode_VisibleLighting(false, false);
3738 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
3740 // optionally draw the illuminated areas
3741 // for performance analysis by level designers
3742 R_Shadow_RenderMode_VisibleLighting(false, false);
3744 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3745 for (i = 0;i < numlightentities;i++)
3746 R_Shadow_DrawEntityLight(lightentities[i]);
3747 for (i = 0;i < numlightentities_noselfshadow;i++)
3748 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3751 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
3753 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
3754 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
3755 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
3756 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
3758 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance/rtlight->radius));
3759 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
3760 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
3762 if (castshadows && (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE))
3768 int receivermask = 0;
3769 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
3770 Matrix4x4_Abs(&radiustolight);
3772 r_shadow_shadowmaplod = 0;
3773 for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
3774 if ((r_shadow_shadowmapmaxsize >> i) > lodlinear)
3775 r_shadow_shadowmaplod = i;
3777 if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
3778 size = max(1, r_shadow_shadowmapmaxsize >> r_shadow_shadowmaplod);
3780 size = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
3782 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
3784 surfacesides = NULL;
3787 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3789 castermask = rtlight->static_shadowmap_casters;
3790 receivermask = rtlight->static_shadowmap_receivers;
3794 surfacesides = r_shadow_buffer_surfacesides;
3795 for(i = 0;i < numsurfaces;i++)
3797 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
3798 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3799 castermask |= surfacesides[i];
3800 receivermask |= surfacesides[i];
3804 if (receivermask < 0x3F)
3806 for (i = 0;i < numlightentities;i++)
3807 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3808 if (receivermask < 0x3F)
3809 for(i = 0; i < numlightentities_noselfshadow;i++)
3810 receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3813 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
3817 for (i = 0;i < numshadowentities;i++)
3818 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3819 for (i = 0;i < numshadowentities_noselfshadow;i++)
3820 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3823 //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
3825 // render shadow casters into 6 sided depth texture
3826 for (side = 0;side < 6;side++) if (receivermask & (1 << side))
3828 R_Shadow_RenderMode_ShadowMap(side, receivermask, size);
3829 if (! (castermask & (1 << side))) continue;
3831 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
3832 for (i = 0;i < numshadowentities;i++) if (entitysides[i] & (1 << side))
3833 R_Shadow_DrawEntityShadow(shadowentities[i]);
3836 if (numlightentities_noselfshadow)
3838 // render lighting using the depth texture as shadowmap
3839 // draw lighting in the unmasked areas
3840 R_Shadow_RenderMode_Lighting(false, false, true);
3841 for (i = 0;i < numlightentities_noselfshadow;i++)
3842 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3845 // render shadow casters into 6 sided depth texture
3846 if (numshadowentities_noselfshadow)
3848 for (side = 0;side < 6;side++) if ((receivermask & castermask) & (1 << side))
3850 R_Shadow_RenderMode_ShadowMap(side, 0, size);
3851 for (i = 0;i < numshadowentities_noselfshadow;i++) if (entitysides_noselfshadow[i] & (1 << side))
3852 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3856 // render lighting using the depth texture as shadowmap
3857 // draw lighting in the unmasked areas
3858 R_Shadow_RenderMode_Lighting(false, false, true);
3859 // draw lighting in the unmasked areas
3861 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3862 for (i = 0;i < numlightentities;i++)
3863 R_Shadow_DrawEntityLight(lightentities[i]);
3865 else if (castshadows && vid.stencil)
3867 // draw stencil shadow volumes to mask off pixels that are in shadow
3868 // so that they won't receive lighting
3869 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
3870 R_Shadow_ClearStencil();
3873 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
3874 for (i = 0;i < numshadowentities;i++)
3875 R_Shadow_DrawEntityShadow(shadowentities[i]);
3877 // draw lighting in the unmasked areas
3878 R_Shadow_RenderMode_Lighting(true, false, false);
3879 for (i = 0;i < numlightentities_noselfshadow;i++)
3880 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3882 for (i = 0;i < numshadowentities_noselfshadow;i++)
3883 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3885 // draw lighting in the unmasked areas
3886 R_Shadow_RenderMode_Lighting(true, false, false);
3888 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3889 for (i = 0;i < numlightentities;i++)
3890 R_Shadow_DrawEntityLight(lightentities[i]);
3894 // draw lighting in the unmasked areas
3895 R_Shadow_RenderMode_Lighting(false, false, false);
3897 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3898 for (i = 0;i < numlightentities;i++)
3899 R_Shadow_DrawEntityLight(lightentities[i]);
3900 for (i = 0;i < numlightentities_noselfshadow;i++)
3901 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3904 if (r_shadow_usingdeferredprepass)
3906 // when rendering deferred lighting, we simply rasterize the box
3907 if (castshadows && (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE))
3908 R_Shadow_RenderMode_DrawDeferredLight(false, true);
3909 else if (castshadows && vid.stencil)
3910 R_Shadow_RenderMode_DrawDeferredLight(true, false);
3912 R_Shadow_RenderMode_DrawDeferredLight(false, false);
3916 static void R_Shadow_FreeDeferred(void)
3918 if (r_shadow_prepassgeometryfbo)
3919 qglDeleteFramebuffersEXT(1, &r_shadow_prepassgeometryfbo);CHECKGLERROR
3920 r_shadow_prepassgeometryfbo = 0;
3922 if (r_shadow_prepasslightingfbo)
3923 qglDeleteFramebuffersEXT(1, &r_shadow_prepasslightingfbo);CHECKGLERROR
3924 r_shadow_prepasslightingfbo = 0;
3926 if (r_shadow_prepassgeometrydepthtexture)
3927 R_FreeTexture(r_shadow_prepassgeometrydepthtexture);
3928 r_shadow_prepassgeometrydepthtexture = NULL;
3930 if (r_shadow_prepassgeometrynormalmaptexture)
3931 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
3932 r_shadow_prepassgeometrynormalmaptexture = NULL;
3934 if (r_shadow_prepasslightingdiffusetexture)
3935 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
3936 r_shadow_prepasslightingdiffusetexture = NULL;
3938 if (r_shadow_prepasslightingspeculartexture)
3939 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
3940 r_shadow_prepasslightingspeculartexture = NULL;
3943 void R_Shadow_DrawPrepass(void)
3951 entity_render_t *ent;
3953 GL_AlphaTest(false);
3954 R_Mesh_ColorPointer(NULL, 0, 0);
3955 R_Mesh_ResetTextureState();
3957 GL_ColorMask(1,1,1,1);
3958 GL_BlendFunc(GL_ONE, GL_ZERO);
3961 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepassgeometryfbo);CHECKGLERROR
3962 qglClearColor(0.5f,0.5f,0.5f,1.0f);CHECKGLERROR
3963 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);CHECKGLERROR
3965 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
3966 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
3967 if (r_timereport_active)
3968 R_TimeReport("prepassworld");
3970 for (i = 0;i < r_refdef.scene.numentities;i++)
3972 if (!r_refdef.viewcache.entityvisible[i])
3974 ent = r_refdef.scene.entities[i];
3975 if (ent->model && ent->model->DrawPrepass != NULL)
3976 ent->model->DrawPrepass(ent);
3979 if (r_timereport_active)
3980 R_TimeReport("prepassmodels");
3982 GL_DepthMask(false);
3983 GL_ColorMask(1,1,1,1);
3986 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepasslightingfbo);CHECKGLERROR
3987 qglClearColor(0.0f,0.0f,0.0f,0.0f);CHECKGLERROR
3988 GL_Clear(GL_COLOR_BUFFER_BIT);CHECKGLERROR
3989 if (r_refdef.fogenabled)
3990 qglClearColor(r_refdef.fogcolor[0],r_refdef.fogcolor[1],r_refdef.fogcolor[2],0);CHECKGLERROR
3992 R_Shadow_RenderMode_Begin();
3994 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3995 if (r_shadow_debuglight.integer >= 0)
3997 lightindex = r_shadow_debuglight.integer;
3998 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3999 if (light && (light->flags & flag))
4000 R_Shadow_DrawLight(&light->rtlight);
4004 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4005 for (lightindex = 0;lightindex < range;lightindex++)
4007 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4008 if (light && (light->flags & flag))
4009 R_Shadow_DrawLight(&light->rtlight);
4012 if (r_refdef.scene.rtdlight)
4013 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4014 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4016 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);CHECKGLERROR
4017 if (r_refdef.fogenabled)
4018 qglClearColor(r_refdef.fogcolor[0],r_refdef.fogcolor[1],r_refdef.fogcolor[2],0);CHECKGLERROR
4020 R_Shadow_RenderMode_End();
4022 if (r_timereport_active)
4023 R_TimeReport("prepasslights");
4026 void R_Shadow_DrawLightSprites(void);
4027 void R_Shadow_PrepareLights(void)
4037 if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4) ||
4038 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
4039 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0) ||
4040 r_shadow_shadowmaptexturetype != r_shadow_shadowmapping_texturetype.integer ||
4041 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
4042 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
4043 r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
4044 R_Shadow_FreeShadowMaps();
4046 r_shadow_usingshadowmaportho = false;
4048 switch (vid.renderpath)
4050 case RENDERPATH_GL20:
4051 case RENDERPATH_CGGL:
4052 if (!r_shadow_deferred.integer || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_STENCIL || !vid.support.ext_framebuffer_object || vid.maxdrawbuffers < 2)
4054 r_shadow_usingdeferredprepass = false;
4055 if (r_shadow_prepass_width)
4056 R_Shadow_FreeDeferred();
4057 r_shadow_prepass_width = r_shadow_prepass_height = 0;
4061 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
4063 R_Shadow_FreeDeferred();
4065 r_shadow_usingdeferredprepass = true;
4066 r_shadow_prepass_width = vid.width;
4067 r_shadow_prepass_height = vid.height;
4068 r_shadow_prepassgeometrydepthtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "prepassgeometrydepthmap", vid.width, vid.height, 24, false);
4069 r_shadow_prepassgeometrynormalmaptexture = R_LoadTexture2D(r_shadow_texturepool, "prepassgeometrynormalmap", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, NULL);
4070 r_shadow_prepasslightingdiffusetexture = R_LoadTexture2D(r_shadow_texturepool, "prepasslightingdiffuse", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, NULL);
4071 r_shadow_prepasslightingspeculartexture = R_LoadTexture2D(r_shadow_texturepool, "prepasslightingspecular", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, NULL);
4073 // set up the geometry pass fbo (depth + normalmap)
4074 qglGenFramebuffersEXT(1, &r_shadow_prepassgeometryfbo);CHECKGLERROR
4075 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepassgeometryfbo);CHECKGLERROR
4076 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_prepassgeometrydepthtexture), 0);CHECKGLERROR
4077 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_prepassgeometrynormalmaptexture), 0);CHECKGLERROR
4078 // render depth into one texture and normalmap into the other
4079 if (qglDrawBuffersARB)
4081 qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);CHECKGLERROR
4082 qglReadBuffer(GL_NONE);CHECKGLERROR
4084 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4085 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4087 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4088 Cvar_SetValueQuick(&r_shadow_deferred, 0);
4089 r_shadow_usingdeferredprepass = false;
4092 // set up the lighting pass fbo (diffuse + specular)
4093 qglGenFramebuffersEXT(1, &r_shadow_prepasslightingfbo);CHECKGLERROR
4094 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepasslightingfbo);CHECKGLERROR
4095 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_prepassgeometrydepthtexture), 0);CHECKGLERROR
4096 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_prepasslightingdiffusetexture), 0);CHECKGLERROR
4097 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_prepasslightingspeculartexture), 0);CHECKGLERROR
4098 // render diffuse into one texture and specular into another,
4099 // with depth and normalmap bound as textures,
4100 // with depth bound as attachment as well
4101 if (qglDrawBuffersARB)
4103 qglDrawBuffersARB(2, r_shadow_prepasslightingdrawbuffers);CHECKGLERROR
4104 qglReadBuffer(GL_NONE);CHECKGLERROR
4106 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4107 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4109 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4110 Cvar_SetValueQuick(&r_shadow_deferred, 0);
4111 r_shadow_usingdeferredprepass = false;
4115 case RENDERPATH_GL13:
4116 case RENDERPATH_GL11:
4117 r_shadow_usingdeferredprepass = false;
4121 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);
4123 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4124 if (r_shadow_debuglight.integer >= 0)
4126 lightindex = r_shadow_debuglight.integer;
4127 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4128 if (light && (light->flags & flag))
4129 R_Shadow_PrepareLight(&light->rtlight);
4133 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4134 for (lightindex = 0;lightindex < range;lightindex++)
4136 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4137 if (light && (light->flags & flag))
4138 R_Shadow_PrepareLight(&light->rtlight);
4141 if (r_refdef.scene.rtdlight)
4143 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4144 R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
4146 else if(gl_flashblend.integer)
4148 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4150 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
4151 f = (rtlight->style >= 0 ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4152 VectorScale(rtlight->color, f, rtlight->currentcolor);
4156 if (r_editlights.integer)
4157 R_Shadow_DrawLightSprites();
4160 void R_Shadow_DrawLights(void)
4168 R_Shadow_RenderMode_Begin();
4170 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4171 if (r_shadow_debuglight.integer >= 0)
4173 lightindex = r_shadow_debuglight.integer;
4174 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4175 if (light && (light->flags & flag))
4176 R_Shadow_DrawLight(&light->rtlight);
4180 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4181 for (lightindex = 0;lightindex < range;lightindex++)
4183 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4184 if (light && (light->flags & flag))
4185 R_Shadow_DrawLight(&light->rtlight);
4188 if (r_refdef.scene.rtdlight)
4189 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4190 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4192 R_Shadow_RenderMode_End();
4195 extern const float r_screenvertex3f[12];
4196 extern void R_SetupView(qboolean allowwaterclippingplane);
4197 extern void R_ResetViewRendering3D(void);
4198 extern void R_ResetViewRendering2D(void);
4199 extern cvar_t r_shadows;
4200 extern cvar_t r_shadows_darken;
4201 extern cvar_t r_shadows_drawafterrtlighting;
4202 extern cvar_t r_shadows_castfrombmodels;
4203 extern cvar_t r_shadows_throwdistance;
4204 extern cvar_t r_shadows_throwdirection;
4205 extern cvar_t r_shadows_focus;
4207 void R_Shadow_PrepareModelShadows(void)
4210 float scale, size, radius, dot1, dot2;
4211 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
4212 entity_render_t *ent;
4214 if (!r_refdef.scene.numentities)
4217 switch (r_shadow_shadowmode)
4219 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4220 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
4222 case R_SHADOW_SHADOWMODE_STENCIL:
4223 for (i = 0;i < r_refdef.scene.numentities;i++)
4225 ent = r_refdef.scene.entities[i];
4226 if (!ent->animcache_vertex3f && ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4227 R_AnimCache_GetEntity(ent, false, false);
4234 size = 2*r_shadow_shadowmapmaxsize;
4235 scale = r_shadow_shadowmapping_precision.value;
4236 radius = 0.5f * size / scale;
4238 Math_atov(r_shadows_throwdirection.string, shadowdir);
4239 VectorNormalize(shadowdir);
4240 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4241 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4242 if (fabs(dot1) <= fabs(dot2))
4243 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4245 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4246 VectorNormalize(shadowforward);
4247 CrossProduct(shadowdir, shadowforward, shadowright);
4248 Math_atov(r_shadows_focus.string, shadowfocus);
4249 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4250 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4251 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4252 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4253 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4255 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4257 shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4258 shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4259 shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4260 shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4261 shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4262 shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4264 for (i = 0;i < r_refdef.scene.numentities;i++)
4266 ent = r_refdef.scene.entities[i];
4267 if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
4269 // cast shadows from anything of the map (submodels are optional)
4270 if (!ent->animcache_vertex3f && ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4271 R_AnimCache_GetEntity(ent, false, false);
4275 void R_DrawModelShadowMaps(void)
4278 float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
4279 entity_render_t *ent;
4280 vec3_t relativelightorigin;
4281 vec3_t relativelightdirection, relativeforward, relativeright;
4282 vec3_t relativeshadowmins, relativeshadowmaxs;
4283 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
4285 matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
4286 r_viewport_t viewport;
4289 if (!r_refdef.scene.numentities)
4292 switch (r_shadow_shadowmode)
4294 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4295 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
4302 R_ResetViewRendering3D();
4303 R_Shadow_RenderMode_Begin();
4304 R_Shadow_RenderMode_ActiveLight(NULL);
4306 switch (r_shadow_shadowmode)
4308 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4309 if (!r_shadow_shadowmap2dtexture)
4310 R_Shadow_MakeShadowMap(0, r_shadow_shadowmapmaxsize);
4311 fbo = r_shadow_fbo2d;
4312 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
4313 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
4314 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
4316 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
4317 if (!r_shadow_shadowmaprectangletexture)
4318 R_Shadow_MakeShadowMap(0, r_shadow_shadowmapmaxsize);
4319 fbo = r_shadow_fborectangle;
4320 r_shadow_shadowmap_texturescale[0] = 1.0f;
4321 r_shadow_shadowmap_texturescale[1] = 1.0f;
4322 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE;
4328 size = 2*r_shadow_shadowmapmaxsize;
4329 scale = r_shadow_shadowmapping_precision.value / size;
4330 radius = 0.5f / scale;
4331 nearclip = -r_shadows_throwdistance.value;
4332 farclip = r_shadows_throwdistance.value;
4333 bias = r_shadow_shadowmapping_bias.value * r_shadow_shadowmapping_nearclip.value / (2 * r_shadows_throwdistance.value) * (1024.0f / size);
4335 r_shadow_shadowmap_parameters[0] = size;
4336 r_shadow_shadowmap_parameters[1] = size;
4337 r_shadow_shadowmap_parameters[2] = 1.0;
4338 r_shadow_shadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
4340 Math_atov(r_shadows_throwdirection.string, shadowdir);
4341 VectorNormalize(shadowdir);
4342 Math_atov(r_shadows_focus.string, shadowfocus);
4343 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4344 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4345 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4346 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4347 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4348 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4349 if (fabs(dot1) <= fabs(dot2))
4350 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4352 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4353 VectorNormalize(shadowforward);
4354 VectorM(scale, shadowforward, &m[0]);
4355 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4357 m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
4358 CrossProduct(shadowdir, shadowforward, shadowright);
4359 VectorM(scale, shadowright, &m[4]);
4360 m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
4361 VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
4362 m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
4363 Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
4364 Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
4365 R_Viewport_InitOrtho(&viewport, &cameramatrix, 0, 0, size, size, 0, 0, 1, 1, 0, -1, NULL);
4367 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4370 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);CHECKGLERROR
4371 R_SetupShader_ShowDepth();
4373 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);CHECKGLERROR
4374 R_SetupShader_DepthOrShadow();
4377 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
4380 R_SetViewport(&viewport);
4381 GL_Scissor(viewport.x, viewport.y, min(viewport.width + r_shadow_shadowmapborder, 2*r_shadow_shadowmapmaxsize), viewport.height + r_shadow_shadowmapborder);
4384 qglClearColor(1,1,1,1);
4385 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
4387 GL_Clear(GL_DEPTH_BUFFER_BIT);
4389 GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
4392 for (i = 0;i < r_refdef.scene.numentities;i++)
4394 ent = r_refdef.scene.entities[i];
4396 // cast shadows from anything of the map (submodels are optional)
4397 if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4399 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4400 Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
4401 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4402 Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
4403 Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
4404 relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4405 relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4406 relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4407 relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4408 relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4409 relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4410 RSurf_ActiveModelEntity(ent, false, false, false);
4411 ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
4412 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4416 R_Shadow_RenderMode_End();
4418 Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
4419 Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
4420 Matrix4x4_CreateScale3(&scalematrix, size, -size, 1);
4421 Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
4422 Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
4423 Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
4425 r_shadow_usingshadowmaportho = true;
4426 switch (r_shadow_shadowmode)
4428 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4429 r_shadow_usingshadowmap2d = true;
4431 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
4432 r_shadow_usingshadowmaprect = true;
4439 void R_DrawModelShadows(void)
4442 float relativethrowdistance;
4443 entity_render_t *ent;
4444 vec3_t relativelightorigin;
4445 vec3_t relativelightdirection;
4446 vec3_t relativeshadowmins, relativeshadowmaxs;
4447 vec3_t tmp, shadowdir;
4449 if (!r_refdef.scene.numentities || !vid.stencil || r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL)
4453 R_ResetViewRendering3D();
4454 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4455 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4456 R_Shadow_RenderMode_Begin();
4457 R_Shadow_RenderMode_ActiveLight(NULL);
4458 r_shadow_lightscissor[0] = r_refdef.view.x;
4459 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
4460 r_shadow_lightscissor[2] = r_refdef.view.width;
4461 r_shadow_lightscissor[3] = r_refdef.view.height;
4462 R_Shadow_RenderMode_StencilShadowVolumes(false);
4465 if (r_shadows.integer == 2)
4467 Math_atov(r_shadows_throwdirection.string, shadowdir);
4468 VectorNormalize(shadowdir);
4471 R_Shadow_ClearStencil();
4473 for (i = 0;i < r_refdef.scene.numentities;i++)
4475 ent = r_refdef.scene.entities[i];
4477 // cast shadows from anything of the map (submodels are optional)
4478 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4480 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4481 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
4482 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
4483 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
4484 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4487 if(ent->entitynumber != 0)
4489 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
4490 int entnum, entnum2, recursion;
4491 entnum = entnum2 = ent->entitynumber;
4492 for(recursion = 32; recursion > 0; --recursion)
4494 entnum2 = cl.entities[entnum].state_current.tagentity;
4495 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
4500 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
4502 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
4503 // transform into modelspace of OUR entity
4504 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
4505 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
4508 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4511 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4514 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
4515 RSurf_ActiveModelEntity(ent, false, false, false);
4516 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4517 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4521 // not really the right mode, but this will disable any silly stencil features
4522 R_Shadow_RenderMode_End();
4524 // set up ortho view for rendering this pass
4525 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4526 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4527 //GL_ScissorTest(true);
4528 //R_EntityMatrix(&identitymatrix);
4529 //R_Mesh_ResetTextureState();
4530 R_ResetViewRendering2D();
4531 R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
4532 R_Mesh_ColorPointer(NULL, 0, 0);
4533 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
4535 // set up a darkening blend on shadowed areas
4536 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4537 //GL_DepthRange(0, 1);
4538 //GL_DepthTest(false);
4539 //GL_DepthMask(false);
4540 //GL_PolygonOffset(0, 0);CHECKGLERROR
4541 GL_Color(0, 0, 0, r_shadows_darken.value);
4542 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4543 //qglDepthFunc(GL_ALWAYS);CHECKGLERROR
4544 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
4545 qglStencilMask(255);CHECKGLERROR
4546 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
4547 qglStencilFunc(GL_NOTEQUAL, 128, 255);CHECKGLERROR
4549 // apply the blend to the shadowed areas
4550 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
4552 // restore the viewport
4553 R_SetViewport(&r_refdef.view.viewport);
4555 // restore other state to normal
4556 //R_Shadow_RenderMode_End();
4559 void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4562 vec3_t centerorigin;
4564 // if it's too close, skip it
4565 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
4567 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4570 if (usequery && r_numqueries + 2 <= r_maxqueries)
4572 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4573 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4574 // 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
4575 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4578 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use qglDepthFunc instead
4579 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
4580 qglDepthFunc(GL_ALWAYS);
4581 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4582 R_Mesh_VertexPointer(vertex3f, 0, 0);
4583 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
4584 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4585 qglDepthFunc(GL_LEQUAL);
4586 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
4587 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4588 R_Mesh_VertexPointer(vertex3f, 0, 0);
4589 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
4590 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4593 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4596 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
4598 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4601 GLint allpixels = 0, visiblepixels = 0;
4602 // now we have to check the query result
4603 if (rtlight->corona_queryindex_visiblepixels)
4606 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
4607 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
4609 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
4610 if (visiblepixels < 1 || allpixels < 1)
4612 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
4613 cscale *= rtlight->corona_visibility;
4617 // FIXME: these traces should scan all render entities instead of cl.world
4618 if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
4621 VectorScale(rtlight->currentcolor, cscale, color);
4622 if (VectorLength(color) > (1.0f / 256.0f))
4625 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
4628 VectorNegate(color, color);
4629 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
4631 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4632 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);
4633 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4635 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
4639 void R_Shadow_DrawCoronas(void)
4647 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4649 if (r_waterstate.renderingscene)
4651 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4652 R_EntityMatrix(&identitymatrix);
4654 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4656 // check occlusion of coronas
4657 // use GL_ARB_occlusion_query if available
4658 // otherwise use raytraces
4660 usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
4663 GL_ColorMask(0,0,0,0);
4664 if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
4665 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
4668 r_maxqueries = (range + r_refdef.scene.numlights) * 4;
4669 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
4671 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
4674 RSurf_ActiveWorldEntity();
4675 GL_BlendFunc(GL_ONE, GL_ZERO);
4676 GL_CullFace(GL_NONE);
4677 GL_DepthMask(false);
4678 GL_DepthRange(0, 1);
4679 GL_PolygonOffset(0, 0);
4681 R_Mesh_ColorPointer(NULL, 0, 0);
4682 R_Mesh_ResetTextureState();
4683 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
4685 for (lightindex = 0;lightindex < range;lightindex++)
4687 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4690 rtlight = &light->rtlight;
4691 rtlight->corona_visibility = 0;
4692 rtlight->corona_queryindex_visiblepixels = 0;
4693 rtlight->corona_queryindex_allpixels = 0;
4694 if (!(rtlight->flags & flag))
4696 if (rtlight->corona <= 0)
4698 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4700 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4702 for (i = 0;i < r_refdef.scene.numlights;i++)
4704 rtlight = r_refdef.scene.lights[i];
4705 rtlight->corona_visibility = 0;
4706 rtlight->corona_queryindex_visiblepixels = 0;
4707 rtlight->corona_queryindex_allpixels = 0;
4708 if (!(rtlight->flags & flag))
4710 if (rtlight->corona <= 0)
4712 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4715 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4717 // now draw the coronas using the query data for intensity info
4718 for (lightindex = 0;lightindex < range;lightindex++)
4720 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4723 rtlight = &light->rtlight;
4724 if (rtlight->corona_visibility <= 0)
4726 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4728 for (i = 0;i < r_refdef.scene.numlights;i++)
4730 rtlight = r_refdef.scene.lights[i];
4731 if (rtlight->corona_visibility <= 0)
4733 if (gl_flashblend.integer)
4734 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4736 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4742 dlight_t *R_Shadow_NewWorldLight(void)
4744 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4747 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)
4750 // validate parameters
4751 if (style < 0 || style >= MAX_LIGHTSTYLES)
4753 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
4759 // copy to light properties
4760 VectorCopy(origin, light->origin);
4761 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4762 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4763 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4765 light->color[0] = max(color[0], 0);
4766 light->color[1] = max(color[1], 0);
4767 light->color[2] = max(color[2], 0);
4769 light->color[0] = color[0];
4770 light->color[1] = color[1];
4771 light->color[2] = color[2];
4772 light->radius = max(radius, 0);
4773 light->style = style;
4774 light->shadow = shadowenable;
4775 light->corona = corona;
4776 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4777 light->coronasizescale = coronasizescale;
4778 light->ambientscale = ambientscale;
4779 light->diffusescale = diffusescale;
4780 light->specularscale = specularscale;
4781 light->flags = flags;
4783 // update renderable light data
4784 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4785 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);
4788 void R_Shadow_FreeWorldLight(dlight_t *light)
4790 if (r_shadow_selectedlight == light)
4791 r_shadow_selectedlight = NULL;
4792 R_RTLight_Uncompile(&light->rtlight);
4793 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4796 void R_Shadow_ClearWorldLights(void)
4800 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4801 for (lightindex = 0;lightindex < range;lightindex++)
4803 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4805 R_Shadow_FreeWorldLight(light);
4807 r_shadow_selectedlight = NULL;
4810 void R_Shadow_SelectLight(dlight_t *light)
4812 if (r_shadow_selectedlight)
4813 r_shadow_selectedlight->selected = false;
4814 r_shadow_selectedlight = light;
4815 if (r_shadow_selectedlight)
4816 r_shadow_selectedlight->selected = true;
4819 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4821 // this is never batched (there can be only one)
4823 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
4824 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4825 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4828 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4833 skinframe_t *skinframe;
4836 // this is never batched (due to the ent parameter changing every time)
4837 // so numsurfaces == 1 and surfacelist[0] == lightnumber
4838 const dlight_t *light = (dlight_t *)ent;
4841 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
4844 VectorScale(light->color, intensity, spritecolor);
4845 if (VectorLength(spritecolor) < 0.1732f)
4846 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
4847 if (VectorLength(spritecolor) > 1.0f)
4848 VectorNormalize(spritecolor);
4850 // draw light sprite
4851 if (light->cubemapname[0] && !light->shadow)
4852 skinframe = r_editlights_sprcubemapnoshadowlight;
4853 else if (light->cubemapname[0])
4854 skinframe = r_editlights_sprcubemaplight;
4855 else if (!light->shadow)
4856 skinframe = r_editlights_sprnoshadowlight;
4858 skinframe = r_editlights_sprlight;
4860 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);
4861 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4863 // draw selection sprite if light is selected
4864 if (light->selected)
4866 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4867 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4868 // VorteX todo: add normalmode/realtime mode light overlay sprites?
4872 void R_Shadow_DrawLightSprites(void)
4876 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4877 for (lightindex = 0;lightindex < range;lightindex++)
4879 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4881 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
4883 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
4886 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
4891 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
4892 if (lightindex >= range)
4894 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4897 rtlight = &light->rtlight;
4898 //if (!(rtlight->flags & flag))
4900 VectorCopy(rtlight->shadoworigin, origin);
4901 *radius = rtlight->radius;
4902 VectorCopy(rtlight->color, color);
4906 void R_Shadow_SelectLightInView(void)
4908 float bestrating, rating, temp[3];
4912 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4915 for (lightindex = 0;lightindex < range;lightindex++)
4917 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4920 VectorSubtract(light->origin, r_refdef.view.origin, temp);
4921 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
4924 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
4925 if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1.0f)
4927 bestrating = rating;
4932 R_Shadow_SelectLight(best);
4935 void R_Shadow_LoadWorldLights(void)
4937 int n, a, style, shadow, flags;
4938 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
4939 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
4940 if (cl.worldmodel == NULL)
4942 Con_Print("No map loaded.\n");
4945 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4946 strlcat (name, ".rtlights", sizeof (name));
4947 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4957 for (;COM_Parse(t, true) && strcmp(
4958 if (COM_Parse(t, true))
4960 if (com_token[0] == '!')
4963 origin[0] = atof(com_token+1);
4966 origin[0] = atof(com_token);
4971 while (*s && *s != '\n' && *s != '\r')
4977 // check for modifier flags
4984 #if _MSC_VER >= 1400
4985 #define sscanf sscanf_s
4987 cubemapname[sizeof(cubemapname)-1] = 0;
4988 #if MAX_QPATH != 128
4989 #error update this code if MAX_QPATH changes
4991 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
4992 #if _MSC_VER >= 1400
4993 , sizeof(cubemapname)
4995 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
4998 flags = LIGHTFLAG_REALTIMEMODE;
5006 coronasizescale = 0.25f;
5008 VectorClear(angles);
5011 if (a < 9 || !strcmp(cubemapname, "\"\""))
5013 // remove quotes on cubemapname
5014 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
5017 namelen = strlen(cubemapname) - 2;
5018 memmove(cubemapname, cubemapname + 1, namelen);
5019 cubemapname[namelen] = '\0';
5023 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);
5026 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5034 Con_Printf("invalid rtlights file \"%s\"\n", name);
5035 Mem_Free(lightsstring);
5039 void R_Shadow_SaveWorldLights(void)
5043 size_t bufchars, bufmaxchars;
5045 char name[MAX_QPATH];
5046 char line[MAX_INPUTLINE];
5047 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
5048 // I hate lines which are 3 times my screen size :( --blub
5051 if (cl.worldmodel == NULL)
5053 Con_Print("No map loaded.\n");
5056 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
5057 strlcat (name, ".rtlights", sizeof (name));
5058 bufchars = bufmaxchars = 0;
5060 for (lightindex = 0;lightindex < range;lightindex++)
5062 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5065 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
5066 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);
5067 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
5068 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]);
5070 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);
5071 if (bufchars + strlen(line) > bufmaxchars)
5073 bufmaxchars = bufchars + strlen(line) + 2048;
5075 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
5079 memcpy(buf, oldbuf, bufchars);
5085 memcpy(buf + bufchars, line, strlen(line));
5086 bufchars += strlen(line);
5090 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
5095 void R_Shadow_LoadLightsFile(void)
5098 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
5099 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
5100 if (cl.worldmodel == NULL)
5102 Con_Print("No map loaded.\n");
5105 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
5106 strlcat (name, ".lights", sizeof (name));
5107 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5115 while (*s && *s != '\n' && *s != '\r')
5121 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);
5125 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);
5128 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
5129 radius = bound(15, radius, 4096);
5130 VectorScale(color, (2.0f / (8388608.0f)), color);
5131 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5139 Con_Printf("invalid lights file \"%s\"\n", name);
5140 Mem_Free(lightsstring);
5144 // tyrlite/hmap2 light types in the delay field
5145 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
5147 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
5159 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
5160 char key[256], value[MAX_INPUTLINE];
5162 if (cl.worldmodel == NULL)
5164 Con_Print("No map loaded.\n");
5167 // try to load a .ent file first
5168 FS_StripExtension (cl.worldmodel->name, key, sizeof (key));
5169 strlcat (key, ".ent", sizeof (key));
5170 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
5171 // and if that is not found, fall back to the bsp file entity string
5173 data = cl.worldmodel->brush.entities;
5176 for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
5178 type = LIGHTTYPE_MINUSX;
5179 origin[0] = origin[1] = origin[2] = 0;
5180 originhack[0] = originhack[1] = originhack[2] = 0;
5181 angles[0] = angles[1] = angles[2] = 0;
5182 color[0] = color[1] = color[2] = 1;
5183 light[0] = light[1] = light[2] = 1;light[3] = 300;
5184 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
5194 if (!COM_ParseToken_Simple(&data, false, false))
5196 if (com_token[0] == '}')
5197 break; // end of entity
5198 if (com_token[0] == '_')
5199 strlcpy(key, com_token + 1, sizeof(key));
5201 strlcpy(key, com_token, sizeof(key));
5202 while (key[strlen(key)-1] == ' ') // remove trailing spaces
5203 key[strlen(key)-1] = 0;
5204 if (!COM_ParseToken_Simple(&data, false, false))
5206 strlcpy(value, com_token, sizeof(value));
5208 // now that we have the key pair worked out...
5209 if (!strcmp("light", key))
5211 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5215 light[0] = vec[0] * (1.0f / 256.0f);
5216 light[1] = vec[0] * (1.0f / 256.0f);
5217 light[2] = vec[0] * (1.0f / 256.0f);
5223 light[0] = vec[0] * (1.0f / 255.0f);
5224 light[1] = vec[1] * (1.0f / 255.0f);
5225 light[2] = vec[2] * (1.0f / 255.0f);
5229 else if (!strcmp("delay", key))
5231 else if (!strcmp("origin", key))
5232 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5233 else if (!strcmp("angle", key))
5234 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5235 else if (!strcmp("angles", key))
5236 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5237 else if (!strcmp("color", key))
5238 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5239 else if (!strcmp("wait", key))
5240 fadescale = atof(value);
5241 else if (!strcmp("classname", key))
5243 if (!strncmp(value, "light", 5))
5246 if (!strcmp(value, "light_fluoro"))
5251 overridecolor[0] = 1;
5252 overridecolor[1] = 1;
5253 overridecolor[2] = 1;
5255 if (!strcmp(value, "light_fluorospark"))
5260 overridecolor[0] = 1;
5261 overridecolor[1] = 1;
5262 overridecolor[2] = 1;
5264 if (!strcmp(value, "light_globe"))
5269 overridecolor[0] = 1;
5270 overridecolor[1] = 0.8;
5271 overridecolor[2] = 0.4;
5273 if (!strcmp(value, "light_flame_large_yellow"))
5278 overridecolor[0] = 1;
5279 overridecolor[1] = 0.5;
5280 overridecolor[2] = 0.1;
5282 if (!strcmp(value, "light_flame_small_yellow"))
5287 overridecolor[0] = 1;
5288 overridecolor[1] = 0.5;
5289 overridecolor[2] = 0.1;
5291 if (!strcmp(value, "light_torch_small_white"))
5296 overridecolor[0] = 1;
5297 overridecolor[1] = 0.5;
5298 overridecolor[2] = 0.1;
5300 if (!strcmp(value, "light_torch_small_walltorch"))
5305 overridecolor[0] = 1;
5306 overridecolor[1] = 0.5;
5307 overridecolor[2] = 0.1;
5311 else if (!strcmp("style", key))
5312 style = atoi(value);
5313 else if (!strcmp("skin", key))
5314 skin = (int)atof(value);
5315 else if (!strcmp("pflags", key))
5316 pflags = (int)atof(value);
5317 //else if (!strcmp("effects", key))
5318 // effects = (int)atof(value);
5319 else if (cl.worldmodel->type == mod_brushq3)
5321 if (!strcmp("scale", key))
5322 lightscale = atof(value);
5323 if (!strcmp("fade", key))
5324 fadescale = atof(value);
5329 if (lightscale <= 0)
5333 if (color[0] == color[1] && color[0] == color[2])
5335 color[0] *= overridecolor[0];
5336 color[1] *= overridecolor[1];
5337 color[2] *= overridecolor[2];
5339 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5340 color[0] = color[0] * light[0];
5341 color[1] = color[1] * light[1];
5342 color[2] = color[2] * light[2];
5345 case LIGHTTYPE_MINUSX:
5347 case LIGHTTYPE_RECIPX:
5349 VectorScale(color, (1.0f / 16.0f), color);
5351 case LIGHTTYPE_RECIPXX:
5353 VectorScale(color, (1.0f / 16.0f), color);
5356 case LIGHTTYPE_NONE:
5360 case LIGHTTYPE_MINUSXX:
5363 VectorAdd(origin, originhack, origin);
5365 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);
5368 Mem_Free(entfiledata);
5372 void R_Shadow_SetCursorLocationForView(void)
5375 vec3_t dest, endpos;
5377 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5378 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
5379 if (trace.fraction < 1)
5381 dist = trace.fraction * r_editlights_cursordistance.value;
5382 push = r_editlights_cursorpushback.value;
5386 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5387 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5391 VectorClear( endpos );
5393 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5394 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5395 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5398 void R_Shadow_UpdateWorldLightSelection(void)
5400 if (r_editlights.integer)
5402 R_Shadow_SetCursorLocationForView();
5403 R_Shadow_SelectLightInView();
5406 R_Shadow_SelectLight(NULL);
5409 void R_Shadow_EditLights_Clear_f(void)
5411 R_Shadow_ClearWorldLights();
5414 void R_Shadow_EditLights_Reload_f(void)
5418 strlcpy(r_shadow_mapname, cl.worldmodel->name, sizeof(r_shadow_mapname));
5419 R_Shadow_ClearWorldLights();
5420 R_Shadow_LoadWorldLights();
5421 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5423 R_Shadow_LoadLightsFile();
5424 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5425 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5429 void R_Shadow_EditLights_Save_f(void)
5433 R_Shadow_SaveWorldLights();
5436 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
5438 R_Shadow_ClearWorldLights();
5439 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5442 void R_Shadow_EditLights_ImportLightsFile_f(void)
5444 R_Shadow_ClearWorldLights();
5445 R_Shadow_LoadLightsFile();
5448 void R_Shadow_EditLights_Spawn_f(void)
5451 if (!r_editlights.integer)
5453 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5456 if (Cmd_Argc() != 1)
5458 Con_Print("r_editlights_spawn does not take parameters\n");
5461 color[0] = color[1] = color[2] = 1;
5462 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5465 void R_Shadow_EditLights_Edit_f(void)
5467 vec3_t origin, angles, color;
5468 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5469 int style, shadows, flags, normalmode, realtimemode;
5470 char cubemapname[MAX_INPUTLINE];
5471 if (!r_editlights.integer)
5473 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5476 if (!r_shadow_selectedlight)
5478 Con_Print("No selected light.\n");
5481 VectorCopy(r_shadow_selectedlight->origin, origin);
5482 VectorCopy(r_shadow_selectedlight->angles, angles);
5483 VectorCopy(r_shadow_selectedlight->color, color);
5484 radius = r_shadow_selectedlight->radius;
5485 style = r_shadow_selectedlight->style;
5486 if (r_shadow_selectedlight->cubemapname)
5487 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5490 shadows = r_shadow_selectedlight->shadow;
5491 corona = r_shadow_selectedlight->corona;
5492 coronasizescale = r_shadow_selectedlight->coronasizescale;
5493 ambientscale = r_shadow_selectedlight->ambientscale;
5494 diffusescale = r_shadow_selectedlight->diffusescale;
5495 specularscale = r_shadow_selectedlight->specularscale;
5496 flags = r_shadow_selectedlight->flags;
5497 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5498 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5499 if (!strcmp(Cmd_Argv(1), "origin"))
5501 if (Cmd_Argc() != 5)
5503 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5506 origin[0] = atof(Cmd_Argv(2));
5507 origin[1] = atof(Cmd_Argv(3));
5508 origin[2] = atof(Cmd_Argv(4));
5510 else if (!strcmp(Cmd_Argv(1), "originx"))
5512 if (Cmd_Argc() != 3)
5514 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5517 origin[0] = atof(Cmd_Argv(2));
5519 else if (!strcmp(Cmd_Argv(1), "originy"))
5521 if (Cmd_Argc() != 3)
5523 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5526 origin[1] = atof(Cmd_Argv(2));
5528 else if (!strcmp(Cmd_Argv(1), "originz"))
5530 if (Cmd_Argc() != 3)
5532 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5535 origin[2] = atof(Cmd_Argv(2));
5537 else if (!strcmp(Cmd_Argv(1), "move"))
5539 if (Cmd_Argc() != 5)
5541 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5544 origin[0] += atof(Cmd_Argv(2));
5545 origin[1] += atof(Cmd_Argv(3));
5546 origin[2] += atof(Cmd_Argv(4));
5548 else if (!strcmp(Cmd_Argv(1), "movex"))
5550 if (Cmd_Argc() != 3)
5552 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5555 origin[0] += atof(Cmd_Argv(2));
5557 else if (!strcmp(Cmd_Argv(1), "movey"))
5559 if (Cmd_Argc() != 3)
5561 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5564 origin[1] += atof(Cmd_Argv(2));
5566 else if (!strcmp(Cmd_Argv(1), "movez"))
5568 if (Cmd_Argc() != 3)
5570 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5573 origin[2] += atof(Cmd_Argv(2));
5575 else if (!strcmp(Cmd_Argv(1), "angles"))
5577 if (Cmd_Argc() != 5)
5579 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5582 angles[0] = atof(Cmd_Argv(2));
5583 angles[1] = atof(Cmd_Argv(3));
5584 angles[2] = atof(Cmd_Argv(4));
5586 else if (!strcmp(Cmd_Argv(1), "anglesx"))
5588 if (Cmd_Argc() != 3)
5590 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5593 angles[0] = atof(Cmd_Argv(2));
5595 else if (!strcmp(Cmd_Argv(1), "anglesy"))
5597 if (Cmd_Argc() != 3)
5599 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5602 angles[1] = atof(Cmd_Argv(2));
5604 else if (!strcmp(Cmd_Argv(1), "anglesz"))
5606 if (Cmd_Argc() != 3)
5608 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5611 angles[2] = atof(Cmd_Argv(2));
5613 else if (!strcmp(Cmd_Argv(1), "color"))
5615 if (Cmd_Argc() != 5)
5617 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
5620 color[0] = atof(Cmd_Argv(2));
5621 color[1] = atof(Cmd_Argv(3));
5622 color[2] = atof(Cmd_Argv(4));
5624 else if (!strcmp(Cmd_Argv(1), "radius"))
5626 if (Cmd_Argc() != 3)
5628 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5631 radius = atof(Cmd_Argv(2));
5633 else if (!strcmp(Cmd_Argv(1), "colorscale"))
5635 if (Cmd_Argc() == 3)
5637 double scale = atof(Cmd_Argv(2));
5644 if (Cmd_Argc() != 5)
5646 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
5649 color[0] *= atof(Cmd_Argv(2));
5650 color[1] *= atof(Cmd_Argv(3));
5651 color[2] *= atof(Cmd_Argv(4));
5654 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
5656 if (Cmd_Argc() != 3)
5658 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5661 radius *= atof(Cmd_Argv(2));
5663 else if (!strcmp(Cmd_Argv(1), "style"))
5665 if (Cmd_Argc() != 3)
5667 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5670 style = atoi(Cmd_Argv(2));
5672 else if (!strcmp(Cmd_Argv(1), "cubemap"))
5676 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5679 if (Cmd_Argc() == 3)
5680 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
5684 else if (!strcmp(Cmd_Argv(1), "shadows"))
5686 if (Cmd_Argc() != 3)
5688 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5691 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5693 else if (!strcmp(Cmd_Argv(1), "corona"))
5695 if (Cmd_Argc() != 3)
5697 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5700 corona = atof(Cmd_Argv(2));
5702 else if (!strcmp(Cmd_Argv(1), "coronasize"))
5704 if (Cmd_Argc() != 3)
5706 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5709 coronasizescale = atof(Cmd_Argv(2));
5711 else if (!strcmp(Cmd_Argv(1), "ambient"))
5713 if (Cmd_Argc() != 3)
5715 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5718 ambientscale = atof(Cmd_Argv(2));
5720 else if (!strcmp(Cmd_Argv(1), "diffuse"))
5722 if (Cmd_Argc() != 3)
5724 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5727 diffusescale = atof(Cmd_Argv(2));
5729 else if (!strcmp(Cmd_Argv(1), "specular"))
5731 if (Cmd_Argc() != 3)
5733 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5736 specularscale = atof(Cmd_Argv(2));
5738 else if (!strcmp(Cmd_Argv(1), "normalmode"))
5740 if (Cmd_Argc() != 3)
5742 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5745 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5747 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
5749 if (Cmd_Argc() != 3)
5751 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5754 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5758 Con_Print("usage: r_editlights_edit [property] [value]\n");
5759 Con_Print("Selected light's properties:\n");
5760 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5761 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5762 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5763 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
5764 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
5765 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
5766 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5767 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
5768 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
5769 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
5770 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
5771 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
5772 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5773 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5776 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5777 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5780 void R_Shadow_EditLights_EditAll_f(void)
5786 if (!r_editlights.integer)
5788 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5792 // EditLights doesn't seem to have a "remove" command or something so:
5793 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5794 for (lightindex = 0;lightindex < range;lightindex++)
5796 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5799 R_Shadow_SelectLight(light);
5800 R_Shadow_EditLights_Edit_f();
5804 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
5806 int lightnumber, lightcount;
5807 size_t lightindex, range;
5811 if (!r_editlights.integer)
5813 x = vid_conwidth.value - 240;
5815 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
5818 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5819 for (lightindex = 0;lightindex < range;lightindex++)
5821 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5824 if (light == r_shadow_selectedlight)
5825 lightnumber = lightindex;
5828 dpsnprintf(temp, sizeof(temp), "Cursor origin: %.0f %.0f %.0f", r_editlights_cursorlocation[0], r_editlights_cursorlocation[1], r_editlights_cursorlocation[2]); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, false, FONT_DEFAULT);y += 8;
5829 dpsnprintf(temp, sizeof(temp), "Total lights : %i active (%i total)", lightcount, (int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray)); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, false, FONT_DEFAULT);y += 8;
5831 if (r_shadow_selectedlight == NULL)
5833 dpsnprintf(temp, sizeof(temp), "Light #%i properties:", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
5834 dpsnprintf(temp, sizeof(temp), "Origin : %.0f %.0f %.0f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
5835 dpsnprintf(temp, sizeof(temp), "Angles : %.0f %.0f %.0f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
5836 dpsnprintf(temp, sizeof(temp), "Color : %.2f %.2f %.2f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
5837 dpsnprintf(temp, sizeof(temp), "Radius : %.0f\n", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
5838 dpsnprintf(temp, sizeof(temp), "Corona : %.0f\n", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
5839 dpsnprintf(temp, sizeof(temp), "Style : %i\n", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
5840 dpsnprintf(temp, sizeof(temp), "Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
5841 dpsnprintf(temp, sizeof(temp), "Cubemap : %s\n", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
5842 dpsnprintf(temp, sizeof(temp), "CoronaSize : %.2f\n", r_shadow_selectedlight->coronasizescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
5843 dpsnprintf(temp, sizeof(temp), "Ambient : %.2f\n", r_shadow_selectedlight->ambientscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
5844 dpsnprintf(temp, sizeof(temp), "Diffuse : %.2f\n", r_shadow_selectedlight->diffusescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
5845 dpsnprintf(temp, sizeof(temp), "Specular : %.2f\n", r_shadow_selectedlight->specularscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
5846 dpsnprintf(temp, sizeof(temp), "NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
5847 dpsnprintf(temp, sizeof(temp), "RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
5850 void R_Shadow_EditLights_ToggleShadow_f(void)
5852 if (!r_editlights.integer)
5854 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5857 if (!r_shadow_selectedlight)
5859 Con_Print("No selected light.\n");
5862 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);
5865 void R_Shadow_EditLights_ToggleCorona_f(void)
5867 if (!r_editlights.integer)
5869 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5872 if (!r_shadow_selectedlight)
5874 Con_Print("No selected light.\n");
5877 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);
5880 void R_Shadow_EditLights_Remove_f(void)
5882 if (!r_editlights.integer)
5884 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
5887 if (!r_shadow_selectedlight)
5889 Con_Print("No selected light.\n");
5892 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
5893 r_shadow_selectedlight = NULL;
5896 void R_Shadow_EditLights_Help_f(void)
5899 "Documentation on r_editlights system:\n"
5901 "r_editlights : enable/disable editing mode\n"
5902 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
5903 "r_editlights_cursorpushback : push back cursor this far from surface\n"
5904 "r_editlights_cursorpushoff : push cursor off surface this far\n"
5905 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
5906 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
5908 "r_editlights_help : this help\n"
5909 "r_editlights_clear : remove all lights\n"
5910 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
5911 "r_editlights_save : save to .rtlights file\n"
5912 "r_editlights_spawn : create a light with default settings\n"
5913 "r_editlights_edit command : edit selected light - more documentation below\n"
5914 "r_editlights_remove : remove selected light\n"
5915 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
5916 "r_editlights_importlightentitiesfrommap : reload light entities\n"
5917 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
5919 "origin x y z : set light location\n"
5920 "originx x: set x component of light location\n"
5921 "originy y: set y component of light location\n"
5922 "originz z: set z component of light location\n"
5923 "move x y z : adjust light location\n"
5924 "movex x: adjust x component of light location\n"
5925 "movey y: adjust y component of light location\n"
5926 "movez z: adjust z component of light location\n"
5927 "angles x y z : set light angles\n"
5928 "anglesx x: set x component of light angles\n"
5929 "anglesy y: set y component of light angles\n"
5930 "anglesz z: set z component of light angles\n"
5931 "color r g b : set color of light (can be brighter than 1 1 1)\n"
5932 "radius radius : set radius (size) of light\n"
5933 "colorscale grey : multiply color of light (1 does nothing)\n"
5934 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
5935 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
5936 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
5937 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
5938 "cubemap basename : set filter cubemap of light (not yet supported)\n"
5939 "shadows 1/0 : turn on/off shadows\n"
5940 "corona n : set corona intensity\n"
5941 "coronasize n : set corona size (0-1)\n"
5942 "ambient n : set ambient intensity (0-1)\n"
5943 "diffuse n : set diffuse intensity (0-1)\n"
5944 "specular n : set specular intensity (0-1)\n"
5945 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
5946 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
5947 "<nothing> : print light properties to console\n"
5951 void R_Shadow_EditLights_CopyInfo_f(void)
5953 if (!r_editlights.integer)
5955 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
5958 if (!r_shadow_selectedlight)
5960 Con_Print("No selected light.\n");
5963 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
5964 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
5965 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
5966 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
5967 if (r_shadow_selectedlight->cubemapname)
5968 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
5970 r_shadow_bufferlight.cubemapname[0] = 0;
5971 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
5972 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
5973 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
5974 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
5975 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
5976 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
5977 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
5980 void R_Shadow_EditLights_PasteInfo_f(void)
5982 if (!r_editlights.integer)
5984 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
5987 if (!r_shadow_selectedlight)
5989 Con_Print("No selected light.\n");
5992 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);
5995 void R_Shadow_EditLights_Init(void)
5997 Cvar_RegisterVariable(&r_editlights);
5998 Cvar_RegisterVariable(&r_editlights_cursordistance);
5999 Cvar_RegisterVariable(&r_editlights_cursorpushback);
6000 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
6001 Cvar_RegisterVariable(&r_editlights_cursorgrid);
6002 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
6003 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
6004 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
6005 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)");
6006 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
6007 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
6008 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
6009 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)");
6010 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
6011 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
6012 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
6013 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
6014 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
6015 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
6016 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)");
6022 =============================================================================
6026 =============================================================================
6029 void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, int dynamic)
6031 VectorClear(diffusecolor);
6032 VectorClear(diffusenormal);
6034 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
6036 ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_refdef.scene.ambient;
6037 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
6040 VectorSet(ambientcolor, 1, 1, 1);
6047 for (i = 0;i < r_refdef.scene.numlights;i++)
6049 light = r_refdef.scene.lights[i];
6050 Matrix4x4_Transform(&light->matrix_worldtolight, p, v);
6051 f = 1 - VectorLength2(v);
6052 if (f > 0 && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
6053 VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);