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;
4206 void R_DrawModelShadowMaps(void)
4209 float relativethrowdistance, scale, size, radius, nearclip, farclip, dot1, dot2;
4210 entity_render_t *ent;
4211 vec3_t relativelightorigin;
4212 vec3_t relativelightdirection, relativeforward, relativeright;
4213 vec3_t relativeshadowmins, relativeshadowmaxs;
4214 vec3_t shadowdir, shadowforward, shadowright, shadoworigin;
4216 matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix;
4217 r_viewport_t viewport;
4220 if (!r_refdef.scene.numentities)
4223 switch (r_shadow_shadowmode)
4225 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4226 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
4233 R_ResetViewRendering3D();
4234 R_Shadow_RenderMode_Begin();
4235 R_Shadow_RenderMode_ActiveLight(NULL);
4237 switch (r_shadow_shadowmode)
4239 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4240 if (!r_shadow_shadowmap2dtexture)
4241 R_Shadow_MakeShadowMap(0, r_shadow_shadowmapmaxsize);
4242 fbo = r_shadow_fbo2d;
4243 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
4244 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
4245 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
4247 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
4248 if (!r_shadow_shadowmaprectangletexture)
4249 R_Shadow_MakeShadowMap(0, r_shadow_shadowmapmaxsize);
4250 fbo = r_shadow_fborectangle;
4251 r_shadow_shadowmap_texturescale[0] = 1.0f;
4252 r_shadow_shadowmap_texturescale[1] = 1.0f;
4253 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE;
4259 size = 2*r_shadow_shadowmapmaxsize;
4261 r_shadow_shadowmap_parameters[0] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
4262 r_shadow_shadowmap_parameters[1] = 1.0f;
4263 r_shadow_shadowmap_parameters[2] = size;
4264 r_shadow_shadowmap_parameters[3] = size;
4266 scale = r_shadow_shadowmapping_precision.value;
4267 radius = 0.5f * size / scale;
4268 nearclip = -r_shadows_throwdistance.value;
4269 farclip = r_shadows_throwdistance.value;
4270 Math_atov(r_shadows_throwdirection.string, shadowdir);
4271 VectorNormalize(shadowdir);
4272 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4273 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4274 if (fabs(dot1) <= fabs(dot2))
4275 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4277 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4278 VectorNormalize(shadowforward);
4279 VectorM(scale, shadowforward, &m[0]);
4280 m[3] = fabs(dot1) * 0.5f * size - DotProduct(r_refdef.view.origin, &m[0]);
4281 CrossProduct(shadowdir, shadowforward, shadowright);
4282 VectorM(scale, shadowright, &m[4]);
4283 m[7] = 0.5f * size - DotProduct(r_refdef.view.origin, &m[4]);
4284 VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
4285 m[11] = 0.5f - DotProduct(r_refdef.view.origin, &m[8]);
4286 Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
4287 Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
4288 R_Viewport_InitOrtho(&viewport, &cameramatrix, 0, 0, size, size, 0, size, size, 0, 0, -1, NULL);
4290 VectorMA(r_refdef.view.origin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4293 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);CHECKGLERROR
4294 R_SetupShader_ShowDepth();
4296 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);CHECKGLERROR
4297 R_SetupShader_DepthOrShadow();
4300 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
4303 R_SetViewport(&viewport);
4304 GL_Scissor(viewport.x, viewport.y, min(viewport.width + r_shadow_shadowmapborder, 2*r_shadow_shadowmapmaxsize), viewport.height + r_shadow_shadowmapborder);
4307 qglClearColor(1,1,1,1);
4308 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
4310 GL_Clear(GL_DEPTH_BUFFER_BIT);
4312 GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
4315 for (i = 0;i < r_refdef.scene.numentities;i++)
4317 ent = r_refdef.scene.entities[i];
4319 // cast shadows from anything of the map (submodels are optional)
4320 if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4322 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4323 Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
4324 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4325 Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
4326 Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
4327 relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4328 relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4329 relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4330 relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4331 relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4332 relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4333 RSurf_ActiveModelEntity(ent, false, false, false);
4334 ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
4335 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4339 R_Shadow_RenderMode_End();
4341 Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
4342 Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
4343 Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &shadowmatrix, &invmvpmatrix);
4345 r_shadow_usingshadowmaportho = true;
4346 switch (r_shadow_shadowmode)
4348 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4349 r_shadow_usingshadowmap2d = true;
4351 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
4352 r_shadow_usingshadowmaprect = true;
4359 void R_DrawModelShadows(void)
4362 float relativethrowdistance;
4363 entity_render_t *ent;
4364 vec3_t relativelightorigin;
4365 vec3_t relativelightdirection;
4366 vec3_t relativeshadowmins, relativeshadowmaxs;
4367 vec3_t tmp, shadowdir;
4369 if (!r_refdef.scene.numentities || !vid.stencil || r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL)
4373 R_ResetViewRendering3D();
4374 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4375 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4376 R_Shadow_RenderMode_Begin();
4377 R_Shadow_RenderMode_ActiveLight(NULL);
4378 r_shadow_lightscissor[0] = r_refdef.view.x;
4379 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
4380 r_shadow_lightscissor[2] = r_refdef.view.width;
4381 r_shadow_lightscissor[3] = r_refdef.view.height;
4382 R_Shadow_RenderMode_StencilShadowVolumes(false);
4385 if (r_shadows.integer == 2)
4387 Math_atov(r_shadows_throwdirection.string, shadowdir);
4388 VectorNormalize(shadowdir);
4391 R_Shadow_ClearStencil();
4393 for (i = 0;i < r_refdef.scene.numentities;i++)
4395 ent = r_refdef.scene.entities[i];
4397 // cast shadows from anything of the map (submodels are optional)
4398 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4400 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4401 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
4402 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
4403 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
4404 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4407 if(ent->entitynumber != 0)
4409 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
4410 int entnum, entnum2, recursion;
4411 entnum = entnum2 = ent->entitynumber;
4412 for(recursion = 32; recursion > 0; --recursion)
4414 entnum2 = cl.entities[entnum].state_current.tagentity;
4415 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
4420 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
4422 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
4423 // transform into modelspace of OUR entity
4424 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
4425 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
4428 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4431 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4434 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
4435 RSurf_ActiveModelEntity(ent, false, false, false);
4436 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4437 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4441 // not really the right mode, but this will disable any silly stencil features
4442 R_Shadow_RenderMode_End();
4444 // set up ortho view for rendering this pass
4445 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4446 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4447 //GL_ScissorTest(true);
4448 //R_EntityMatrix(&identitymatrix);
4449 //R_Mesh_ResetTextureState();
4450 R_ResetViewRendering2D();
4451 R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
4452 R_Mesh_ColorPointer(NULL, 0, 0);
4453 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
4455 // set up a darkening blend on shadowed areas
4456 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4457 //GL_DepthRange(0, 1);
4458 //GL_DepthTest(false);
4459 //GL_DepthMask(false);
4460 //GL_PolygonOffset(0, 0);CHECKGLERROR
4461 GL_Color(0, 0, 0, r_shadows_darken.value);
4462 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4463 //qglDepthFunc(GL_ALWAYS);CHECKGLERROR
4464 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
4465 qglStencilMask(255);CHECKGLERROR
4466 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
4467 qglStencilFunc(GL_NOTEQUAL, 128, 255);CHECKGLERROR
4469 // apply the blend to the shadowed areas
4470 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
4472 // restore the viewport
4473 R_SetViewport(&r_refdef.view.viewport);
4475 // restore other state to normal
4476 //R_Shadow_RenderMode_End();
4479 void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4482 vec3_t centerorigin;
4484 // if it's too close, skip it
4485 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
4487 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4490 if (usequery && r_numqueries + 2 <= r_maxqueries)
4492 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4493 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4494 // 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
4495 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4498 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use qglDepthFunc instead
4499 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
4500 qglDepthFunc(GL_ALWAYS);
4501 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4502 R_Mesh_VertexPointer(vertex3f, 0, 0);
4503 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
4504 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4505 qglDepthFunc(GL_LEQUAL);
4506 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
4507 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4508 R_Mesh_VertexPointer(vertex3f, 0, 0);
4509 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
4510 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4513 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4516 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
4518 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4521 GLint allpixels = 0, visiblepixels = 0;
4522 // now we have to check the query result
4523 if (rtlight->corona_queryindex_visiblepixels)
4526 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
4527 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
4529 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
4530 if (visiblepixels < 1 || allpixels < 1)
4532 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
4533 cscale *= rtlight->corona_visibility;
4537 // FIXME: these traces should scan all render entities instead of cl.world
4538 if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
4541 VectorScale(rtlight->currentcolor, cscale, color);
4542 if (VectorLength(color) > (1.0f / 256.0f))
4545 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
4548 VectorNegate(color, color);
4549 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
4551 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4552 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);
4553 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4555 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
4559 void R_Shadow_DrawCoronas(void)
4567 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4569 if (r_waterstate.renderingscene)
4571 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4572 R_EntityMatrix(&identitymatrix);
4574 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4576 // check occlusion of coronas
4577 // use GL_ARB_occlusion_query if available
4578 // otherwise use raytraces
4580 usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
4583 GL_ColorMask(0,0,0,0);
4584 if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
4585 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
4588 r_maxqueries = (range + r_refdef.scene.numlights) * 4;
4589 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
4591 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
4594 RSurf_ActiveWorldEntity();
4595 GL_BlendFunc(GL_ONE, GL_ZERO);
4596 GL_CullFace(GL_NONE);
4597 GL_DepthMask(false);
4598 GL_DepthRange(0, 1);
4599 GL_PolygonOffset(0, 0);
4601 R_Mesh_ColorPointer(NULL, 0, 0);
4602 R_Mesh_ResetTextureState();
4603 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
4605 for (lightindex = 0;lightindex < range;lightindex++)
4607 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4610 rtlight = &light->rtlight;
4611 rtlight->corona_visibility = 0;
4612 rtlight->corona_queryindex_visiblepixels = 0;
4613 rtlight->corona_queryindex_allpixels = 0;
4614 if (!(rtlight->flags & flag))
4616 if (rtlight->corona <= 0)
4618 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4620 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4622 for (i = 0;i < r_refdef.scene.numlights;i++)
4624 rtlight = r_refdef.scene.lights[i];
4625 rtlight->corona_visibility = 0;
4626 rtlight->corona_queryindex_visiblepixels = 0;
4627 rtlight->corona_queryindex_allpixels = 0;
4628 if (!(rtlight->flags & flag))
4630 if (rtlight->corona <= 0)
4632 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4635 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4637 // now draw the coronas using the query data for intensity info
4638 for (lightindex = 0;lightindex < range;lightindex++)
4640 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4643 rtlight = &light->rtlight;
4644 if (rtlight->corona_visibility <= 0)
4646 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4648 for (i = 0;i < r_refdef.scene.numlights;i++)
4650 rtlight = r_refdef.scene.lights[i];
4651 if (rtlight->corona_visibility <= 0)
4653 if (gl_flashblend.integer)
4654 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4656 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4662 dlight_t *R_Shadow_NewWorldLight(void)
4664 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4667 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)
4670 // validate parameters
4671 if (style < 0 || style >= MAX_LIGHTSTYLES)
4673 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
4679 // copy to light properties
4680 VectorCopy(origin, light->origin);
4681 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4682 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4683 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4685 light->color[0] = max(color[0], 0);
4686 light->color[1] = max(color[1], 0);
4687 light->color[2] = max(color[2], 0);
4689 light->color[0] = color[0];
4690 light->color[1] = color[1];
4691 light->color[2] = color[2];
4692 light->radius = max(radius, 0);
4693 light->style = style;
4694 light->shadow = shadowenable;
4695 light->corona = corona;
4696 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4697 light->coronasizescale = coronasizescale;
4698 light->ambientscale = ambientscale;
4699 light->diffusescale = diffusescale;
4700 light->specularscale = specularscale;
4701 light->flags = flags;
4703 // update renderable light data
4704 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4705 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);
4708 void R_Shadow_FreeWorldLight(dlight_t *light)
4710 if (r_shadow_selectedlight == light)
4711 r_shadow_selectedlight = NULL;
4712 R_RTLight_Uncompile(&light->rtlight);
4713 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4716 void R_Shadow_ClearWorldLights(void)
4720 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4721 for (lightindex = 0;lightindex < range;lightindex++)
4723 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4725 R_Shadow_FreeWorldLight(light);
4727 r_shadow_selectedlight = NULL;
4730 void R_Shadow_SelectLight(dlight_t *light)
4732 if (r_shadow_selectedlight)
4733 r_shadow_selectedlight->selected = false;
4734 r_shadow_selectedlight = light;
4735 if (r_shadow_selectedlight)
4736 r_shadow_selectedlight->selected = true;
4739 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4741 // this is never batched (there can be only one)
4743 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
4744 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4745 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4748 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4753 skinframe_t *skinframe;
4756 // this is never batched (due to the ent parameter changing every time)
4757 // so numsurfaces == 1 and surfacelist[0] == lightnumber
4758 const dlight_t *light = (dlight_t *)ent;
4761 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
4764 VectorScale(light->color, intensity, spritecolor);
4765 if (VectorLength(spritecolor) < 0.1732f)
4766 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
4767 if (VectorLength(spritecolor) > 1.0f)
4768 VectorNormalize(spritecolor);
4770 // draw light sprite
4771 if (light->cubemapname[0] && !light->shadow)
4772 skinframe = r_editlights_sprcubemapnoshadowlight;
4773 else if (light->cubemapname[0])
4774 skinframe = r_editlights_sprcubemaplight;
4775 else if (!light->shadow)
4776 skinframe = r_editlights_sprnoshadowlight;
4778 skinframe = r_editlights_sprlight;
4780 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);
4781 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4783 // draw selection sprite if light is selected
4784 if (light->selected)
4786 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4787 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4788 // VorteX todo: add normalmode/realtime mode light overlay sprites?
4792 void R_Shadow_DrawLightSprites(void)
4796 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4797 for (lightindex = 0;lightindex < range;lightindex++)
4799 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4801 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
4803 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
4806 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
4811 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
4812 if (lightindex >= range)
4814 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4817 rtlight = &light->rtlight;
4818 //if (!(rtlight->flags & flag))
4820 VectorCopy(rtlight->shadoworigin, origin);
4821 *radius = rtlight->radius;
4822 VectorCopy(rtlight->color, color);
4826 void R_Shadow_SelectLightInView(void)
4828 float bestrating, rating, temp[3];
4832 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4835 for (lightindex = 0;lightindex < range;lightindex++)
4837 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4840 VectorSubtract(light->origin, r_refdef.view.origin, temp);
4841 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
4844 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
4845 if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1.0f)
4847 bestrating = rating;
4852 R_Shadow_SelectLight(best);
4855 void R_Shadow_LoadWorldLights(void)
4857 int n, a, style, shadow, flags;
4858 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
4859 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
4860 if (cl.worldmodel == NULL)
4862 Con_Print("No map loaded.\n");
4865 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4866 strlcat (name, ".rtlights", sizeof (name));
4867 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4877 for (;COM_Parse(t, true) && strcmp(
4878 if (COM_Parse(t, true))
4880 if (com_token[0] == '!')
4883 origin[0] = atof(com_token+1);
4886 origin[0] = atof(com_token);
4891 while (*s && *s != '\n' && *s != '\r')
4897 // check for modifier flags
4904 #if _MSC_VER >= 1400
4905 #define sscanf sscanf_s
4907 cubemapname[sizeof(cubemapname)-1] = 0;
4908 #if MAX_QPATH != 128
4909 #error update this code if MAX_QPATH changes
4911 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
4912 #if _MSC_VER >= 1400
4913 , sizeof(cubemapname)
4915 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
4918 flags = LIGHTFLAG_REALTIMEMODE;
4926 coronasizescale = 0.25f;
4928 VectorClear(angles);
4931 if (a < 9 || !strcmp(cubemapname, "\"\""))
4933 // remove quotes on cubemapname
4934 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
4937 namelen = strlen(cubemapname) - 2;
4938 memmove(cubemapname, cubemapname + 1, namelen);
4939 cubemapname[namelen] = '\0';
4943 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);
4946 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4954 Con_Printf("invalid rtlights file \"%s\"\n", name);
4955 Mem_Free(lightsstring);
4959 void R_Shadow_SaveWorldLights(void)
4963 size_t bufchars, bufmaxchars;
4965 char name[MAX_QPATH];
4966 char line[MAX_INPUTLINE];
4967 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
4968 // I hate lines which are 3 times my screen size :( --blub
4971 if (cl.worldmodel == NULL)
4973 Con_Print("No map loaded.\n");
4976 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4977 strlcat (name, ".rtlights", sizeof (name));
4978 bufchars = bufmaxchars = 0;
4980 for (lightindex = 0;lightindex < range;lightindex++)
4982 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4985 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
4986 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);
4987 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
4988 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]);
4990 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);
4991 if (bufchars + strlen(line) > bufmaxchars)
4993 bufmaxchars = bufchars + strlen(line) + 2048;
4995 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
4999 memcpy(buf, oldbuf, bufchars);
5005 memcpy(buf + bufchars, line, strlen(line));
5006 bufchars += strlen(line);
5010 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
5015 void R_Shadow_LoadLightsFile(void)
5018 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
5019 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
5020 if (cl.worldmodel == NULL)
5022 Con_Print("No map loaded.\n");
5025 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
5026 strlcat (name, ".lights", sizeof (name));
5027 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5035 while (*s && *s != '\n' && *s != '\r')
5041 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);
5045 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);
5048 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
5049 radius = bound(15, radius, 4096);
5050 VectorScale(color, (2.0f / (8388608.0f)), color);
5051 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5059 Con_Printf("invalid lights file \"%s\"\n", name);
5060 Mem_Free(lightsstring);
5064 // tyrlite/hmap2 light types in the delay field
5065 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
5067 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
5079 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
5080 char key[256], value[MAX_INPUTLINE];
5082 if (cl.worldmodel == NULL)
5084 Con_Print("No map loaded.\n");
5087 // try to load a .ent file first
5088 FS_StripExtension (cl.worldmodel->name, key, sizeof (key));
5089 strlcat (key, ".ent", sizeof (key));
5090 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
5091 // and if that is not found, fall back to the bsp file entity string
5093 data = cl.worldmodel->brush.entities;
5096 for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
5098 type = LIGHTTYPE_MINUSX;
5099 origin[0] = origin[1] = origin[2] = 0;
5100 originhack[0] = originhack[1] = originhack[2] = 0;
5101 angles[0] = angles[1] = angles[2] = 0;
5102 color[0] = color[1] = color[2] = 1;
5103 light[0] = light[1] = light[2] = 1;light[3] = 300;
5104 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
5114 if (!COM_ParseToken_Simple(&data, false, false))
5116 if (com_token[0] == '}')
5117 break; // end of entity
5118 if (com_token[0] == '_')
5119 strlcpy(key, com_token + 1, sizeof(key));
5121 strlcpy(key, com_token, sizeof(key));
5122 while (key[strlen(key)-1] == ' ') // remove trailing spaces
5123 key[strlen(key)-1] = 0;
5124 if (!COM_ParseToken_Simple(&data, false, false))
5126 strlcpy(value, com_token, sizeof(value));
5128 // now that we have the key pair worked out...
5129 if (!strcmp("light", key))
5131 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5135 light[0] = vec[0] * (1.0f / 256.0f);
5136 light[1] = vec[0] * (1.0f / 256.0f);
5137 light[2] = vec[0] * (1.0f / 256.0f);
5143 light[0] = vec[0] * (1.0f / 255.0f);
5144 light[1] = vec[1] * (1.0f / 255.0f);
5145 light[2] = vec[2] * (1.0f / 255.0f);
5149 else if (!strcmp("delay", key))
5151 else if (!strcmp("origin", key))
5152 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5153 else if (!strcmp("angle", key))
5154 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5155 else if (!strcmp("angles", key))
5156 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5157 else if (!strcmp("color", key))
5158 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5159 else if (!strcmp("wait", key))
5160 fadescale = atof(value);
5161 else if (!strcmp("classname", key))
5163 if (!strncmp(value, "light", 5))
5166 if (!strcmp(value, "light_fluoro"))
5171 overridecolor[0] = 1;
5172 overridecolor[1] = 1;
5173 overridecolor[2] = 1;
5175 if (!strcmp(value, "light_fluorospark"))
5180 overridecolor[0] = 1;
5181 overridecolor[1] = 1;
5182 overridecolor[2] = 1;
5184 if (!strcmp(value, "light_globe"))
5189 overridecolor[0] = 1;
5190 overridecolor[1] = 0.8;
5191 overridecolor[2] = 0.4;
5193 if (!strcmp(value, "light_flame_large_yellow"))
5198 overridecolor[0] = 1;
5199 overridecolor[1] = 0.5;
5200 overridecolor[2] = 0.1;
5202 if (!strcmp(value, "light_flame_small_yellow"))
5207 overridecolor[0] = 1;
5208 overridecolor[1] = 0.5;
5209 overridecolor[2] = 0.1;
5211 if (!strcmp(value, "light_torch_small_white"))
5216 overridecolor[0] = 1;
5217 overridecolor[1] = 0.5;
5218 overridecolor[2] = 0.1;
5220 if (!strcmp(value, "light_torch_small_walltorch"))
5225 overridecolor[0] = 1;
5226 overridecolor[1] = 0.5;
5227 overridecolor[2] = 0.1;
5231 else if (!strcmp("style", key))
5232 style = atoi(value);
5233 else if (!strcmp("skin", key))
5234 skin = (int)atof(value);
5235 else if (!strcmp("pflags", key))
5236 pflags = (int)atof(value);
5237 //else if (!strcmp("effects", key))
5238 // effects = (int)atof(value);
5239 else if (cl.worldmodel->type == mod_brushq3)
5241 if (!strcmp("scale", key))
5242 lightscale = atof(value);
5243 if (!strcmp("fade", key))
5244 fadescale = atof(value);
5249 if (lightscale <= 0)
5253 if (color[0] == color[1] && color[0] == color[2])
5255 color[0] *= overridecolor[0];
5256 color[1] *= overridecolor[1];
5257 color[2] *= overridecolor[2];
5259 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5260 color[0] = color[0] * light[0];
5261 color[1] = color[1] * light[1];
5262 color[2] = color[2] * light[2];
5265 case LIGHTTYPE_MINUSX:
5267 case LIGHTTYPE_RECIPX:
5269 VectorScale(color, (1.0f / 16.0f), color);
5271 case LIGHTTYPE_RECIPXX:
5273 VectorScale(color, (1.0f / 16.0f), color);
5276 case LIGHTTYPE_NONE:
5280 case LIGHTTYPE_MINUSXX:
5283 VectorAdd(origin, originhack, origin);
5285 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);
5288 Mem_Free(entfiledata);
5292 void R_Shadow_SetCursorLocationForView(void)
5295 vec3_t dest, endpos;
5297 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5298 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
5299 if (trace.fraction < 1)
5301 dist = trace.fraction * r_editlights_cursordistance.value;
5302 push = r_editlights_cursorpushback.value;
5306 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5307 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5311 VectorClear( endpos );
5313 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5314 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5315 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5318 void R_Shadow_UpdateWorldLightSelection(void)
5320 if (r_editlights.integer)
5322 R_Shadow_SetCursorLocationForView();
5323 R_Shadow_SelectLightInView();
5326 R_Shadow_SelectLight(NULL);
5329 void R_Shadow_EditLights_Clear_f(void)
5331 R_Shadow_ClearWorldLights();
5334 void R_Shadow_EditLights_Reload_f(void)
5338 strlcpy(r_shadow_mapname, cl.worldmodel->name, sizeof(r_shadow_mapname));
5339 R_Shadow_ClearWorldLights();
5340 R_Shadow_LoadWorldLights();
5341 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5343 R_Shadow_LoadLightsFile();
5344 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5345 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5349 void R_Shadow_EditLights_Save_f(void)
5353 R_Shadow_SaveWorldLights();
5356 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
5358 R_Shadow_ClearWorldLights();
5359 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5362 void R_Shadow_EditLights_ImportLightsFile_f(void)
5364 R_Shadow_ClearWorldLights();
5365 R_Shadow_LoadLightsFile();
5368 void R_Shadow_EditLights_Spawn_f(void)
5371 if (!r_editlights.integer)
5373 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5376 if (Cmd_Argc() != 1)
5378 Con_Print("r_editlights_spawn does not take parameters\n");
5381 color[0] = color[1] = color[2] = 1;
5382 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5385 void R_Shadow_EditLights_Edit_f(void)
5387 vec3_t origin, angles, color;
5388 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5389 int style, shadows, flags, normalmode, realtimemode;
5390 char cubemapname[MAX_INPUTLINE];
5391 if (!r_editlights.integer)
5393 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5396 if (!r_shadow_selectedlight)
5398 Con_Print("No selected light.\n");
5401 VectorCopy(r_shadow_selectedlight->origin, origin);
5402 VectorCopy(r_shadow_selectedlight->angles, angles);
5403 VectorCopy(r_shadow_selectedlight->color, color);
5404 radius = r_shadow_selectedlight->radius;
5405 style = r_shadow_selectedlight->style;
5406 if (r_shadow_selectedlight->cubemapname)
5407 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5410 shadows = r_shadow_selectedlight->shadow;
5411 corona = r_shadow_selectedlight->corona;
5412 coronasizescale = r_shadow_selectedlight->coronasizescale;
5413 ambientscale = r_shadow_selectedlight->ambientscale;
5414 diffusescale = r_shadow_selectedlight->diffusescale;
5415 specularscale = r_shadow_selectedlight->specularscale;
5416 flags = r_shadow_selectedlight->flags;
5417 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5418 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5419 if (!strcmp(Cmd_Argv(1), "origin"))
5421 if (Cmd_Argc() != 5)
5423 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5426 origin[0] = atof(Cmd_Argv(2));
5427 origin[1] = atof(Cmd_Argv(3));
5428 origin[2] = atof(Cmd_Argv(4));
5430 else if (!strcmp(Cmd_Argv(1), "originx"))
5432 if (Cmd_Argc() != 3)
5434 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5437 origin[0] = atof(Cmd_Argv(2));
5439 else if (!strcmp(Cmd_Argv(1), "originy"))
5441 if (Cmd_Argc() != 3)
5443 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5446 origin[1] = atof(Cmd_Argv(2));
5448 else if (!strcmp(Cmd_Argv(1), "originz"))
5450 if (Cmd_Argc() != 3)
5452 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5455 origin[2] = atof(Cmd_Argv(2));
5457 else if (!strcmp(Cmd_Argv(1), "move"))
5459 if (Cmd_Argc() != 5)
5461 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5464 origin[0] += atof(Cmd_Argv(2));
5465 origin[1] += atof(Cmd_Argv(3));
5466 origin[2] += atof(Cmd_Argv(4));
5468 else if (!strcmp(Cmd_Argv(1), "movex"))
5470 if (Cmd_Argc() != 3)
5472 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5475 origin[0] += atof(Cmd_Argv(2));
5477 else if (!strcmp(Cmd_Argv(1), "movey"))
5479 if (Cmd_Argc() != 3)
5481 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5484 origin[1] += atof(Cmd_Argv(2));
5486 else if (!strcmp(Cmd_Argv(1), "movez"))
5488 if (Cmd_Argc() != 3)
5490 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5493 origin[2] += atof(Cmd_Argv(2));
5495 else if (!strcmp(Cmd_Argv(1), "angles"))
5497 if (Cmd_Argc() != 5)
5499 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5502 angles[0] = atof(Cmd_Argv(2));
5503 angles[1] = atof(Cmd_Argv(3));
5504 angles[2] = atof(Cmd_Argv(4));
5506 else if (!strcmp(Cmd_Argv(1), "anglesx"))
5508 if (Cmd_Argc() != 3)
5510 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5513 angles[0] = atof(Cmd_Argv(2));
5515 else if (!strcmp(Cmd_Argv(1), "anglesy"))
5517 if (Cmd_Argc() != 3)
5519 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5522 angles[1] = atof(Cmd_Argv(2));
5524 else if (!strcmp(Cmd_Argv(1), "anglesz"))
5526 if (Cmd_Argc() != 3)
5528 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5531 angles[2] = atof(Cmd_Argv(2));
5533 else if (!strcmp(Cmd_Argv(1), "color"))
5535 if (Cmd_Argc() != 5)
5537 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
5540 color[0] = atof(Cmd_Argv(2));
5541 color[1] = atof(Cmd_Argv(3));
5542 color[2] = atof(Cmd_Argv(4));
5544 else if (!strcmp(Cmd_Argv(1), "radius"))
5546 if (Cmd_Argc() != 3)
5548 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5551 radius = atof(Cmd_Argv(2));
5553 else if (!strcmp(Cmd_Argv(1), "colorscale"))
5555 if (Cmd_Argc() == 3)
5557 double scale = atof(Cmd_Argv(2));
5564 if (Cmd_Argc() != 5)
5566 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
5569 color[0] *= atof(Cmd_Argv(2));
5570 color[1] *= atof(Cmd_Argv(3));
5571 color[2] *= atof(Cmd_Argv(4));
5574 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
5576 if (Cmd_Argc() != 3)
5578 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5581 radius *= atof(Cmd_Argv(2));
5583 else if (!strcmp(Cmd_Argv(1), "style"))
5585 if (Cmd_Argc() != 3)
5587 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5590 style = atoi(Cmd_Argv(2));
5592 else if (!strcmp(Cmd_Argv(1), "cubemap"))
5596 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5599 if (Cmd_Argc() == 3)
5600 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
5604 else if (!strcmp(Cmd_Argv(1), "shadows"))
5606 if (Cmd_Argc() != 3)
5608 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5611 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5613 else if (!strcmp(Cmd_Argv(1), "corona"))
5615 if (Cmd_Argc() != 3)
5617 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5620 corona = atof(Cmd_Argv(2));
5622 else if (!strcmp(Cmd_Argv(1), "coronasize"))
5624 if (Cmd_Argc() != 3)
5626 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5629 coronasizescale = atof(Cmd_Argv(2));
5631 else if (!strcmp(Cmd_Argv(1), "ambient"))
5633 if (Cmd_Argc() != 3)
5635 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5638 ambientscale = atof(Cmd_Argv(2));
5640 else if (!strcmp(Cmd_Argv(1), "diffuse"))
5642 if (Cmd_Argc() != 3)
5644 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5647 diffusescale = atof(Cmd_Argv(2));
5649 else if (!strcmp(Cmd_Argv(1), "specular"))
5651 if (Cmd_Argc() != 3)
5653 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5656 specularscale = atof(Cmd_Argv(2));
5658 else if (!strcmp(Cmd_Argv(1), "normalmode"))
5660 if (Cmd_Argc() != 3)
5662 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5665 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5667 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
5669 if (Cmd_Argc() != 3)
5671 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5674 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5678 Con_Print("usage: r_editlights_edit [property] [value]\n");
5679 Con_Print("Selected light's properties:\n");
5680 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5681 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5682 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5683 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
5684 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
5685 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
5686 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5687 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
5688 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
5689 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
5690 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
5691 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
5692 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5693 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5696 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5697 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5700 void R_Shadow_EditLights_EditAll_f(void)
5706 if (!r_editlights.integer)
5708 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5712 // EditLights doesn't seem to have a "remove" command or something so:
5713 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5714 for (lightindex = 0;lightindex < range;lightindex++)
5716 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5719 R_Shadow_SelectLight(light);
5720 R_Shadow_EditLights_Edit_f();
5724 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
5726 int lightnumber, lightcount;
5727 size_t lightindex, range;
5731 if (!r_editlights.integer)
5733 x = vid_conwidth.value - 240;
5735 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
5738 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5739 for (lightindex = 0;lightindex < range;lightindex++)
5741 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5744 if (light == r_shadow_selectedlight)
5745 lightnumber = lightindex;
5748 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;
5749 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;
5751 if (r_shadow_selectedlight == NULL)
5753 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;
5754 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;
5755 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;
5756 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;
5757 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;
5758 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;
5759 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;
5760 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;
5761 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;
5762 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;
5763 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;
5764 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;
5765 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;
5766 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;
5767 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;
5770 void R_Shadow_EditLights_ToggleShadow_f(void)
5772 if (!r_editlights.integer)
5774 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5777 if (!r_shadow_selectedlight)
5779 Con_Print("No selected light.\n");
5782 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);
5785 void R_Shadow_EditLights_ToggleCorona_f(void)
5787 if (!r_editlights.integer)
5789 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5792 if (!r_shadow_selectedlight)
5794 Con_Print("No selected light.\n");
5797 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);
5800 void R_Shadow_EditLights_Remove_f(void)
5802 if (!r_editlights.integer)
5804 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
5807 if (!r_shadow_selectedlight)
5809 Con_Print("No selected light.\n");
5812 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
5813 r_shadow_selectedlight = NULL;
5816 void R_Shadow_EditLights_Help_f(void)
5819 "Documentation on r_editlights system:\n"
5821 "r_editlights : enable/disable editing mode\n"
5822 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
5823 "r_editlights_cursorpushback : push back cursor this far from surface\n"
5824 "r_editlights_cursorpushoff : push cursor off surface this far\n"
5825 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
5826 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
5828 "r_editlights_help : this help\n"
5829 "r_editlights_clear : remove all lights\n"
5830 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
5831 "r_editlights_save : save to .rtlights file\n"
5832 "r_editlights_spawn : create a light with default settings\n"
5833 "r_editlights_edit command : edit selected light - more documentation below\n"
5834 "r_editlights_remove : remove selected light\n"
5835 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
5836 "r_editlights_importlightentitiesfrommap : reload light entities\n"
5837 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
5839 "origin x y z : set light location\n"
5840 "originx x: set x component of light location\n"
5841 "originy y: set y component of light location\n"
5842 "originz z: set z component of light location\n"
5843 "move x y z : adjust light location\n"
5844 "movex x: adjust x component of light location\n"
5845 "movey y: adjust y component of light location\n"
5846 "movez z: adjust z component of light location\n"
5847 "angles x y z : set light angles\n"
5848 "anglesx x: set x component of light angles\n"
5849 "anglesy y: set y component of light angles\n"
5850 "anglesz z: set z component of light angles\n"
5851 "color r g b : set color of light (can be brighter than 1 1 1)\n"
5852 "radius radius : set radius (size) of light\n"
5853 "colorscale grey : multiply color of light (1 does nothing)\n"
5854 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
5855 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
5856 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
5857 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
5858 "cubemap basename : set filter cubemap of light (not yet supported)\n"
5859 "shadows 1/0 : turn on/off shadows\n"
5860 "corona n : set corona intensity\n"
5861 "coronasize n : set corona size (0-1)\n"
5862 "ambient n : set ambient intensity (0-1)\n"
5863 "diffuse n : set diffuse intensity (0-1)\n"
5864 "specular n : set specular intensity (0-1)\n"
5865 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
5866 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
5867 "<nothing> : print light properties to console\n"
5871 void R_Shadow_EditLights_CopyInfo_f(void)
5873 if (!r_editlights.integer)
5875 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
5878 if (!r_shadow_selectedlight)
5880 Con_Print("No selected light.\n");
5883 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
5884 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
5885 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
5886 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
5887 if (r_shadow_selectedlight->cubemapname)
5888 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
5890 r_shadow_bufferlight.cubemapname[0] = 0;
5891 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
5892 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
5893 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
5894 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
5895 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
5896 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
5897 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
5900 void R_Shadow_EditLights_PasteInfo_f(void)
5902 if (!r_editlights.integer)
5904 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
5907 if (!r_shadow_selectedlight)
5909 Con_Print("No selected light.\n");
5912 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);
5915 void R_Shadow_EditLights_Init(void)
5917 Cvar_RegisterVariable(&r_editlights);
5918 Cvar_RegisterVariable(&r_editlights_cursordistance);
5919 Cvar_RegisterVariable(&r_editlights_cursorpushback);
5920 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
5921 Cvar_RegisterVariable(&r_editlights_cursorgrid);
5922 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
5923 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
5924 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
5925 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)");
5926 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
5927 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
5928 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
5929 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)");
5930 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
5931 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
5932 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
5933 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
5934 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
5935 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
5936 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)");
5942 =============================================================================
5946 =============================================================================
5949 void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, int dynamic)
5951 VectorClear(diffusecolor);
5952 VectorClear(diffusenormal);
5954 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
5956 ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_refdef.scene.ambient;
5957 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
5960 VectorSet(ambientcolor, 1, 1, 1);
5967 for (i = 0;i < r_refdef.scene.numlights;i++)
5969 light = r_refdef.scene.lights[i];
5970 Matrix4x4_Transform(&light->matrix_worldtolight, p, v);
5971 f = 1 - VectorLength2(v);
5972 if (f > 0 && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
5973 VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);