3 Terminology: Stencil Shadow Volume (sometimes called Stencil Shadows)
4 An extrusion of the lit faces, beginning at the original geometry and ending
5 further from the light source than the original geometry (presumably at least
6 as far as the light's radius, if the light has a radius at all), capped at
7 both front and back to avoid any problems (extrusion from dark faces also
8 works but has a different set of problems)
10 This is normally rendered using Carmack's Reverse technique, in which
11 backfaces behind zbuffer (zfail) increment the stencil, and frontfaces behind
12 zbuffer (zfail) decrement the stencil, the result is a stencil value of zero
13 where shadows did not intersect the visible geometry, suitable as a stencil
14 mask for rendering lighting everywhere but shadow.
16 In our case to hopefully avoid the Creative Labs patent, we draw the backfaces
17 as decrement and the frontfaces as increment, and we redefine the DepthFunc to
18 GL_LESS (the patent uses GL_GEQUAL) which causes zfail when behind surfaces
19 and zpass when infront (the patent draws where zpass with a GL_GEQUAL test),
20 additionally we clear stencil to 128 to avoid the need for the unclamped
21 incr/decr extension (not related to patent).
24 This algorithm may be covered by Creative's patent (US Patent #6384822),
25 however that patent is quite specific about increment on backfaces and
26 decrement on frontfaces where zpass with GL_GEQUAL depth test, which is
27 opposite this implementation and partially opposite Carmack's Reverse paper
28 (which uses GL_LESS, but increments on backfaces and decrements on frontfaces).
32 Terminology: Stencil Light Volume (sometimes called Light Volumes)
33 Similar to a Stencil Shadow Volume, but inverted; rather than containing the
34 areas in shadow it contains the areas in light, this can only be built
35 quickly for certain limited cases (such as portal visibility from a point),
36 but is quite useful for some effects (sunlight coming from sky polygons is
37 one possible example, translucent occluders is another example).
41 Terminology: Optimized Stencil Shadow Volume
42 A Stencil Shadow Volume that has been processed sufficiently to ensure it has
43 no duplicate coverage of areas (no need to shadow an area twice), often this
44 greatly improves performance but is an operation too costly to use on moving
45 lights (however completely optimal Stencil Light Volumes can be constructed
50 Terminology: Per Pixel Lighting (sometimes abbreviated PPL)
51 Per pixel evaluation of lighting equations, at a bare minimum this involves
52 DOT3 shading of diffuse lighting (per pixel dotproduct of negated incidence
53 vector and surface normal, using a texture of the surface bumps, called a
54 NormalMap) if supported by hardware; in our case there is support for cards
55 which are incapable of DOT3, the quality is quite poor however. Additionally
56 it is desirable to have specular evaluation per pixel, per vertex
57 normalization of specular halfangle vectors causes noticable distortion but
58 is unavoidable on hardware without GL_ARB_fragment_program or
59 GL_ARB_fragment_shader.
63 Terminology: Normalization CubeMap
64 A cubemap containing normalized dot3-encoded (vectors of length 1 or less
65 encoded as RGB colors) for any possible direction, this technique allows per
66 pixel calculation of incidence vector for per pixel lighting purposes, which
67 would not otherwise be possible per pixel without GL_ARB_fragment_program or
68 GL_ARB_fragment_shader.
72 Terminology: 2D+1D Attenuation Texturing
73 A very crude approximation of light attenuation with distance which results
74 in cylindrical light shapes which fade vertically as a streak (some games
75 such as Doom3 allow this to be rotated to be less noticable in specific
76 cases), the technique is simply modulating lighting by two 2D textures (which
77 can be the same) on different axes of projection (XY and Z, typically), this
78 is the second best technique available without 3D Attenuation Texturing,
79 GL_ARB_fragment_program or GL_ARB_fragment_shader technology.
83 Terminology: 2D+1D Inverse Attenuation Texturing
84 A clever method described in papers on the Abducted engine, this has a squared
85 distance texture (bright on the outside, black in the middle), which is used
86 twice using GL_ADD blending, the result of this is used in an inverse modulate
87 (GL_ONE_MINUS_DST_ALPHA, GL_ZERO) to implement the equation
88 lighting*=(1-((X*X+Y*Y)+(Z*Z))) which is spherical (unlike 2D+1D attenuation
93 Terminology: 3D Attenuation Texturing
94 A slightly crude approximation of light attenuation with distance, its flaws
95 are limited radius and resolution (performance tradeoffs).
99 Terminology: 3D Attenuation-Normalization Texturing
100 A 3D Attenuation Texture merged with a Normalization CubeMap, by making the
101 vectors shorter the lighting becomes darker, a very effective optimization of
102 diffuse lighting if 3D Attenuation Textures are already used.
106 Terminology: Light Cubemap Filtering
107 A technique for modeling non-uniform light distribution according to
108 direction, for example a lantern may use a cubemap to describe the light
109 emission pattern of the cage around the lantern (as well as soot buildup
110 discoloring the light in certain areas), often also used for softened grate
111 shadows and light shining through a stained glass window (done crudely by
112 texturing the lighting with a cubemap), another good example would be a disco
113 light. This technique is used heavily in many games (Doom3 does not support
118 Terminology: Light Projection Filtering
119 A technique for modeling shadowing of light passing through translucent
120 surfaces, allowing stained glass windows and other effects to be done more
121 elegantly than possible with Light Cubemap Filtering by applying an occluder
122 texture to the lighting combined with a stencil light volume to limit the lit
123 area, this technique is used by Doom3 for spotlights and flashlights, among
124 other things, this can also be used more generally to render light passing
125 through multiple translucent occluders in a scene (using a light volume to
126 describe the area beyond the occluder, and thus mask off rendering of all
131 Terminology: Doom3 Lighting
132 A combination of Stencil Shadow Volume, Per Pixel Lighting, Normalization
133 CubeMap, 2D+1D Attenuation Texturing, and Light Projection Filtering, as
134 demonstrated by the game Doom3.
137 #include "quakedef.h"
138 #include "r_shadow.h"
139 #include "cl_collision.h"
143 extern void R_Shadow_EditLights_Init(void);
145 typedef enum r_shadow_rendermode_e
147 R_SHADOW_RENDERMODE_NONE,
148 R_SHADOW_RENDERMODE_ZPASS_STENCIL,
149 R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL,
150 R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE,
151 R_SHADOW_RENDERMODE_ZFAIL_STENCIL,
152 R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL,
153 R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE,
154 R_SHADOW_RENDERMODE_LIGHT_VERTEX,
155 R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN,
156 R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN,
157 R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN,
158 R_SHADOW_RENDERMODE_LIGHT_GLSL,
159 R_SHADOW_RENDERMODE_VISIBLEVOLUMES,
160 R_SHADOW_RENDERMODE_VISIBLELIGHTING,
161 R_SHADOW_RENDERMODE_SHADOWMAP2D,
162 R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE,
163 R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE,
165 r_shadow_rendermode_t;
167 typedef enum r_shadow_shadowmode_e
169 R_SHADOW_SHADOWMODE_STENCIL,
170 R_SHADOW_SHADOWMODE_SHADOWMAP2D,
171 R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE,
172 R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE
174 r_shadow_shadowmode_t;
176 r_shadow_rendermode_t r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
177 r_shadow_rendermode_t r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_NONE;
178 r_shadow_rendermode_t r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_NONE;
179 r_shadow_rendermode_t r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_NONE;
180 qboolean r_shadow_usingshadowmaprect;
181 qboolean r_shadow_usingshadowmap2d;
182 qboolean r_shadow_usingshadowmapcube;
183 int r_shadow_shadowmapside;
184 float r_shadow_shadowmap_texturescale[2];
185 float r_shadow_shadowmap_parameters[4];
187 int r_shadow_drawbuffer;
188 int r_shadow_readbuffer;
190 int r_shadow_cullface_front, r_shadow_cullface_back;
191 GLuint r_shadow_fborectangle;
192 GLuint r_shadow_fbocubeside[R_SHADOW_SHADOWMAP_NUMCUBEMAPS];
193 GLuint r_shadow_fbo2d;
194 r_shadow_shadowmode_t r_shadow_shadowmode;
195 int r_shadow_shadowmapfilterquality;
196 int r_shadow_shadowmaptexturetype;
197 int r_shadow_shadowmapdepthbits;
198 int r_shadow_shadowmapmaxsize;
199 qboolean r_shadow_shadowmapvsdct;
200 qboolean r_shadow_shadowmapsampler;
201 int r_shadow_shadowmappcf;
202 int r_shadow_shadowmapborder;
203 int r_shadow_lightscissor[4];
204 qboolean r_shadow_usingdeferredprepass;
206 int maxshadowtriangles;
209 int maxshadowvertices;
210 float *shadowvertex3f;
220 unsigned char *shadowsides;
221 int *shadowsideslist;
228 int r_shadow_buffer_numleafpvsbytes;
229 unsigned char *r_shadow_buffer_visitingleafpvs;
230 unsigned char *r_shadow_buffer_leafpvs;
231 int *r_shadow_buffer_leaflist;
233 int r_shadow_buffer_numsurfacepvsbytes;
234 unsigned char *r_shadow_buffer_surfacepvs;
235 int *r_shadow_buffer_surfacelist;
236 unsigned char *r_shadow_buffer_surfacesides;
238 int r_shadow_buffer_numshadowtrispvsbytes;
239 unsigned char *r_shadow_buffer_shadowtrispvs;
240 int r_shadow_buffer_numlighttrispvsbytes;
241 unsigned char *r_shadow_buffer_lighttrispvs;
243 rtexturepool_t *r_shadow_texturepool;
244 rtexture_t *r_shadow_attenuationgradienttexture;
245 rtexture_t *r_shadow_attenuation2dtexture;
246 rtexture_t *r_shadow_attenuation3dtexture;
247 skinframe_t *r_shadow_lightcorona;
248 rtexture_t *r_shadow_shadowmaprectangletexture;
249 rtexture_t *r_shadow_shadowmap2dtexture;
250 rtexture_t *r_shadow_shadowmapcubetexture[R_SHADOW_SHADOWMAP_NUMCUBEMAPS];
251 rtexture_t *r_shadow_shadowmapvsdcttexture;
252 int r_shadow_shadowmapsize; // changes for each light based on distance
253 int r_shadow_shadowmaplod; // changes for each light based on distance
255 GLuint r_shadow_prepassgeometryfbo;
256 GLuint r_shadow_prepasslightingfbo;
257 int r_shadow_prepass_width;
258 int r_shadow_prepass_height;
259 rtexture_t *r_shadow_prepassgeometrydepthtexture;
260 rtexture_t *r_shadow_prepassgeometrynormalmaptexture;
261 rtexture_t *r_shadow_prepasslightingdiffusetexture;
262 rtexture_t *r_shadow_prepasslightingspeculartexture;
264 // lights are reloaded when this changes
265 char r_shadow_mapname[MAX_QPATH];
267 // used only for light filters (cubemaps)
268 rtexturepool_t *r_shadow_filters_texturepool;
270 static const GLenum r_shadow_prepasslightingdrawbuffers[2] = {GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT};
272 cvar_t r_shadow_bumpscale_basetexture = {0, "r_shadow_bumpscale_basetexture", "0", "generate fake bumpmaps from diffuse textures at this bumpyness, try 4 to match tenebrae, higher values increase depth, requires r_restart to take effect"};
273 cvar_t r_shadow_bumpscale_bumpmap = {0, "r_shadow_bumpscale_bumpmap", "4", "what magnitude to interpret _bump.tga textures as, higher values increase depth, requires r_restart to take effect"};
274 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
275 cvar_t r_shadow_deferred = {CVAR_SAVE, "r_shadow_deferred", "0", "uses image-based lighting instead of geometry-based lighting, the method used renders a depth image and a normalmap image, renders lights into separate diffuse and specular images, and then combines this into the normal rendering, requires r_shadow_shadowmapping"};
276 cvar_t r_shadow_deferred_8bitrange = {CVAR_SAVE, "r_shadow_deferred_8bitrange", "2", "dynamic range of image-based lighting when using 32bit color (does not apply to fp)"};
277 //cvar_t r_shadow_deferred_fp = {CVAR_SAVE, "r_shadow_deferred_fp", "0", "use 16bit (1) or 32bit (2) floating point for accumulation of image-based lighting"};
278 cvar_t r_shadow_usenormalmap = {CVAR_SAVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"};
279 cvar_t r_shadow_gloss = {CVAR_SAVE, "r_shadow_gloss", "1", "0 disables gloss (specularity) rendering, 1 uses gloss if textures are found, 2 forces a flat metallic specular effect on everything without textures (similar to tenebrae)"};
280 cvar_t r_shadow_gloss2intensity = {0, "r_shadow_gloss2intensity", "0.125", "how bright the forced flat gloss should look if r_shadow_gloss is 2"};
281 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
282 cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
283 cvar_t r_shadow_gloss2exponent = {0, "r_shadow_gloss2exponent", "32", "same as r_shadow_glossexponent but for forced gloss (gloss 2) surfaces"};
284 cvar_t r_shadow_glossexact = {0, "r_shadow_glossexact", "0", "use exact reflection math for gloss (slightly slower, but should look a tad better)"};
285 cvar_t r_shadow_lightattenuationdividebias = {0, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"};
286 cvar_t r_shadow_lightattenuationlinearscale = {0, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"};
287 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
288 cvar_t r_shadow_lightradiusscale = {0, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
289 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "0", "how far to cast shadows"};
290 cvar_t r_shadow_frontsidecasting = {0, "r_shadow_frontsidecasting", "1", "whether to cast shadows from illuminated triangles (front side of model) or unlit triangles (back side of model)"};
291 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
292 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
293 cvar_t r_shadow_realtime_dlight_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
294 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
295 cvar_t r_shadow_realtime_world = {CVAR_SAVE, "r_shadow_realtime_world", "0", "enables rendering of full world lighting (whether loaded from the map, or a .rtlights file, or a .ent file, or a .lights file produced by hlight)"};
296 cvar_t r_shadow_realtime_world_lightmaps = {CVAR_SAVE, "r_shadow_realtime_world_lightmaps", "0", "brightness to render lightmaps when using full world lighting, try 0.5 for a tenebrae-like appearance"};
297 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
298 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
299 cvar_t r_shadow_realtime_world_compileshadow = {0, "r_shadow_realtime_world_compileshadow", "1", "enables compilation of shadows from world lights for higher performance rendering"};
300 cvar_t r_shadow_realtime_world_compilesvbsp = {0, "r_shadow_realtime_world_compilesvbsp", "1", "enables svbsp optimization during compilation (slower than compileportalculling but more exact)"};
301 cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "0", "enables portal-based culling optimization during compilation (overrides compilesvbsp)"};
302 cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1", "use scissor optimization of light rendering (restricts rendering to the portion of the screen affected by the light)"};
303 cvar_t r_shadow_shadowmapping = {CVAR_SAVE, "r_shadow_shadowmapping", "0", "enables use of shadowmapping (depth texture sampling) instead of stencil shadow volumes, requires gl_fbo 1"};
304 cvar_t r_shadow_shadowmapping_texturetype = {CVAR_SAVE, "r_shadow_shadowmapping_texturetype", "-1", "shadowmap texture types: -1 = auto-select, 0 = 2D, 1 = rectangle, 2 = cubemap"};
305 cvar_t r_shadow_shadowmapping_filterquality = {CVAR_SAVE, "r_shadow_shadowmapping_filterquality", "-1", "shadowmap filter modes: -1 = auto-select, 0 = no filtering, 1 = bilinear, 2 = bilinear 2x2 blur (fast), 3 = 3x3 blur (moderate), 4 = 4x4 blur (slow)"};
306 cvar_t r_shadow_shadowmapping_depthbits = {CVAR_SAVE, "r_shadow_shadowmapping_depthbits", "24", "requested minimum shadowmap texture depth bits"};
307 cvar_t r_shadow_shadowmapping_vsdct = {CVAR_SAVE, "r_shadow_shadowmapping_vsdct", "1", "enables use of virtual shadow depth cube texture"};
308 cvar_t r_shadow_shadowmapping_minsize = {CVAR_SAVE, "r_shadow_shadowmapping_minsize", "32", "shadowmap size limit"};
309 cvar_t r_shadow_shadowmapping_maxsize = {CVAR_SAVE, "r_shadow_shadowmapping_maxsize", "512", "shadowmap size limit"};
310 cvar_t r_shadow_shadowmapping_precision = {CVAR_SAVE, "r_shadow_shadowmapping_precision", "1", "makes shadowmaps have a maximum resolution of this number of pixels per light source radius unit such that, for example, at precision 0.5 a light with radius 200 will have a maximum resolution of 100 pixels"};
311 //cvar_t r_shadow_shadowmapping_lod_bias = {CVAR_SAVE, "r_shadow_shadowmapping_lod_bias", "16", "shadowmap size bias"};
312 //cvar_t r_shadow_shadowmapping_lod_scale = {CVAR_SAVE, "r_shadow_shadowmapping_lod_scale", "128", "shadowmap size scaling parameter"};
313 cvar_t r_shadow_shadowmapping_bordersize = {CVAR_SAVE, "r_shadow_shadowmapping_bordersize", "4", "shadowmap size bias for filtering"};
314 cvar_t r_shadow_shadowmapping_nearclip = {CVAR_SAVE, "r_shadow_shadowmapping_nearclip", "1", "shadowmap nearclip in world units"};
315 cvar_t r_shadow_shadowmapping_bias = {CVAR_SAVE, "r_shadow_shadowmapping_bias", "0.03", "shadowmap bias parameter (this is multiplied by nearclip * 1024 / lodsize)"};
316 cvar_t r_shadow_shadowmapping_polygonfactor = {CVAR_SAVE, "r_shadow_shadowmapping_polygonfactor", "2", "slope-dependent shadowmapping bias"};
317 cvar_t r_shadow_shadowmapping_polygonoffset = {CVAR_SAVE, "r_shadow_shadowmapping_polygonoffset", "0", "constant shadowmapping bias"};
318 cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
319 cvar_t r_shadow_polygonoffset = {0, "r_shadow_polygonoffset", "1", "how much to push shadow volumes into the distance when rendering, to reduce chances of zfighting artifacts (should not be less than 0)"};
320 cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "1", "use 3D voxel textures for spherical attenuation rather than cylindrical (does not affect OpenGL 2.0 render path)"};
321 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "1", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
322 cvar_t r_coronas_occlusionsizescale = {CVAR_SAVE, "r_coronas_occlusionsizescale", "0.1", "size of light source for corona occlusion checksm the proportion of hidden pixels controls corona intensity"};
323 cvar_t r_coronas_occlusionquery = {CVAR_SAVE, "r_coronas_occlusionquery", "1", "use GL_ARB_occlusion_query extension if supported (fades coronas according to visibility)"};
324 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
325 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
326 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
327 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
328 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
329 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
330 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
331 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
332 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
334 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
335 #define ATTENTABLESIZE 256
336 // 1D gradient, 2D circle and 3D sphere attenuation textures
337 #define ATTEN1DSIZE 32
338 #define ATTEN2DSIZE 64
339 #define ATTEN3DSIZE 32
341 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
342 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
343 static float r_shadow_attentable[ATTENTABLESIZE+1];
345 rtlight_t *r_shadow_compilingrtlight;
346 static memexpandablearray_t r_shadow_worldlightsarray;
347 dlight_t *r_shadow_selectedlight;
348 dlight_t r_shadow_bufferlight;
349 vec3_t r_editlights_cursorlocation;
351 extern int con_vislines;
353 void R_Shadow_UncompileWorldLights(void);
354 void R_Shadow_ClearWorldLights(void);
355 void R_Shadow_SaveWorldLights(void);
356 void R_Shadow_LoadWorldLights(void);
357 void R_Shadow_LoadLightsFile(void);
358 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
359 void R_Shadow_EditLights_Reload_f(void);
360 void R_Shadow_ValidateCvars(void);
361 static void R_Shadow_MakeTextures(void);
363 #define EDLIGHTSPRSIZE 8
364 skinframe_t *r_editlights_sprcursor;
365 skinframe_t *r_editlights_sprlight;
366 skinframe_t *r_editlights_sprnoshadowlight;
367 skinframe_t *r_editlights_sprcubemaplight;
368 skinframe_t *r_editlights_sprcubemapnoshadowlight;
369 skinframe_t *r_editlights_sprselection;
371 void R_Shadow_SetShadowMode(void)
373 r_shadow_shadowmapmaxsize = bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4);
374 r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer != 0;
375 r_shadow_shadowmapfilterquality = r_shadow_shadowmapping_filterquality.integer;
376 r_shadow_shadowmaptexturetype = r_shadow_shadowmapping_texturetype.integer;
377 r_shadow_shadowmapdepthbits = r_shadow_shadowmapping_depthbits.integer;
378 r_shadow_shadowmapborder = bound(0, r_shadow_shadowmapping_bordersize.integer, 16);
379 r_shadow_shadowmaplod = -1;
380 r_shadow_shadowmapsize = 0;
381 r_shadow_shadowmapsampler = false;
382 r_shadow_shadowmappcf = 0;
383 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
384 switch(vid.renderpath)
386 case RENDERPATH_GL20:
387 case RENDERPATH_CGGL:
388 if ((r_shadow_shadowmapping.integer || r_shadow_deferred.integer) && vid.support.ext_framebuffer_object)
390 if(r_shadow_shadowmapfilterquality < 0)
392 if(vid.support.amd_texture_texture4 || vid.support.arb_texture_gather)
393 r_shadow_shadowmappcf = 1;
394 else if(strstr(gl_vendor, "NVIDIA") || strstr(gl_renderer, "Radeon HD"))
396 r_shadow_shadowmapsampler = vid.support.arb_shadow;
397 r_shadow_shadowmappcf = 1;
399 else if(strstr(gl_vendor, "ATI"))
400 r_shadow_shadowmappcf = 1;
402 r_shadow_shadowmapsampler = vid.support.arb_shadow;
406 switch (r_shadow_shadowmapfilterquality)
409 r_shadow_shadowmapsampler = vid.support.arb_shadow;
412 r_shadow_shadowmapsampler = vid.support.arb_shadow;
413 r_shadow_shadowmappcf = 1;
416 r_shadow_shadowmappcf = 1;
419 r_shadow_shadowmappcf = 2;
423 switch (r_shadow_shadowmaptexturetype)
426 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
429 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE;
432 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE;
435 if((vid.support.amd_texture_texture4 || vid.support.arb_texture_gather) && r_shadow_shadowmappcf && !r_shadow_shadowmapsampler)
436 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
437 else if(vid.support.arb_texture_rectangle)
438 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE;
440 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
445 case RENDERPATH_GL13:
447 case RENDERPATH_GL11:
452 void R_Shadow_FreeShadowMaps(void)
456 R_Shadow_SetShadowMode();
458 if (!vid.support.ext_framebuffer_object || !vid.support.arb_fragment_shader)
463 if (r_shadow_fborectangle)
464 qglDeleteFramebuffersEXT(1, &r_shadow_fborectangle);CHECKGLERROR
465 r_shadow_fborectangle = 0;
468 qglDeleteFramebuffersEXT(1, &r_shadow_fbo2d);CHECKGLERROR
470 for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
471 if (r_shadow_fbocubeside[i])
472 qglDeleteFramebuffersEXT(1, &r_shadow_fbocubeside[i]);CHECKGLERROR
473 memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
475 if (r_shadow_shadowmaprectangletexture)
476 R_FreeTexture(r_shadow_shadowmaprectangletexture);
477 r_shadow_shadowmaprectangletexture = NULL;
479 if (r_shadow_shadowmap2dtexture)
480 R_FreeTexture(r_shadow_shadowmap2dtexture);
481 r_shadow_shadowmap2dtexture = NULL;
483 for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
484 if (r_shadow_shadowmapcubetexture[i])
485 R_FreeTexture(r_shadow_shadowmapcubetexture[i]);
486 memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
488 if (r_shadow_shadowmapvsdcttexture)
489 R_FreeTexture(r_shadow_shadowmapvsdcttexture);
490 r_shadow_shadowmapvsdcttexture = NULL;
495 void r_shadow_start(void)
497 // allocate vertex processing arrays
498 r_shadow_attenuationgradienttexture = NULL;
499 r_shadow_attenuation2dtexture = NULL;
500 r_shadow_attenuation3dtexture = NULL;
501 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
502 r_shadow_shadowmaprectangletexture = NULL;
503 r_shadow_shadowmap2dtexture = NULL;
504 memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
505 r_shadow_shadowmapvsdcttexture = NULL;
506 r_shadow_shadowmapmaxsize = 0;
507 r_shadow_shadowmapsize = 0;
508 r_shadow_shadowmaplod = 0;
509 r_shadow_shadowmapfilterquality = -1;
510 r_shadow_shadowmaptexturetype = -1;
511 r_shadow_shadowmapdepthbits = 0;
512 r_shadow_shadowmapvsdct = false;
513 r_shadow_shadowmapsampler = false;
514 r_shadow_shadowmappcf = 0;
515 r_shadow_fborectangle = 0;
517 memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
519 R_Shadow_FreeShadowMaps();
521 r_shadow_texturepool = NULL;
522 r_shadow_filters_texturepool = NULL;
523 R_Shadow_ValidateCvars();
524 R_Shadow_MakeTextures();
525 maxshadowtriangles = 0;
526 shadowelements = NULL;
527 maxshadowvertices = 0;
528 shadowvertex3f = NULL;
536 shadowmarklist = NULL;
541 shadowsideslist = NULL;
542 r_shadow_buffer_numleafpvsbytes = 0;
543 r_shadow_buffer_visitingleafpvs = NULL;
544 r_shadow_buffer_leafpvs = NULL;
545 r_shadow_buffer_leaflist = NULL;
546 r_shadow_buffer_numsurfacepvsbytes = 0;
547 r_shadow_buffer_surfacepvs = NULL;
548 r_shadow_buffer_surfacelist = NULL;
549 r_shadow_buffer_surfacesides = NULL;
550 r_shadow_buffer_numshadowtrispvsbytes = 0;
551 r_shadow_buffer_shadowtrispvs = NULL;
552 r_shadow_buffer_numlighttrispvsbytes = 0;
553 r_shadow_buffer_lighttrispvs = NULL;
555 r_shadow_usingdeferredprepass = false;
556 r_shadow_prepass_width = r_shadow_prepass_height = 0;
559 static void R_Shadow_FreeDeferred(void);
560 void r_shadow_shutdown(void)
563 R_Shadow_UncompileWorldLights();
565 R_Shadow_FreeShadowMaps();
567 r_shadow_usingdeferredprepass = false;
568 if (r_shadow_prepass_width)
569 R_Shadow_FreeDeferred();
570 r_shadow_prepass_width = r_shadow_prepass_height = 0;
573 r_shadow_attenuationgradienttexture = NULL;
574 r_shadow_attenuation2dtexture = NULL;
575 r_shadow_attenuation3dtexture = NULL;
576 R_FreeTexturePool(&r_shadow_texturepool);
577 R_FreeTexturePool(&r_shadow_filters_texturepool);
578 maxshadowtriangles = 0;
580 Mem_Free(shadowelements);
581 shadowelements = NULL;
583 Mem_Free(shadowvertex3f);
584 shadowvertex3f = NULL;
587 Mem_Free(vertexupdate);
590 Mem_Free(vertexremap);
596 Mem_Free(shadowmark);
599 Mem_Free(shadowmarklist);
600 shadowmarklist = NULL;
605 Mem_Free(shadowsides);
608 Mem_Free(shadowsideslist);
609 shadowsideslist = NULL;
610 r_shadow_buffer_numleafpvsbytes = 0;
611 if (r_shadow_buffer_visitingleafpvs)
612 Mem_Free(r_shadow_buffer_visitingleafpvs);
613 r_shadow_buffer_visitingleafpvs = NULL;
614 if (r_shadow_buffer_leafpvs)
615 Mem_Free(r_shadow_buffer_leafpvs);
616 r_shadow_buffer_leafpvs = NULL;
617 if (r_shadow_buffer_leaflist)
618 Mem_Free(r_shadow_buffer_leaflist);
619 r_shadow_buffer_leaflist = NULL;
620 r_shadow_buffer_numsurfacepvsbytes = 0;
621 if (r_shadow_buffer_surfacepvs)
622 Mem_Free(r_shadow_buffer_surfacepvs);
623 r_shadow_buffer_surfacepvs = NULL;
624 if (r_shadow_buffer_surfacelist)
625 Mem_Free(r_shadow_buffer_surfacelist);
626 r_shadow_buffer_surfacelist = NULL;
627 if (r_shadow_buffer_surfacesides)
628 Mem_Free(r_shadow_buffer_surfacesides);
629 r_shadow_buffer_surfacesides = NULL;
630 r_shadow_buffer_numshadowtrispvsbytes = 0;
631 if (r_shadow_buffer_shadowtrispvs)
632 Mem_Free(r_shadow_buffer_shadowtrispvs);
633 r_shadow_buffer_numlighttrispvsbytes = 0;
634 if (r_shadow_buffer_lighttrispvs)
635 Mem_Free(r_shadow_buffer_lighttrispvs);
638 void r_shadow_newmap(void)
640 if (r_shadow_lightcorona) R_SkinFrame_MarkUsed(r_shadow_lightcorona);
641 if (r_editlights_sprcursor) R_SkinFrame_MarkUsed(r_editlights_sprcursor);
642 if (r_editlights_sprlight) R_SkinFrame_MarkUsed(r_editlights_sprlight);
643 if (r_editlights_sprnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprnoshadowlight);
644 if (r_editlights_sprcubemaplight) R_SkinFrame_MarkUsed(r_editlights_sprcubemaplight);
645 if (r_editlights_sprcubemapnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprcubemapnoshadowlight);
646 if (r_editlights_sprselection) R_SkinFrame_MarkUsed(r_editlights_sprselection);
647 if (cl.worldmodel && strncmp(cl.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
648 R_Shadow_EditLights_Reload_f();
651 void R_Shadow_Init(void)
653 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
654 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
655 Cvar_RegisterVariable(&r_shadow_usenormalmap);
656 Cvar_RegisterVariable(&r_shadow_debuglight);
657 Cvar_RegisterVariable(&r_shadow_deferred);
658 Cvar_RegisterVariable(&r_shadow_deferred_8bitrange);
659 // Cvar_RegisterVariable(&r_shadow_deferred_fp);
660 Cvar_RegisterVariable(&r_shadow_gloss);
661 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
662 Cvar_RegisterVariable(&r_shadow_glossintensity);
663 Cvar_RegisterVariable(&r_shadow_glossexponent);
664 Cvar_RegisterVariable(&r_shadow_gloss2exponent);
665 Cvar_RegisterVariable(&r_shadow_glossexact);
666 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
667 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
668 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
669 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
670 Cvar_RegisterVariable(&r_shadow_projectdistance);
671 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
672 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
673 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
674 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
675 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
676 Cvar_RegisterVariable(&r_shadow_realtime_world);
677 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
678 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
679 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
680 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
681 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
682 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
683 Cvar_RegisterVariable(&r_shadow_scissor);
684 Cvar_RegisterVariable(&r_shadow_shadowmapping);
685 Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
686 Cvar_RegisterVariable(&r_shadow_shadowmapping_texturetype);
687 Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
688 Cvar_RegisterVariable(&r_shadow_shadowmapping_depthbits);
689 Cvar_RegisterVariable(&r_shadow_shadowmapping_precision);
690 Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
691 Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
692 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
693 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
694 Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
695 Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
696 Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
697 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonfactor);
698 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonoffset);
699 Cvar_RegisterVariable(&r_shadow_polygonfactor);
700 Cvar_RegisterVariable(&r_shadow_polygonoffset);
701 Cvar_RegisterVariable(&r_shadow_texture3d);
702 Cvar_RegisterVariable(&r_coronas);
703 Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
704 Cvar_RegisterVariable(&r_coronas_occlusionquery);
705 Cvar_RegisterVariable(&gl_flashblend);
706 Cvar_RegisterVariable(&gl_ext_separatestencil);
707 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
708 if (gamemode == GAME_TENEBRAE)
710 Cvar_SetValue("r_shadow_gloss", 2);
711 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
713 R_Shadow_EditLights_Init();
714 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
715 maxshadowtriangles = 0;
716 shadowelements = NULL;
717 maxshadowvertices = 0;
718 shadowvertex3f = NULL;
726 shadowmarklist = NULL;
731 shadowsideslist = NULL;
732 r_shadow_buffer_numleafpvsbytes = 0;
733 r_shadow_buffer_visitingleafpvs = NULL;
734 r_shadow_buffer_leafpvs = NULL;
735 r_shadow_buffer_leaflist = NULL;
736 r_shadow_buffer_numsurfacepvsbytes = 0;
737 r_shadow_buffer_surfacepvs = NULL;
738 r_shadow_buffer_surfacelist = NULL;
739 r_shadow_buffer_surfacesides = NULL;
740 r_shadow_buffer_shadowtrispvs = NULL;
741 r_shadow_buffer_lighttrispvs = NULL;
742 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
745 matrix4x4_t matrix_attenuationxyz =
748 {0.5, 0.0, 0.0, 0.5},
749 {0.0, 0.5, 0.0, 0.5},
750 {0.0, 0.0, 0.5, 0.5},
755 matrix4x4_t matrix_attenuationz =
758 {0.0, 0.0, 0.5, 0.5},
759 {0.0, 0.0, 0.0, 0.5},
760 {0.0, 0.0, 0.0, 0.5},
765 void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles, int vertscale, int triscale)
767 numvertices = ((numvertices + 255) & ~255) * vertscale;
768 numtriangles = ((numtriangles + 255) & ~255) * triscale;
769 // make sure shadowelements is big enough for this volume
770 if (maxshadowtriangles < numtriangles)
772 maxshadowtriangles = numtriangles;
774 Mem_Free(shadowelements);
775 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[3]));
777 // make sure shadowvertex3f is big enough for this volume
778 if (maxshadowvertices < numvertices)
780 maxshadowvertices = numvertices;
782 Mem_Free(shadowvertex3f);
783 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[3]));
787 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
789 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
790 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
791 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
792 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
793 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
795 if (r_shadow_buffer_visitingleafpvs)
796 Mem_Free(r_shadow_buffer_visitingleafpvs);
797 if (r_shadow_buffer_leafpvs)
798 Mem_Free(r_shadow_buffer_leafpvs);
799 if (r_shadow_buffer_leaflist)
800 Mem_Free(r_shadow_buffer_leaflist);
801 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
802 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
803 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
804 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
806 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
808 if (r_shadow_buffer_surfacepvs)
809 Mem_Free(r_shadow_buffer_surfacepvs);
810 if (r_shadow_buffer_surfacelist)
811 Mem_Free(r_shadow_buffer_surfacelist);
812 if (r_shadow_buffer_surfacesides)
813 Mem_Free(r_shadow_buffer_surfacesides);
814 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
815 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
816 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
817 r_shadow_buffer_surfacesides = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
819 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
821 if (r_shadow_buffer_shadowtrispvs)
822 Mem_Free(r_shadow_buffer_shadowtrispvs);
823 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
824 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
826 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
828 if (r_shadow_buffer_lighttrispvs)
829 Mem_Free(r_shadow_buffer_lighttrispvs);
830 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
831 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
835 void R_Shadow_PrepareShadowMark(int numtris)
837 // make sure shadowmark is big enough for this volume
838 if (maxshadowmark < numtris)
840 maxshadowmark = numtris;
842 Mem_Free(shadowmark);
844 Mem_Free(shadowmarklist);
845 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
846 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
850 // if shadowmarkcount wrapped we clear the array and adjust accordingly
851 if (shadowmarkcount == 0)
854 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
859 void R_Shadow_PrepareShadowSides(int numtris)
861 if (maxshadowsides < numtris)
863 maxshadowsides = numtris;
865 Mem_Free(shadowsides);
867 Mem_Free(shadowsideslist);
868 shadowsides = (unsigned char *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsides));
869 shadowsideslist = (int *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsideslist));
874 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)
877 int outtriangles = 0, outvertices = 0;
880 float ratio, direction[3], projectvector[3];
882 if (projectdirection)
883 VectorScale(projectdirection, projectdistance, projectvector);
885 VectorClear(projectvector);
887 // create the vertices
888 if (projectdirection)
890 for (i = 0;i < numshadowmarktris;i++)
892 element = inelement3i + shadowmarktris[i] * 3;
893 for (j = 0;j < 3;j++)
895 if (vertexupdate[element[j]] != vertexupdatenum)
897 vertexupdate[element[j]] = vertexupdatenum;
898 vertexremap[element[j]] = outvertices;
899 vertex = invertex3f + element[j] * 3;
900 // project one copy of the vertex according to projectvector
901 VectorCopy(vertex, outvertex3f);
902 VectorAdd(vertex, projectvector, (outvertex3f + 3));
911 for (i = 0;i < numshadowmarktris;i++)
913 element = inelement3i + shadowmarktris[i] * 3;
914 for (j = 0;j < 3;j++)
916 if (vertexupdate[element[j]] != vertexupdatenum)
918 vertexupdate[element[j]] = vertexupdatenum;
919 vertexremap[element[j]] = outvertices;
920 vertex = invertex3f + element[j] * 3;
921 // project one copy of the vertex to the sphere radius of the light
922 // (FIXME: would projecting it to the light box be better?)
923 VectorSubtract(vertex, projectorigin, direction);
924 ratio = projectdistance / VectorLength(direction);
925 VectorCopy(vertex, outvertex3f);
926 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
934 if (r_shadow_frontsidecasting.integer)
936 for (i = 0;i < numshadowmarktris;i++)
938 int remappedelement[3];
940 const int *neighbortriangle;
942 markindex = shadowmarktris[i] * 3;
943 element = inelement3i + markindex;
944 neighbortriangle = inneighbor3i + markindex;
945 // output the front and back triangles
946 outelement3i[0] = vertexremap[element[0]];
947 outelement3i[1] = vertexremap[element[1]];
948 outelement3i[2] = vertexremap[element[2]];
949 outelement3i[3] = vertexremap[element[2]] + 1;
950 outelement3i[4] = vertexremap[element[1]] + 1;
951 outelement3i[5] = vertexremap[element[0]] + 1;
955 // output the sides (facing outward from this triangle)
956 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
958 remappedelement[0] = vertexremap[element[0]];
959 remappedelement[1] = vertexremap[element[1]];
960 outelement3i[0] = remappedelement[1];
961 outelement3i[1] = remappedelement[0];
962 outelement3i[2] = remappedelement[0] + 1;
963 outelement3i[3] = remappedelement[1];
964 outelement3i[4] = remappedelement[0] + 1;
965 outelement3i[5] = remappedelement[1] + 1;
970 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
972 remappedelement[1] = vertexremap[element[1]];
973 remappedelement[2] = vertexremap[element[2]];
974 outelement3i[0] = remappedelement[2];
975 outelement3i[1] = remappedelement[1];
976 outelement3i[2] = remappedelement[1] + 1;
977 outelement3i[3] = remappedelement[2];
978 outelement3i[4] = remappedelement[1] + 1;
979 outelement3i[5] = remappedelement[2] + 1;
984 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
986 remappedelement[0] = vertexremap[element[0]];
987 remappedelement[2] = vertexremap[element[2]];
988 outelement3i[0] = remappedelement[0];
989 outelement3i[1] = remappedelement[2];
990 outelement3i[2] = remappedelement[2] + 1;
991 outelement3i[3] = remappedelement[0];
992 outelement3i[4] = remappedelement[2] + 1;
993 outelement3i[5] = remappedelement[0] + 1;
1002 for (i = 0;i < numshadowmarktris;i++)
1004 int remappedelement[3];
1006 const int *neighbortriangle;
1008 markindex = shadowmarktris[i] * 3;
1009 element = inelement3i + markindex;
1010 neighbortriangle = inneighbor3i + markindex;
1011 // output the front and back triangles
1012 outelement3i[0] = vertexremap[element[2]];
1013 outelement3i[1] = vertexremap[element[1]];
1014 outelement3i[2] = vertexremap[element[0]];
1015 outelement3i[3] = vertexremap[element[0]] + 1;
1016 outelement3i[4] = vertexremap[element[1]] + 1;
1017 outelement3i[5] = vertexremap[element[2]] + 1;
1021 // output the sides (facing outward from this triangle)
1022 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
1024 remappedelement[0] = vertexremap[element[0]];
1025 remappedelement[1] = vertexremap[element[1]];
1026 outelement3i[0] = remappedelement[0];
1027 outelement3i[1] = remappedelement[1];
1028 outelement3i[2] = remappedelement[1] + 1;
1029 outelement3i[3] = remappedelement[0];
1030 outelement3i[4] = remappedelement[1] + 1;
1031 outelement3i[5] = remappedelement[0] + 1;
1036 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1038 remappedelement[1] = vertexremap[element[1]];
1039 remappedelement[2] = vertexremap[element[2]];
1040 outelement3i[0] = remappedelement[1];
1041 outelement3i[1] = remappedelement[2];
1042 outelement3i[2] = remappedelement[2] + 1;
1043 outelement3i[3] = remappedelement[1];
1044 outelement3i[4] = remappedelement[2] + 1;
1045 outelement3i[5] = remappedelement[1] + 1;
1050 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1052 remappedelement[0] = vertexremap[element[0]];
1053 remappedelement[2] = vertexremap[element[2]];
1054 outelement3i[0] = remappedelement[2];
1055 outelement3i[1] = remappedelement[0];
1056 outelement3i[2] = remappedelement[0] + 1;
1057 outelement3i[3] = remappedelement[2];
1058 outelement3i[4] = remappedelement[0] + 1;
1059 outelement3i[5] = remappedelement[2] + 1;
1067 *outnumvertices = outvertices;
1068 return outtriangles;
1071 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)
1074 int outtriangles = 0, outvertices = 0;
1076 const float *vertex;
1077 float ratio, direction[3], projectvector[3];
1080 if (projectdirection)
1081 VectorScale(projectdirection, projectdistance, projectvector);
1083 VectorClear(projectvector);
1085 for (i = 0;i < numshadowmarktris;i++)
1087 int remappedelement[3];
1089 const int *neighbortriangle;
1091 markindex = shadowmarktris[i] * 3;
1092 neighbortriangle = inneighbor3i + markindex;
1093 side[0] = shadowmark[neighbortriangle[0]] == shadowmarkcount;
1094 side[1] = shadowmark[neighbortriangle[1]] == shadowmarkcount;
1095 side[2] = shadowmark[neighbortriangle[2]] == shadowmarkcount;
1096 if (side[0] + side[1] + side[2] == 0)
1100 element = inelement3i + markindex;
1102 // create the vertices
1103 for (j = 0;j < 3;j++)
1105 if (side[j] + side[j+1] == 0)
1108 if (vertexupdate[k] != vertexupdatenum)
1110 vertexupdate[k] = vertexupdatenum;
1111 vertexremap[k] = outvertices;
1112 vertex = invertex3f + k * 3;
1113 VectorCopy(vertex, outvertex3f);
1114 if (projectdirection)
1116 // project one copy of the vertex according to projectvector
1117 VectorAdd(vertex, projectvector, (outvertex3f + 3));
1121 // project one copy of the vertex to the sphere radius of the light
1122 // (FIXME: would projecting it to the light box be better?)
1123 VectorSubtract(vertex, projectorigin, direction);
1124 ratio = projectdistance / VectorLength(direction);
1125 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1132 // output the sides (facing outward from this triangle)
1135 remappedelement[0] = vertexremap[element[0]];
1136 remappedelement[1] = vertexremap[element[1]];
1137 outelement3i[0] = remappedelement[1];
1138 outelement3i[1] = remappedelement[0];
1139 outelement3i[2] = remappedelement[0] + 1;
1140 outelement3i[3] = remappedelement[1];
1141 outelement3i[4] = remappedelement[0] + 1;
1142 outelement3i[5] = remappedelement[1] + 1;
1149 remappedelement[1] = vertexremap[element[1]];
1150 remappedelement[2] = vertexremap[element[2]];
1151 outelement3i[0] = remappedelement[2];
1152 outelement3i[1] = remappedelement[1];
1153 outelement3i[2] = remappedelement[1] + 1;
1154 outelement3i[3] = remappedelement[2];
1155 outelement3i[4] = remappedelement[1] + 1;
1156 outelement3i[5] = remappedelement[2] + 1;
1163 remappedelement[0] = vertexremap[element[0]];
1164 remappedelement[2] = vertexremap[element[2]];
1165 outelement3i[0] = remappedelement[0];
1166 outelement3i[1] = remappedelement[2];
1167 outelement3i[2] = remappedelement[2] + 1;
1168 outelement3i[3] = remappedelement[0];
1169 outelement3i[4] = remappedelement[2] + 1;
1170 outelement3i[5] = remappedelement[0] + 1;
1177 *outnumvertices = outvertices;
1178 return outtriangles;
1181 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)
1187 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1189 tend = firsttriangle + numtris;
1190 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1192 // surface box entirely inside light box, no box cull
1193 if (projectdirection)
1195 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1197 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
1198 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1199 shadowmarklist[numshadowmark++] = t;
1204 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1205 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
1206 shadowmarklist[numshadowmark++] = t;
1211 // surface box not entirely inside light box, cull each triangle
1212 if (projectdirection)
1214 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1216 v[0] = invertex3f + e[0] * 3;
1217 v[1] = invertex3f + e[1] * 3;
1218 v[2] = invertex3f + e[2] * 3;
1219 TriangleNormal(v[0], v[1], v[2], normal);
1220 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1221 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1222 shadowmarklist[numshadowmark++] = t;
1227 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1229 v[0] = invertex3f + e[0] * 3;
1230 v[1] = invertex3f + e[1] * 3;
1231 v[2] = invertex3f + e[2] * 3;
1232 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1233 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1234 shadowmarklist[numshadowmark++] = t;
1240 qboolean R_Shadow_UseZPass(vec3_t mins, vec3_t maxs)
1245 if (r_shadow_compilingrtlight || !r_shadow_frontsidecasting.integer || !r_shadow_usezpassifpossible.integer)
1247 // check if the shadow volume intersects the near plane
1249 // a ray between the eye and light origin may intersect the caster,
1250 // indicating that the shadow may touch the eye location, however we must
1251 // test the near plane (a polygon), not merely the eye location, so it is
1252 // easiest to enlarge the caster bounding shape slightly for this.
1258 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)
1260 int i, tris, outverts;
1261 if (projectdistance < 0.1)
1263 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
1266 if (!numverts || !nummarktris)
1268 // make sure shadowelements is big enough for this volume
1269 if (maxshadowtriangles < nummarktris*8 || maxshadowvertices < numverts*2)
1270 R_Shadow_ResizeShadowArrays(numverts, nummarktris, 2, 8);
1272 if (maxvertexupdate < numverts)
1274 maxvertexupdate = numverts;
1276 Mem_Free(vertexupdate);
1278 Mem_Free(vertexremap);
1279 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1280 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1281 vertexupdatenum = 0;
1284 if (vertexupdatenum == 0)
1286 vertexupdatenum = 1;
1287 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
1288 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
1291 for (i = 0;i < nummarktris;i++)
1292 shadowmark[marktris[i]] = shadowmarkcount;
1294 if (r_shadow_compilingrtlight)
1296 // if we're compiling an rtlight, capture the mesh
1297 //tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1298 //Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zpass, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1299 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1300 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zfail, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1302 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
1304 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1305 R_Mesh_VertexPointer(shadowvertex3f, 0, 0);
1306 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1310 // decide which type of shadow to generate and set stencil mode
1311 R_Shadow_RenderMode_StencilShadowVolumes(R_Shadow_UseZPass(trismins, trismaxs));
1312 // generate the sides or a solid volume, depending on type
1313 if (r_shadow_rendermode >= R_SHADOW_RENDERMODE_ZPASS_STENCIL && r_shadow_rendermode <= R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE)
1314 tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1316 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1317 r_refdef.stats.lights_dynamicshadowtriangles += tris;
1318 r_refdef.stats.lights_shadowtriangles += tris;
1320 R_Mesh_VertexPointer(shadowvertex3f, 0, 0);
1321 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
1323 // increment stencil if frontface is infront of depthbuffer
1324 GL_CullFace(r_refdef.view.cullface_front);
1325 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1326 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1327 // decrement stencil if backface is infront of depthbuffer
1328 GL_CullFace(r_refdef.view.cullface_back);
1329 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1331 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
1333 // decrement stencil if backface is behind depthbuffer
1334 GL_CullFace(r_refdef.view.cullface_front);
1335 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1336 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1337 // increment stencil if frontface is behind depthbuffer
1338 GL_CullFace(r_refdef.view.cullface_back);
1339 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1341 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1346 int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias)
1348 // p1, p2, p3 are in the cubemap's local coordinate system
1349 // bias = border/(size - border)
1352 float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1353 dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2),
1354 dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3);
1355 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1357 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1358 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1359 | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1360 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1362 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1363 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1364 | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1366 dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1367 dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2),
1368 dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3);
1369 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1371 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1372 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1373 | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1374 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1376 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1377 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1378 | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1380 dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1381 dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2),
1382 dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3);
1383 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1385 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1386 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1387 | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1388 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1390 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1391 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1392 | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1397 int R_Shadow_CalcBBoxSideMask(const vec3_t mins, const vec3_t maxs, const matrix4x4_t *worldtolight, const matrix4x4_t *radiustolight, float bias)
1399 vec3_t center, radius, lightcenter, lightradius, pmin, pmax;
1400 float dp1, dn1, ap1, an1, dp2, dn2, ap2, an2;
1403 VectorSubtract(maxs, mins, radius);
1404 VectorScale(radius, 0.5f, radius);
1405 VectorAdd(mins, radius, center);
1406 Matrix4x4_Transform(worldtolight, center, lightcenter);
1407 Matrix4x4_Transform3x3(radiustolight, radius, lightradius);
1408 VectorSubtract(lightcenter, lightradius, pmin);
1409 VectorAdd(lightcenter, lightradius, pmax);
1411 dp1 = pmax[0] + pmax[1], dn1 = pmax[0] - pmin[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1412 dp2 = pmin[0] + pmin[1], dn2 = pmin[0] - pmax[1], ap2 = fabs(dp2), an2 = fabs(dn2);
1413 if(ap1 > bias*an1 && ap2 > bias*an2)
1415 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1416 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1417 if(an1 > bias*ap1 && an2 > bias*ap2)
1419 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1420 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1422 dp1 = pmax[1] + pmax[2], dn1 = pmax[1] - pmin[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1423 dp2 = pmin[1] + pmin[2], dn2 = pmin[1] - pmax[2], ap2 = fabs(dp2), an2 = fabs(dn2);
1424 if(ap1 > bias*an1 && ap2 > bias*an2)
1426 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1427 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1428 if(an1 > bias*ap1 && an2 > bias*ap2)
1430 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1431 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1433 dp1 = pmax[2] + pmax[0], dn1 = pmax[2] - pmin[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1434 dp2 = pmin[2] + pmin[0], dn2 = pmin[2] - pmax[0], ap2 = fabs(dp2), an2 = fabs(dn2);
1435 if(ap1 > bias*an1 && ap2 > bias*an2)
1437 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1438 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1439 if(an1 > bias*ap1 && an2 > bias*ap2)
1441 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1442 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1447 #define R_Shadow_CalcEntitySideMask(ent, worldtolight, radiustolight, bias) R_Shadow_CalcBBoxSideMask((ent)->mins, (ent)->maxs, worldtolight, radiustolight, bias)
1449 int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
1451 // p is in the cubemap's local coordinate system
1452 // bias = border/(size - border)
1453 float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn);
1454 float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn);
1455 float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn);
1457 if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
1458 if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
1459 if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
1460 if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
1461 if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
1462 if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
1466 int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
1470 int sides = 0x3F, masks[6] = { 3<<4, 3<<4, 3<<0, 3<<0, 3<<2, 3<<2 };
1471 float scale = (size - 2*border)/size, len;
1472 float bias = border / (float)(size - border), dp, dn, ap, an;
1473 // check if cone enclosing side would cross frustum plane
1474 scale = 2 / (scale*scale + 2);
1475 for (i = 0;i < 5;i++)
1477 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) > -0.03125)
1479 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[i].normal, n);
1480 len = scale*VectorLength2(n);
1481 if(n[0]*n[0] > len) sides &= n[0] < 0 ? ~(1<<0) : ~(2 << 0);
1482 if(n[1]*n[1] > len) sides &= n[1] < 0 ? ~(1<<2) : ~(2 << 2);
1483 if(n[2]*n[2] > len) sides &= n[2] < 0 ? ~(1<<4) : ~(2 << 4);
1485 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[4]) >= r_refdef.farclip - r_refdef.nearclip + 0.03125)
1487 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[4].normal, n);
1488 len = scale*VectorLength(n);
1489 if(n[0]*n[0] > len) sides &= n[0] >= 0 ? ~(1<<0) : ~(2 << 0);
1490 if(n[1]*n[1] > len) sides &= n[1] >= 0 ? ~(1<<2) : ~(2 << 2);
1491 if(n[2]*n[2] > len) sides &= n[2] >= 0 ? ~(1<<4) : ~(2 << 4);
1493 // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results
1494 // check if frustum corners/origin cross plane sides
1495 for (i = 0;i < 5;i++)
1497 Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p);
1498 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn),
1499 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1500 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1501 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn),
1502 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1503 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1504 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn),
1505 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1506 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1508 return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5];
1511 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)
1519 int mask, surfacemask = 0;
1520 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1522 bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
1523 tend = firsttriangle + numtris;
1524 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1526 // surface box entirely inside light box, no box cull
1527 if (projectdirection)
1529 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1531 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1532 TriangleNormal(v[0], v[1], v[2], normal);
1533 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1535 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1536 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1537 surfacemask |= mask;
1540 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;
1541 shadowsides[numshadowsides] = mask;
1542 shadowsideslist[numshadowsides++] = t;
1549 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1551 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1552 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]))
1554 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1555 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1556 surfacemask |= mask;
1559 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;
1560 shadowsides[numshadowsides] = mask;
1561 shadowsideslist[numshadowsides++] = t;
1569 // surface box not entirely inside light box, cull each triangle
1570 if (projectdirection)
1572 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1574 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1575 TriangleNormal(v[0], v[1], v[2], normal);
1576 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1577 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1579 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1580 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1581 surfacemask |= mask;
1584 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;
1585 shadowsides[numshadowsides] = mask;
1586 shadowsideslist[numshadowsides++] = t;
1593 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1595 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1596 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1597 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1599 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1600 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1601 surfacemask |= mask;
1604 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;
1605 shadowsides[numshadowsides] = mask;
1606 shadowsideslist[numshadowsides++] = t;
1615 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)
1617 int i, j, outtriangles = 0;
1618 int *outelement3i[6];
1619 if (!numverts || !numsidetris || !r_shadow_compilingrtlight)
1621 outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5];
1622 // make sure shadowelements is big enough for this mesh
1623 if (maxshadowtriangles < outtriangles)
1624 R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1);
1626 // compute the offset and size of the separate index lists for each cubemap side
1628 for (i = 0;i < 6;i++)
1630 outelement3i[i] = shadowelements + outtriangles * 3;
1631 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles;
1632 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i];
1633 outtriangles += sidetotals[i];
1636 // gather up the (sparse) triangles into separate index lists for each cubemap side
1637 for (i = 0;i < numsidetris;i++)
1639 const int *element = elements + sidetris[i] * 3;
1640 for (j = 0;j < 6;j++)
1642 if (sides[i] & (1 << j))
1644 outelement3i[j][0] = element[0];
1645 outelement3i[j][1] = element[1];
1646 outelement3i[j][2] = element[2];
1647 outelement3i[j] += 3;
1652 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, outtriangles, shadowelements);
1655 static void R_Shadow_MakeTextures_MakeCorona(void)
1659 unsigned char pixels[32][32][4];
1660 for (y = 0;y < 32;y++)
1662 dy = (y - 15.5f) * (1.0f / 16.0f);
1663 for (x = 0;x < 32;x++)
1665 dx = (x - 15.5f) * (1.0f / 16.0f);
1666 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1667 a = bound(0, a, 255);
1668 pixels[y][x][0] = a;
1669 pixels[y][x][1] = a;
1670 pixels[y][x][2] = a;
1671 pixels[y][x][3] = 255;
1674 r_shadow_lightcorona = R_SkinFrame_LoadInternalBGRA("lightcorona", TEXF_FORCELINEAR, &pixels[0][0][0], 32, 32);
1677 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1679 float dist = sqrt(x*x+y*y+z*z);
1680 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1681 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1682 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1685 static void R_Shadow_MakeTextures(void)
1688 float intensity, dist;
1690 R_Shadow_FreeShadowMaps();
1691 R_FreeTexturePool(&r_shadow_texturepool);
1692 r_shadow_texturepool = R_AllocTexturePool();
1693 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1694 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1695 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1696 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1697 for (x = 0;x <= ATTENTABLESIZE;x++)
1699 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1700 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1701 r_shadow_attentable[x] = bound(0, intensity, 1);
1703 // 1D gradient texture
1704 for (x = 0;x < ATTEN1DSIZE;x++)
1705 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1706 r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, NULL);
1707 // 2D circle texture
1708 for (y = 0;y < ATTEN2DSIZE;y++)
1709 for (x = 0;x < ATTEN2DSIZE;x++)
1710 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);
1711 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, NULL);
1712 // 3D sphere texture
1713 if (r_shadow_texture3d.integer && vid.support.ext_texture_3d)
1715 for (z = 0;z < ATTEN3DSIZE;z++)
1716 for (y = 0;y < ATTEN3DSIZE;y++)
1717 for (x = 0;x < ATTEN3DSIZE;x++)
1718 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));
1719 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, NULL);
1722 r_shadow_attenuation3dtexture = NULL;
1725 R_Shadow_MakeTextures_MakeCorona();
1727 // Editor light sprites
1728 r_editlights_sprcursor = R_SkinFrame_LoadInternal8bit("gfx/editlights/cursor", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1745 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1746 r_editlights_sprlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/light", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1763 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1764 r_editlights_sprnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/noshadow", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1781 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1782 r_editlights_sprcubemaplight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemaplight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1799 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1800 r_editlights_sprcubemapnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemapnoshadowlight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1817 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1818 r_editlights_sprselection = R_SkinFrame_LoadInternal8bit("gfx/editlights/selection", TEXF_ALPHA | TEXF_CLAMP, (unsigned char *)
1835 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1838 void R_Shadow_ValidateCvars(void)
1840 if (r_shadow_texture3d.integer && !vid.support.ext_texture_3d)
1841 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1842 if (gl_ext_separatestencil.integer && !vid.support.ati_separate_stencil)
1843 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
1844 if (gl_ext_stenciltwoside.integer && !vid.support.ext_stencil_two_side)
1845 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1848 void R_Shadow_RenderMode_Begin(void)
1854 R_Shadow_ValidateCvars();
1856 if (!r_shadow_attenuation2dtexture
1857 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1858 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1859 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1860 R_Shadow_MakeTextures();
1863 R_Mesh_ColorPointer(NULL, 0, 0);
1864 R_Mesh_ResetTextureState();
1865 GL_BlendFunc(GL_ONE, GL_ZERO);
1866 GL_DepthRange(0, 1);
1867 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1869 GL_DepthMask(false);
1870 GL_Color(0, 0, 0, 1);
1871 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1873 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1875 if (gl_ext_separatestencil.integer && vid.support.ati_separate_stencil)
1877 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
1878 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
1880 else if (gl_ext_stenciltwoside.integer && vid.support.ext_stencil_two_side)
1882 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
1883 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
1887 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
1888 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
1891 switch(vid.renderpath)
1893 case RENDERPATH_GL20:
1894 case RENDERPATH_CGGL:
1895 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1897 case RENDERPATH_GL13:
1898 case RENDERPATH_GL11:
1899 if (r_textureunits.integer >= 2 && vid.texunits >= 2 && r_shadow_texture3d.integer && r_shadow_attenuation3dtexture)
1900 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN;
1901 else if (r_textureunits.integer >= 3 && vid.texunits >= 3)
1902 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN;
1903 else if (r_textureunits.integer >= 2 && vid.texunits >= 2)
1904 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN;
1906 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1912 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
1913 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
1914 r_shadow_drawbuffer = drawbuffer;
1915 r_shadow_readbuffer = readbuffer;
1917 r_shadow_cullface_front = r_refdef.view.cullface_front;
1918 r_shadow_cullface_back = r_refdef.view.cullface_back;
1921 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
1923 rsurface.rtlight = rtlight;
1926 void R_Shadow_RenderMode_Reset(void)
1929 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE)
1931 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1933 if (vid.support.ext_framebuffer_object)
1935 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);CHECKGLERROR
1938 qglDrawBuffer(r_shadow_drawbuffer);CHECKGLERROR
1939 qglReadBuffer(r_shadow_readbuffer);CHECKGLERROR
1941 R_SetViewport(&r_refdef.view.viewport);
1942 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
1943 R_Mesh_ColorPointer(NULL, 0, 0);
1944 R_Mesh_ResetTextureState();
1945 GL_DepthRange(0, 1);
1947 GL_DepthMask(false);
1948 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1949 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1950 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
1951 qglStencilMask(255);CHECKGLERROR
1952 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
1953 qglStencilFunc(GL_ALWAYS, 128, 255);CHECKGLERROR
1954 r_refdef.view.cullface_front = r_shadow_cullface_front;
1955 r_refdef.view.cullface_back = r_shadow_cullface_back;
1956 GL_CullFace(r_refdef.view.cullface_back);
1957 GL_Color(1, 1, 1, 1);
1958 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
1959 GL_BlendFunc(GL_ONE, GL_ZERO);
1960 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
1961 r_shadow_usingshadowmaprect = false;
1962 r_shadow_usingshadowmapcube = false;
1963 r_shadow_usingshadowmap2d = false;
1967 void R_Shadow_ClearStencil(void)
1970 GL_Clear(GL_STENCIL_BUFFER_BIT);
1971 r_refdef.stats.lights_clears++;
1974 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
1976 r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
1977 if (r_shadow_rendermode == mode)
1980 R_Shadow_RenderMode_Reset();
1981 GL_ColorMask(0, 0, 0, 0);
1982 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1983 R_SetupShader_DepthOrShadow();
1984 qglDepthFunc(GL_LESS);CHECKGLERROR
1985 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1986 r_shadow_rendermode = mode;
1991 case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
1992 GL_CullFace(GL_NONE);
1993 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1994 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1996 case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
1997 GL_CullFace(GL_NONE);
1998 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1999 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
2001 case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
2002 GL_CullFace(GL_NONE);
2003 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
2004 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
2005 qglStencilMask(255);CHECKGLERROR
2006 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
2007 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
2008 qglStencilMask(255);CHECKGLERROR
2009 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
2011 case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
2012 GL_CullFace(GL_NONE);
2013 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
2014 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
2015 qglStencilMask(255);CHECKGLERROR
2016 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
2017 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
2018 qglStencilMask(255);CHECKGLERROR
2019 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
2024 static void R_Shadow_MakeVSDCT(void)
2026 // maps to a 2x3 texture rectangle with normalized coordinates
2031 // stores abs(dir.xy), offset.xy/2.5
2032 unsigned char data[4*6] =
2034 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
2035 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
2036 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
2037 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
2038 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
2039 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
2041 r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, NULL);
2044 static void R_Shadow_MakeShadowMap(int side, int size)
2047 switch (r_shadow_shadowmode)
2049 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2050 if (r_shadow_shadowmap2dtexture) return;
2051 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);
2052 qglGenFramebuffersEXT(1, &r_shadow_fbo2d);CHECKGLERROR
2053 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbo2d);CHECKGLERROR
2054 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_shadowmap2dtexture), 0);CHECKGLERROR
2056 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
2057 if (r_shadow_shadowmaprectangletexture) return;
2058 r_shadow_shadowmaprectangletexture = R_LoadTextureShadowMapRectangle(r_shadow_texturepool, "shadowmap", size*2, size*3, r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
2059 qglGenFramebuffersEXT(1, &r_shadow_fborectangle);CHECKGLERROR
2060 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fborectangle);CHECKGLERROR
2061 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, R_GetTexture(r_shadow_shadowmaprectangletexture), 0);CHECKGLERROR
2063 case R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE:
2064 if (r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]) return;
2065 r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod] = R_LoadTextureShadowMapCube(r_shadow_texturepool, "shadowmapcube", size, r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
2066 qglGenFramebuffersEXT(1, &r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR
2067 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR
2068 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
2073 // render depth into the fbo, do not render color at all
2074 qglDrawBuffer(GL_NONE);CHECKGLERROR
2075 qglReadBuffer(GL_NONE);CHECKGLERROR
2076 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2077 if (status != GL_FRAMEBUFFER_COMPLETE_EXT && (r_shadow_shadowmapping.integer || r_shadow_deferred.integer))
2079 Con_Printf("R_Shadow_MakeShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2080 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2081 Cvar_SetValueQuick(&r_shadow_deferred, 0);
2085 void R_Shadow_RenderMode_ShadowMap(int side, int clear, int size)
2087 float nearclip, farclip, bias;
2088 r_viewport_t viewport;
2091 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
2093 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
2094 r_shadow_shadowmap_parameters[2] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
2095 r_shadow_shadowmap_parameters[3] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
2096 r_shadow_shadowmapside = side;
2097 r_shadow_shadowmapsize = size;
2098 switch (r_shadow_shadowmode)
2100 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2101 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2102 r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2103 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
2104 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D) goto init_done;
2106 // complex unrolled cube approach (more flexible)
2107 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2108 R_Shadow_MakeVSDCT();
2109 if (!r_shadow_shadowmap2dtexture)
2110 R_Shadow_MakeShadowMap(side, r_shadow_shadowmapmaxsize);
2112 if (r_shadow_shadowmap2dtexture) fbo = r_shadow_fbo2d;
2113 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
2114 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
2115 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
2117 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
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_SHADOWMAPRECTANGLE) 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_shadowmaprectangletexture)
2127 R_Shadow_MakeShadowMap(side, r_shadow_shadowmapmaxsize);
2129 if(r_shadow_shadowmaprectangletexture) fbo = r_shadow_fborectangle;
2130 r_shadow_shadowmap_texturescale[0] = 1.0f;
2131 r_shadow_shadowmap_texturescale[1] = 1.0f;
2132 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE;
2134 case R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE:
2135 r_shadow_shadowmap_parameters[0] = 1.0f;
2136 r_shadow_shadowmap_parameters[1] = 1.0f;
2137 R_Viewport_InitCubeSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, nearclip, farclip, NULL);
2138 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE) goto init_done;
2140 // simple cube approach
2141 if (!r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod])
2142 R_Shadow_MakeShadowMap(side, size);
2144 if (r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]) fbo = r_shadow_fbocubeside[r_shadow_shadowmaplod];
2145 r_shadow_shadowmap_texturescale[0] = 0.0f;
2146 r_shadow_shadowmap_texturescale[1] = 0.0f;
2147 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE;
2153 R_Shadow_RenderMode_Reset();
2156 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);CHECKGLERROR
2157 R_SetupShader_DepthOrShadow();
2161 R_SetupShader_ShowDepth();
2162 qglClearColor(1,1,1,1);CHECKGLERROR
2165 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
2172 R_SetViewport(&viewport);
2173 if(r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE)
2175 int flipped = (side & 1) ^ (side >> 2);
2176 r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
2177 r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
2178 GL_CullFace(r_refdef.view.cullface_back);
2179 if ((clear & ((2 << side) - 1)) == (1 << side)) // only clear if the side is the first in the mask
2181 // get tightest scissor rectangle that encloses all viewports in the clear mask
2182 int x1 = clear & 0x15 ? 0 : size;
2183 int x2 = clear & 0x2A ? 2 * size : size;
2184 int y1 = clear & 0x03 ? 0 : (clear & 0xC ? size : 2 * size);
2185 int y2 = clear & 0x30 ? 3 * size : (clear & 0xC ? 2 * size : size);
2186 GL_Scissor(x1, y1, x2 - x1, y2 - y1);
2187 GL_Clear(GL_DEPTH_BUFFER_BIT);
2189 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2191 else if(r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE)
2193 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
2194 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2196 GL_Clear(GL_DEPTH_BUFFER_BIT);
2201 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
2205 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2206 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2207 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2208 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2211 R_Shadow_RenderMode_Reset();
2212 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2215 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2219 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2220 // only draw light where this geometry was already rendered AND the
2221 // stencil is 128 (values other than this mean shadow)
2222 qglStencilFunc(GL_EQUAL, 128, 255);CHECKGLERROR
2224 r_shadow_rendermode = r_shadow_lightingrendermode;
2225 // do global setup needed for the chosen lighting mode
2226 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2228 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2233 if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
2234 r_shadow_usingshadowmap2d = true;
2235 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE)
2236 r_shadow_usingshadowmaprect = true;
2237 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
2238 r_shadow_usingshadowmapcube = true;
2240 R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
2244 static const unsigned short bboxelements[36] =
2254 static const float bboxpoints[8][3] =
2266 void R_Shadow_RenderMode_DrawDeferredLight(qboolean stenciltest, qboolean shadowmapping)
2269 float vertex3f[8*3];
2270 const matrix4x4_t *matrix = &rsurface.rtlight->matrix_lighttoworld;
2272 R_Shadow_RenderMode_Reset();
2273 r_shadow_rendermode = r_shadow_lightingrendermode;
2274 // do global setup needed for the chosen lighting mode
2276 R_EntityMatrix(&identitymatrix);
2277 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2280 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2281 // only draw light where this geometry was already rendered AND the
2282 // stencil is 128 (values other than this mean shadow)
2283 qglStencilFunc(GL_EQUAL, 128, 255);CHECKGLERROR
2285 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepasslightingfbo);CHECKGLERROR
2288 if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
2289 r_shadow_usingshadowmap2d = true;
2290 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE)
2291 r_shadow_usingshadowmaprect = true;
2292 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
2293 r_shadow_usingshadowmapcube = true;
2296 // render the lighting
2297 R_SetupShader_DeferredLight(rsurface.rtlight);
2298 for (i = 0;i < 8;i++)
2299 Matrix4x4_Transform(matrix, bboxpoints[i], vertex3f + i*3);
2301 R_Mesh_VertexPointer(vertex3f, 0, 0);
2302 R_Mesh_ColorPointer(NULL, 0, 0);
2303 GL_ColorMask(1,1,1,1);
2304 GL_DepthMask(false);
2305 GL_DepthRange(0, 1);
2306 GL_PolygonOffset(0, 0);
2308 qglDepthFunc(GL_GREATER);CHECKGLERROR
2309 GL_CullFace(r_refdef.view.cullface_back);
2310 R_Mesh_Draw(0, 8, 0, 12, NULL, bboxelements, 0, 0);
2314 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
2317 R_Shadow_RenderMode_Reset();
2318 GL_BlendFunc(GL_ONE, GL_ONE);
2319 GL_DepthRange(0, 1);
2320 GL_DepthTest(r_showshadowvolumes.integer < 2);
2321 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
2322 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2323 GL_CullFace(GL_NONE);
2324 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
2327 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
2330 R_Shadow_RenderMode_Reset();
2331 GL_BlendFunc(GL_ONE, GL_ONE);
2332 GL_DepthRange(0, 1);
2333 GL_DepthTest(r_showlighting.integer < 2);
2334 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2337 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2341 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2342 qglStencilFunc(GL_EQUAL, 128, 255);CHECKGLERROR
2344 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2347 void R_Shadow_RenderMode_End(void)
2350 R_Shadow_RenderMode_Reset();
2351 R_Shadow_RenderMode_ActiveLight(NULL);
2353 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2354 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2357 int bboxedges[12][2] =
2376 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2378 int i, ix1, iy1, ix2, iy2;
2379 float x1, y1, x2, y2;
2381 float vertex[20][3];
2390 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2391 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2392 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2393 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2395 if (!r_shadow_scissor.integer)
2398 // if view is inside the light box, just say yes it's visible
2399 if (BoxesOverlap(r_refdef.view.origin, r_refdef.view.origin, mins, maxs))
2402 x1 = y1 = x2 = y2 = 0;
2404 // transform all corners that are infront of the nearclip plane
2405 VectorNegate(r_refdef.view.frustum[4].normal, plane4f);
2406 plane4f[3] = r_refdef.view.frustum[4].dist;
2408 for (i = 0;i < 8;i++)
2410 Vector4Set(corner[i], (i & 1) ? maxs[0] : mins[0], (i & 2) ? maxs[1] : mins[1], (i & 4) ? maxs[2] : mins[2], 1);
2411 dist[i] = DotProduct4(corner[i], plane4f);
2412 sign[i] = dist[i] > 0;
2415 VectorCopy(corner[i], vertex[numvertices]);
2419 // if some points are behind the nearclip, add clipped edge points to make
2420 // sure that the scissor boundary is complete
2421 if (numvertices > 0 && numvertices < 8)
2423 // add clipped edge points
2424 for (i = 0;i < 12;i++)
2426 j = bboxedges[i][0];
2427 k = bboxedges[i][1];
2428 if (sign[j] != sign[k])
2430 f = dist[j] / (dist[j] - dist[k]);
2431 VectorLerp(corner[j], f, corner[k], vertex[numvertices]);
2437 // if we have no points to check, the light is behind the view plane
2441 // if we have some points to transform, check what screen area is covered
2442 x1 = y1 = x2 = y2 = 0;
2444 //Con_Printf("%i vertices to transform...\n", numvertices);
2445 for (i = 0;i < numvertices;i++)
2447 VectorCopy(vertex[i], v);
2448 R_Viewport_TransformToScreen(&r_refdef.view.viewport, v, v2);
2449 //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]);
2452 if (x1 > v2[0]) x1 = v2[0];
2453 if (x2 < v2[0]) x2 = v2[0];
2454 if (y1 > v2[1]) y1 = v2[1];
2455 if (y2 < v2[1]) y2 = v2[1];
2464 // now convert the scissor rectangle to integer screen coordinates
2465 ix1 = (int)(x1 - 1.0f);
2466 iy1 = vid.height - (int)(y2 - 1.0f);
2467 ix2 = (int)(x2 + 1.0f);
2468 iy2 = vid.height - (int)(y1 + 1.0f);
2469 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
2471 // clamp it to the screen
2472 if (ix1 < r_refdef.view.viewport.x) ix1 = r_refdef.view.viewport.x;
2473 if (iy1 < r_refdef.view.viewport.y) iy1 = r_refdef.view.viewport.y;
2474 if (ix2 > r_refdef.view.viewport.x + r_refdef.view.viewport.width) ix2 = r_refdef.view.viewport.x + r_refdef.view.viewport.width;
2475 if (iy2 > r_refdef.view.viewport.y + r_refdef.view.viewport.height) iy2 = r_refdef.view.viewport.y + r_refdef.view.viewport.height;
2477 // if it is inside out, it's not visible
2478 if (ix2 <= ix1 || iy2 <= iy1)
2481 // the light area is visible, set up the scissor rectangle
2482 r_shadow_lightscissor[0] = ix1;
2483 r_shadow_lightscissor[1] = iy1;
2484 r_shadow_lightscissor[2] = ix2 - ix1;
2485 r_shadow_lightscissor[3] = iy2 - iy1;
2487 r_refdef.stats.lights_scissored++;
2491 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, int numtriangles, const int *element3i, const float *diffusecolor, const float *ambientcolor)
2493 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
2494 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
2495 float *color4f = rsurface.array_color4f + 4 * firstvertex;
2496 float dist, dot, distintensity, shadeintensity, v[3], n[3];
2497 switch (r_shadow_rendermode)
2499 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2500 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2501 if (VectorLength2(diffusecolor) > 0)
2503 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2505 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2506 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2507 if ((dot = DotProduct(n, v)) < 0)
2509 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2510 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
2513 VectorCopy(ambientcolor, color4f);
2514 if (r_refdef.fogenabled)
2517 f = RSurf_FogVertex(vertex3f);
2518 VectorScale(color4f, f, color4f);
2525 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2527 VectorCopy(ambientcolor, color4f);
2528 if (r_refdef.fogenabled)
2531 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2532 f = RSurf_FogVertex(vertex3f);
2533 VectorScale(color4f, f, color4f);
2539 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2540 if (VectorLength2(diffusecolor) > 0)
2542 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2544 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2545 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2547 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2548 if ((dot = DotProduct(n, v)) < 0)
2550 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2551 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2552 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2553 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2557 color4f[0] = ambientcolor[0] * distintensity;
2558 color4f[1] = ambientcolor[1] * distintensity;
2559 color4f[2] = ambientcolor[2] * distintensity;
2561 if (r_refdef.fogenabled)
2564 f = RSurf_FogVertex(vertex3f);
2565 VectorScale(color4f, f, color4f);
2569 VectorClear(color4f);
2575 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2577 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2578 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2580 color4f[0] = ambientcolor[0] * distintensity;
2581 color4f[1] = ambientcolor[1] * distintensity;
2582 color4f[2] = ambientcolor[2] * distintensity;
2583 if (r_refdef.fogenabled)
2586 f = RSurf_FogVertex(vertex3f);
2587 VectorScale(color4f, f, color4f);
2591 VectorClear(color4f);
2596 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2597 if (VectorLength2(diffusecolor) > 0)
2599 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2601 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2602 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2604 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2605 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2606 if ((dot = DotProduct(n, v)) < 0)
2608 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2609 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2610 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2611 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2615 color4f[0] = ambientcolor[0] * distintensity;
2616 color4f[1] = ambientcolor[1] * distintensity;
2617 color4f[2] = ambientcolor[2] * distintensity;
2619 if (r_refdef.fogenabled)
2622 f = RSurf_FogVertex(vertex3f);
2623 VectorScale(color4f, f, color4f);
2627 VectorClear(color4f);
2633 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2635 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2636 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2638 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2639 color4f[0] = ambientcolor[0] * distintensity;
2640 color4f[1] = ambientcolor[1] * distintensity;
2641 color4f[2] = ambientcolor[2] * distintensity;
2642 if (r_refdef.fogenabled)
2645 f = RSurf_FogVertex(vertex3f);
2646 VectorScale(color4f, f, color4f);
2650 VectorClear(color4f);
2660 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)
2662 // used to display how many times a surface is lit for level design purposes
2663 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2666 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)
2668 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2669 R_SetupShader_Surface(lightcolor, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT);
2670 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2672 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2674 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2675 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2677 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
2681 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
2688 int newnumtriangles;
2692 int maxtriangles = 4096;
2693 static int newelements[4096*3];
2694 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, numtriangles, element3i, diffusecolor2, ambientcolor2);
2695 for (renders = 0;renders < 4;renders++)
2700 newnumtriangles = 0;
2702 // due to low fillrate on the cards this vertex lighting path is
2703 // designed for, we manually cull all triangles that do not
2704 // contain a lit vertex
2705 // this builds batches of triangles from multiple surfaces and
2706 // renders them at once
2707 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
2709 if (VectorLength2(rsurface.array_color4f + e[0] * 4) + VectorLength2(rsurface.array_color4f + e[1] * 4) + VectorLength2(rsurface.array_color4f + e[2] * 4) >= 0.01)
2711 if (newnumtriangles)
2713 newfirstvertex = min(newfirstvertex, e[0]);
2714 newlastvertex = max(newlastvertex, e[0]);
2718 newfirstvertex = e[0];
2719 newlastvertex = e[0];
2721 newfirstvertex = min(newfirstvertex, e[1]);
2722 newlastvertex = max(newlastvertex, e[1]);
2723 newfirstvertex = min(newfirstvertex, e[2]);
2724 newlastvertex = max(newlastvertex, e[2]);
2730 if (newnumtriangles >= maxtriangles)
2732 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
2733 newnumtriangles = 0;
2739 if (newnumtriangles >= 1)
2741 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
2744 // if we couldn't find any lit triangles, exit early
2747 // now reduce the intensity for the next overbright pass
2748 // we have to clamp to 0 here incase the drivers have improper
2749 // handling of negative colors
2750 // (some old drivers even have improper handling of >1 color)
2752 for (i = 0, c = rsurface.array_color4f + 4 * firstvertex;i < numvertices;i++, c += 4)
2754 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
2756 c[0] = max(0, c[0] - 1);
2757 c[1] = max(0, c[1] - 1);
2758 c[2] = max(0, c[2] - 1);
2770 static void R_Shadow_RenderLighting_Light_Vertex(int firstvertex, int numvertices, int numtriangles, const int *element3i, const vec3_t lightcolor, float ambientscale, float diffusescale)
2772 // OpenGL 1.1 path (anything)
2773 float ambientcolorbase[3], diffusecolorbase[3];
2774 float ambientcolorpants[3], diffusecolorpants[3];
2775 float ambientcolorshirt[3], diffusecolorshirt[3];
2776 const float *surfacecolor = rsurface.texture->dlightcolor;
2777 const float *surfacepants = rsurface.colormap_pantscolor;
2778 const float *surfaceshirt = rsurface.colormap_shirtcolor;
2779 rtexture_t *basetexture = rsurface.texture->basetexture;
2780 rtexture_t *pantstexture = rsurface.texture->pantstexture;
2781 rtexture_t *shirttexture = rsurface.texture->shirttexture;
2782 qboolean dopants = pantstexture && VectorLength2(surfacepants) >= (1.0f / 1048576.0f);
2783 qboolean doshirt = shirttexture && VectorLength2(surfaceshirt) >= (1.0f / 1048576.0f);
2784 ambientscale *= 2 * r_refdef.view.colorscale;
2785 diffusescale *= 2 * r_refdef.view.colorscale;
2786 ambientcolorbase[0] = lightcolor[0] * ambientscale * surfacecolor[0];ambientcolorbase[1] = lightcolor[1] * ambientscale * surfacecolor[1];ambientcolorbase[2] = lightcolor[2] * ambientscale * surfacecolor[2];
2787 diffusecolorbase[0] = lightcolor[0] * diffusescale * surfacecolor[0];diffusecolorbase[1] = lightcolor[1] * diffusescale * surfacecolor[1];diffusecolorbase[2] = lightcolor[2] * diffusescale * surfacecolor[2];
2788 ambientcolorpants[0] = ambientcolorbase[0] * surfacepants[0];ambientcolorpants[1] = ambientcolorbase[1] * surfacepants[1];ambientcolorpants[2] = ambientcolorbase[2] * surfacepants[2];
2789 diffusecolorpants[0] = diffusecolorbase[0] * surfacepants[0];diffusecolorpants[1] = diffusecolorbase[1] * surfacepants[1];diffusecolorpants[2] = diffusecolorbase[2] * surfacepants[2];
2790 ambientcolorshirt[0] = ambientcolorbase[0] * surfaceshirt[0];ambientcolorshirt[1] = ambientcolorbase[1] * surfaceshirt[1];ambientcolorshirt[2] = ambientcolorbase[2] * surfaceshirt[2];
2791 diffusecolorshirt[0] = diffusecolorbase[0] * surfaceshirt[0];diffusecolorshirt[1] = diffusecolorbase[1] * surfaceshirt[1];diffusecolorshirt[2] = diffusecolorbase[2] * surfaceshirt[2];
2792 R_Mesh_TexBind(0, basetexture);
2793 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
2794 R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
2795 R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
2796 switch(r_shadow_rendermode)
2798 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2799 R_Mesh_TexBind(1, r_shadow_attenuation3dtexture);
2800 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
2801 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
2802 R_Mesh_TexCoordPointer(1, 3, rsurface.vertex3f, rsurface.vertex3f_bufferobject, rsurface.vertex3f_bufferoffset);
2804 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2805 R_Mesh_TexBind(2, r_shadow_attenuation2dtexture);
2806 R_Mesh_TexMatrix(2, &rsurface.entitytoattenuationz);
2807 R_Mesh_TexCombine(2, GL_MODULATE, GL_MODULATE, 1, 1);
2808 R_Mesh_TexCoordPointer(2, 3, rsurface.vertex3f, rsurface.vertex3f_bufferobject, rsurface.vertex3f_bufferoffset);
2810 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2811 R_Mesh_TexBind(1, r_shadow_attenuation2dtexture);
2812 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
2813 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
2814 R_Mesh_TexCoordPointer(1, 3, rsurface.vertex3f, rsurface.vertex3f_bufferobject, rsurface.vertex3f_bufferoffset);
2816 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2821 //R_Mesh_TexBind(0, basetexture);
2822 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorbase, ambientcolorbase);
2825 R_Mesh_TexBind(0, pantstexture);
2826 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorpants, ambientcolorpants);
2830 R_Mesh_TexBind(0, shirttexture);
2831 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorshirt, ambientcolorshirt);
2835 extern cvar_t gl_lightmaps;
2836 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)
2838 float ambientscale, diffusescale, specularscale;
2840 float lightcolor[3];
2841 VectorCopy(rsurface.rtlight->currentcolor, lightcolor);
2842 ambientscale = rsurface.rtlight->ambientscale;
2843 diffusescale = rsurface.rtlight->diffusescale;
2844 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
2845 if (!r_shadow_usenormalmap.integer)
2847 ambientscale += 1.0f * diffusescale;
2851 if ((ambientscale + diffusescale) * VectorLength2(lightcolor) + specularscale * VectorLength2(lightcolor) < (1.0f / 1048576.0f))
2853 negated = (lightcolor[0] + lightcolor[1] + lightcolor[2] < 0) && vid.support.ext_blend_subtract;
2856 VectorNegate(lightcolor, lightcolor);
2857 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
2859 RSurf_SetupDepthAndCulling();
2860 switch (r_shadow_rendermode)
2862 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2863 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2864 R_Shadow_RenderLighting_VisibleLighting(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2866 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2867 R_Shadow_RenderLighting_Light_GLSL(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolor, ambientscale, diffusescale, specularscale);
2869 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2870 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2871 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2872 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2873 R_Shadow_RenderLighting_Light_Vertex(firstvertex, numvertices, numtriangles, element3i + firsttriangle * 3, lightcolor, ambientscale, diffusescale);
2876 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2880 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
2883 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)
2885 matrix4x4_t tempmatrix = *matrix;
2886 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
2888 // if this light has been compiled before, free the associated data
2889 R_RTLight_Uncompile(rtlight);
2891 // clear it completely to avoid any lingering data
2892 memset(rtlight, 0, sizeof(*rtlight));
2894 // copy the properties
2895 rtlight->matrix_lighttoworld = tempmatrix;
2896 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
2897 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
2898 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
2899 VectorCopy(color, rtlight->color);
2900 rtlight->cubemapname[0] = 0;
2901 if (cubemapname && cubemapname[0])
2902 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
2903 rtlight->shadow = shadow;
2904 rtlight->corona = corona;
2905 rtlight->style = style;
2906 rtlight->isstatic = isstatic;
2907 rtlight->coronasizescale = coronasizescale;
2908 rtlight->ambientscale = ambientscale;
2909 rtlight->diffusescale = diffusescale;
2910 rtlight->specularscale = specularscale;
2911 rtlight->flags = flags;
2913 // compute derived data
2914 //rtlight->cullradius = rtlight->radius;
2915 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2916 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2917 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2918 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2919 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2920 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2921 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2924 // compiles rtlight geometry
2925 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2926 void R_RTLight_Compile(rtlight_t *rtlight)
2929 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
2930 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
2931 entity_render_t *ent = r_refdef.scene.worldentity;
2932 dp_model_t *model = r_refdef.scene.worldmodel;
2933 unsigned char *data;
2936 // compile the light
2937 rtlight->compiled = true;
2938 rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
2939 rtlight->static_numleafs = 0;
2940 rtlight->static_numleafpvsbytes = 0;
2941 rtlight->static_leaflist = NULL;
2942 rtlight->static_leafpvs = NULL;
2943 rtlight->static_numsurfaces = 0;
2944 rtlight->static_surfacelist = NULL;
2945 rtlight->static_shadowmap_receivers = 0x3F;
2946 rtlight->static_shadowmap_casters = 0x3F;
2947 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2948 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2949 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2950 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2951 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2952 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2954 if (model && model->GetLightInfo)
2956 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
2957 r_shadow_compilingrtlight = rtlight;
2958 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);
2959 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2960 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
2961 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
2962 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
2963 rtlight->static_numsurfaces = numsurfaces;
2964 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
2965 rtlight->static_numleafs = numleafs;
2966 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
2967 rtlight->static_numleafpvsbytes = numleafpvsbytes;
2968 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
2969 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
2970 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
2971 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
2972 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
2973 if (rtlight->static_numsurfaces)
2974 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
2975 if (rtlight->static_numleafs)
2976 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
2977 if (rtlight->static_numleafpvsbytes)
2978 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
2979 if (rtlight->static_numshadowtrispvsbytes)
2980 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
2981 if (rtlight->static_numlighttrispvsbytes)
2982 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
2983 switch (rtlight->shadowmode)
2985 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2986 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
2987 case R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE:
2988 if (model->CompileShadowMap && rtlight->shadow)
2989 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2992 if (model->CompileShadowVolume && rtlight->shadow)
2993 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2996 // now we're done compiling the rtlight
2997 r_shadow_compilingrtlight = NULL;
3001 // use smallest available cullradius - box radius or light radius
3002 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3003 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3005 shadowzpasstris = 0;
3006 if (rtlight->static_meshchain_shadow_zpass)
3007 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
3008 shadowzpasstris += mesh->numtriangles;
3010 shadowzfailtris = 0;
3011 if (rtlight->static_meshchain_shadow_zfail)
3012 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
3013 shadowzfailtris += mesh->numtriangles;
3016 if (rtlight->static_numlighttrispvsbytes)
3017 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3018 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3022 if (rtlight->static_numlighttrispvsbytes)
3023 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3024 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3027 if (developer_extra.integer)
3028 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);
3031 void R_RTLight_Uncompile(rtlight_t *rtlight)
3033 if (rtlight->compiled)
3035 if (rtlight->static_meshchain_shadow_zpass)
3036 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
3037 rtlight->static_meshchain_shadow_zpass = NULL;
3038 if (rtlight->static_meshchain_shadow_zfail)
3039 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
3040 rtlight->static_meshchain_shadow_zfail = NULL;
3041 if (rtlight->static_meshchain_shadow_shadowmap)
3042 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
3043 rtlight->static_meshchain_shadow_shadowmap = NULL;
3044 // these allocations are grouped
3045 if (rtlight->static_surfacelist)
3046 Mem_Free(rtlight->static_surfacelist);
3047 rtlight->static_numleafs = 0;
3048 rtlight->static_numleafpvsbytes = 0;
3049 rtlight->static_leaflist = NULL;
3050 rtlight->static_leafpvs = NULL;
3051 rtlight->static_numsurfaces = 0;
3052 rtlight->static_surfacelist = NULL;
3053 rtlight->static_numshadowtrispvsbytes = 0;
3054 rtlight->static_shadowtrispvs = NULL;
3055 rtlight->static_numlighttrispvsbytes = 0;
3056 rtlight->static_lighttrispvs = NULL;
3057 rtlight->compiled = false;
3061 void R_Shadow_UncompileWorldLights(void)
3065 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3066 for (lightindex = 0;lightindex < range;lightindex++)
3068 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3071 R_RTLight_Uncompile(&light->rtlight);
3075 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3079 // reset the count of frustum planes
3080 // see rtlight->cached_frustumplanes definition for how much this array
3082 rtlight->cached_numfrustumplanes = 0;
3084 // haven't implemented a culling path for ortho rendering
3085 if (!r_refdef.view.useperspective)
3087 // check if the light is on screen and copy the 4 planes if it is
3088 for (i = 0;i < 4;i++)
3089 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3092 for (i = 0;i < 4;i++)
3093 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3098 // generate a deformed frustum that includes the light origin, this is
3099 // used to cull shadow casting surfaces that can not possibly cast a
3100 // shadow onto the visible light-receiving surfaces, which can be a
3103 // if the light origin is onscreen the result will be 4 planes exactly
3104 // if the light origin is offscreen on only one axis the result will
3105 // be exactly 5 planes (split-side case)
3106 // if the light origin is offscreen on two axes the result will be
3107 // exactly 4 planes (stretched corner case)
3108 for (i = 0;i < 4;i++)
3110 // quickly reject standard frustum planes that put the light
3111 // origin outside the frustum
3112 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3115 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3117 // if all the standard frustum planes were accepted, the light is onscreen
3118 // otherwise we need to generate some more planes below...
3119 if (rtlight->cached_numfrustumplanes < 4)
3121 // at least one of the stock frustum planes failed, so we need to
3122 // create one or two custom planes to enclose the light origin
3123 for (i = 0;i < 4;i++)
3125 // create a plane using the view origin and light origin, and a
3126 // single point from the frustum corner set
3127 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3128 VectorNormalize(plane.normal);
3129 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3130 // see if this plane is backwards and flip it if so
3131 for (j = 0;j < 4;j++)
3132 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3136 VectorNegate(plane.normal, plane.normal);
3138 // flipped plane, test again to see if it is now valid
3139 for (j = 0;j < 4;j++)
3140 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3142 // if the plane is still not valid, then it is dividing the
3143 // frustum and has to be rejected
3147 // we have created a valid plane, compute extra info
3148 PlaneClassify(&plane);
3150 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3152 // if we've found 5 frustum planes then we have constructed a
3153 // proper split-side case and do not need to keep searching for
3154 // planes to enclose the light origin
3155 if (rtlight->cached_numfrustumplanes == 5)
3163 for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
3165 plane = rtlight->cached_frustumplanes[i];
3166 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));
3171 // now add the light-space box planes if the light box is rotated, as any
3172 // caster outside the oriented light box is irrelevant (even if it passed
3173 // the worldspace light box, which is axial)
3174 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3176 for (i = 0;i < 6;i++)
3180 v[i >> 1] = (i & 1) ? -1 : 1;
3181 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3182 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3183 plane.dist = VectorNormalizeLength(plane.normal);
3184 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3185 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3191 // add the world-space reduced box planes
3192 for (i = 0;i < 6;i++)
3194 VectorClear(plane.normal);
3195 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3196 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
3197 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3206 // reduce all plane distances to tightly fit the rtlight cull box, which
3208 VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3209 VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3210 VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3211 VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3212 VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3213 VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3214 VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3215 VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3216 oldnum = rtlight->cached_numfrustumplanes;
3217 rtlight->cached_numfrustumplanes = 0;
3218 for (j = 0;j < oldnum;j++)
3220 // find the nearest point on the box to this plane
3221 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
3222 for (i = 1;i < 8;i++)
3224 dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
3225 if (bestdist > dist)
3228 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);
3229 // if the nearest point is near or behind the plane, we want this
3230 // plane, otherwise the plane is useless as it won't cull anything
3231 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
3233 PlaneClassify(&rtlight->cached_frustumplanes[j]);
3234 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
3241 void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
3245 RSurf_ActiveWorldEntity();
3247 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3250 GL_CullFace(GL_NONE);
3251 mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3252 for (;mesh;mesh = mesh->next)
3254 if (!mesh->sidetotals[r_shadow_shadowmapside])
3256 r_refdef.stats.lights_shadowtriangles += mesh->sidetotals[r_shadow_shadowmapside];
3257 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
3258 R_Mesh_Draw(0, mesh->numverts, mesh->sideoffsets[r_shadow_shadowmapside], mesh->sidetotals[r_shadow_shadowmapside], mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3262 else if (r_refdef.scene.worldentity->model)
3263 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);
3265 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3268 void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3270 qboolean zpass = false;
3273 int surfacelistindex;
3274 msurface_t *surface;
3276 RSurf_ActiveWorldEntity();
3278 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3281 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
3283 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
3284 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
3286 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
3287 for (;mesh;mesh = mesh->next)
3289 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
3290 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
3291 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
3293 // increment stencil if frontface is infront of depthbuffer
3294 GL_CullFace(r_refdef.view.cullface_back);
3295 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
3296 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3297 // decrement stencil if backface is infront of depthbuffer
3298 GL_CullFace(r_refdef.view.cullface_front);
3299 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
3301 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
3303 // decrement stencil if backface is behind depthbuffer
3304 GL_CullFace(r_refdef.view.cullface_front);
3305 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
3306 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3307 // increment stencil if frontface is behind depthbuffer
3308 GL_CullFace(r_refdef.view.cullface_back);
3309 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
3311 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3315 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh)
3317 // use the shadow trispvs calculated earlier by GetLightInfo to cull world triangles on this dynamic light
3318 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
3319 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
3321 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
3322 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
3323 if (CHECKPVSBIT(trispvs, t))
3324 shadowmarklist[numshadowmark++] = t;
3326 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);
3328 else if (numsurfaces)
3329 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);
3331 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3334 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3336 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3337 vec_t relativeshadowradius;
3338 RSurf_ActiveModelEntity(ent, false, false, false);
3339 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3340 // we need to re-init the shader for each entity because the matrix changed
3341 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3342 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3343 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3344 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3345 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3346 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3347 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3348 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D)
3350 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
3353 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3354 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3357 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3359 // set up properties for rendering light onto this entity
3360 RSurf_ActiveModelEntity(ent, true, true, false);
3361 GL_AlphaTest(false);
3362 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3363 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3364 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3365 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3368 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
3370 if (!r_refdef.scene.worldmodel->DrawLight)
3373 // set up properties for rendering light onto this entity
3374 RSurf_ActiveWorldEntity();
3375 GL_AlphaTest(false);
3376 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3377 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3378 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3379 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3381 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
3383 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3386 void R_Shadow_DrawEntityLight(entity_render_t *ent)
3388 dp_model_t *model = ent->model;
3389 if (!model->DrawLight)
3392 R_Shadow_SetupEntityLight(ent);
3394 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3396 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3399 void R_Shadow_PrepareLight(rtlight_t *rtlight)
3403 int numleafs, numsurfaces;
3404 int *leaflist, *surfacelist;
3405 unsigned char *leafpvs;
3406 unsigned char *shadowtrispvs;
3407 unsigned char *lighttrispvs;
3408 //unsigned char *surfacesides;
3409 int numlightentities;
3410 int numlightentities_noselfshadow;
3411 int numshadowentities;
3412 int numshadowentities_noselfshadow;
3413 static entity_render_t *lightentities[MAX_EDICTS];
3414 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3415 static entity_render_t *shadowentities[MAX_EDICTS];
3416 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3418 rtlight->draw = false;
3420 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3421 // skip lights that are basically invisible (color 0 0 0)
3422 if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
3425 // loading is done before visibility checks because loading should happen
3426 // all at once at the start of a level, not when it stalls gameplay.
3427 // (especially important to benchmarks)
3429 if (rtlight->isstatic && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
3431 if (rtlight->compiled)
3432 R_RTLight_Uncompile(rtlight);
3433 R_RTLight_Compile(rtlight);
3437 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
3439 // look up the light style value at this time
3440 f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3441 VectorScale(rtlight->color, f, rtlight->currentcolor);
3443 if (rtlight->selected)
3445 f = 2 + sin(realtime * M_PI * 4.0);
3446 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3450 // if lightstyle is currently off, don't draw the light
3451 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3454 // if the light box is offscreen, skip it
3455 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3458 VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
3459 VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
3461 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3463 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3465 // compiled light, world available and can receive realtime lighting
3466 // retrieve leaf information
3467 numleafs = rtlight->static_numleafs;
3468 leaflist = rtlight->static_leaflist;
3469 leafpvs = rtlight->static_leafpvs;
3470 numsurfaces = rtlight->static_numsurfaces;
3471 surfacelist = rtlight->static_surfacelist;
3472 //surfacesides = NULL;
3473 shadowtrispvs = rtlight->static_shadowtrispvs;
3474 lighttrispvs = rtlight->static_lighttrispvs;
3476 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3478 // dynamic light, world available and can receive realtime lighting
3479 // calculate lit surfaces and leafs
3480 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);
3481 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3482 leaflist = r_shadow_buffer_leaflist;
3483 leafpvs = r_shadow_buffer_leafpvs;
3484 surfacelist = r_shadow_buffer_surfacelist;
3485 //surfacesides = r_shadow_buffer_surfacesides;
3486 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3487 lighttrispvs = r_shadow_buffer_lighttrispvs;
3488 // if the reduced leaf bounds are offscreen, skip it
3489 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3500 //surfacesides = NULL;
3501 shadowtrispvs = NULL;
3502 lighttrispvs = NULL;
3504 // check if light is illuminating any visible leafs
3507 for (i = 0;i < numleafs;i++)
3508 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3514 // make a list of lit entities and shadow casting entities
3515 numlightentities = 0;
3516 numlightentities_noselfshadow = 0;
3517 numshadowentities = 0;
3518 numshadowentities_noselfshadow = 0;
3520 // add dynamic entities that are lit by the light
3521 for (i = 0;i < r_refdef.scene.numentities;i++)
3524 entity_render_t *ent = r_refdef.scene.entities[i];
3526 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3528 // skip the object entirely if it is not within the valid
3529 // shadow-casting region (which includes the lit region)
3530 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
3532 if (!(model = ent->model))
3534 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
3536 // this entity wants to receive light, is visible, and is
3537 // inside the light box
3538 // TODO: check if the surfaces in the model can receive light
3539 // so now check if it's in a leaf seen by the light
3540 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))
3542 if (ent->flags & RENDER_NOSELFSHADOW)
3543 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
3545 lightentities[numlightentities++] = ent;
3546 // since it is lit, it probably also casts a shadow...
3547 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3548 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3549 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3551 // note: exterior models without the RENDER_NOSELFSHADOW
3552 // flag still create a RENDER_NOSELFSHADOW shadow but
3553 // are lit normally, this means that they are
3554 // self-shadowing but do not shadow other
3555 // RENDER_NOSELFSHADOW entities such as the gun
3556 // (very weird, but keeps the player shadow off the gun)
3557 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3558 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3560 shadowentities[numshadowentities++] = ent;
3563 else if (ent->flags & RENDER_SHADOW)
3565 // this entity is not receiving light, but may still need to
3567 // TODO: check if the surfaces in the model can cast shadow
3568 // now check if it is in a leaf seen by the light
3569 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))
3571 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3572 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3573 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3575 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3576 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3578 shadowentities[numshadowentities++] = ent;
3583 // return if there's nothing at all to light
3584 if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
3587 // count this light in the r_speeds
3588 r_refdef.stats.lights++;
3590 // flag it as worth drawing later
3591 rtlight->draw = true;
3593 // cache all the animated entities that cast a shadow but are not visible
3594 for (i = 0;i < numshadowentities;i++)
3595 if (!shadowentities[i]->animcache_vertex3f)
3596 R_AnimCache_GetEntity(shadowentities[i], false, false);
3597 for (i = 0;i < numshadowentities_noselfshadow;i++)
3598 if (!shadowentities_noselfshadow[i]->animcache_vertex3f)
3599 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
3601 // allocate some temporary memory for rendering this light later in the frame
3602 // reusable buffers need to be copied, static data can be used as-is
3603 rtlight->cached_numlightentities = numlightentities;
3604 rtlight->cached_numlightentities_noselfshadow = numlightentities_noselfshadow;
3605 rtlight->cached_numshadowentities = numshadowentities;
3606 rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
3607 rtlight->cached_numsurfaces = numsurfaces;
3608 rtlight->cached_lightentities = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
3609 rtlight->cached_lightentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
3610 rtlight->cached_shadowentities = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
3611 rtlight->cached_shadowentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
3612 if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
3614 int numshadowtrispvsbytes = (((r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles) + 7) >> 3);
3615 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
3616 rtlight->cached_shadowtrispvs = (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
3617 rtlight->cached_lighttrispvs = (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
3618 rtlight->cached_surfacelist = (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
3622 // compiled light data
3623 rtlight->cached_shadowtrispvs = shadowtrispvs;
3624 rtlight->cached_lighttrispvs = lighttrispvs;
3625 rtlight->cached_surfacelist = surfacelist;
3629 void R_Shadow_DrawLight(rtlight_t *rtlight)
3633 unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
3634 int numlightentities;
3635 int numlightentities_noselfshadow;
3636 int numshadowentities;
3637 int numshadowentities_noselfshadow;
3638 entity_render_t **lightentities;
3639 entity_render_t **lightentities_noselfshadow;
3640 entity_render_t **shadowentities;
3641 entity_render_t **shadowentities_noselfshadow;
3643 static unsigned char entitysides[MAX_EDICTS];
3644 static unsigned char entitysides_noselfshadow[MAX_EDICTS];
3645 vec3_t nearestpoint;
3647 qboolean castshadows;
3650 // check if we cached this light this frame (meaning it is worth drawing)
3654 // if R_FrameData_Store ran out of space we skip anything dependent on it
3655 if (r_framedata_failed)
3658 numlightentities = rtlight->cached_numlightentities;
3659 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
3660 numshadowentities = rtlight->cached_numshadowentities;
3661 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
3662 numsurfaces = rtlight->cached_numsurfaces;
3663 lightentities = rtlight->cached_lightentities;
3664 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
3665 shadowentities = rtlight->cached_shadowentities;
3666 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
3667 shadowtrispvs = rtlight->cached_shadowtrispvs;
3668 lighttrispvs = rtlight->cached_lighttrispvs;
3669 surfacelist = rtlight->cached_surfacelist;
3671 // set up a scissor rectangle for this light
3672 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3675 // don't let sound skip if going slow
3676 if (r_refdef.scene.extraupdate)
3679 // make this the active rtlight for rendering purposes
3680 R_Shadow_RenderMode_ActiveLight(rtlight);
3682 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
3684 // optionally draw visible shape of the shadow volumes
3685 // for performance analysis by level designers
3686 R_Shadow_RenderMode_VisibleShadowVolumes();
3688 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
3689 for (i = 0;i < numshadowentities;i++)
3690 R_Shadow_DrawEntityShadow(shadowentities[i]);
3691 for (i = 0;i < numshadowentities_noselfshadow;i++)
3692 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3693 R_Shadow_RenderMode_VisibleLighting(false, false);
3696 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
3698 // optionally draw the illuminated areas
3699 // for performance analysis by level designers
3700 R_Shadow_RenderMode_VisibleLighting(false, false);
3702 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3703 for (i = 0;i < numlightentities;i++)
3704 R_Shadow_DrawEntityLight(lightentities[i]);
3705 for (i = 0;i < numlightentities_noselfshadow;i++)
3706 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3709 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
3711 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
3712 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
3713 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
3714 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
3716 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance/rtlight->radius));
3717 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
3718 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
3720 if (castshadows && (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE))
3726 int receivermask = 0;
3727 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
3728 Matrix4x4_Abs(&radiustolight);
3730 r_shadow_shadowmaplod = 0;
3731 for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
3732 if ((r_shadow_shadowmapmaxsize >> i) > lodlinear)
3733 r_shadow_shadowmaplod = i;
3735 if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
3736 size = max(1, r_shadow_shadowmapmaxsize >> r_shadow_shadowmaplod);
3738 size = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
3740 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
3742 surfacesides = NULL;
3745 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3747 castermask = rtlight->static_shadowmap_casters;
3748 receivermask = rtlight->static_shadowmap_receivers;
3752 surfacesides = r_shadow_buffer_surfacesides;
3753 for(i = 0;i < numsurfaces;i++)
3755 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
3756 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3757 castermask |= surfacesides[i];
3758 receivermask |= surfacesides[i];
3762 if (receivermask < 0x3F)
3764 for (i = 0;i < numlightentities;i++)
3765 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3766 if (receivermask < 0x3F)
3767 for(i = 0; i < numlightentities_noselfshadow;i++)
3768 receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3771 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
3775 for (i = 0;i < numshadowentities;i++)
3776 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3777 for (i = 0;i < numshadowentities_noselfshadow;i++)
3778 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3781 //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
3783 // render shadow casters into 6 sided depth texture
3784 for (side = 0;side < 6;side++) if (receivermask & (1 << side))
3786 R_Shadow_RenderMode_ShadowMap(side, receivermask, size);
3787 if (! (castermask & (1 << side))) continue;
3789 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
3790 for (i = 0;i < numshadowentities;i++) if (entitysides[i] & (1 << side))
3791 R_Shadow_DrawEntityShadow(shadowentities[i]);
3794 if (numlightentities_noselfshadow)
3796 // render lighting using the depth texture as shadowmap
3797 // draw lighting in the unmasked areas
3798 R_Shadow_RenderMode_Lighting(false, false, true);
3799 for (i = 0;i < numlightentities_noselfshadow;i++)
3800 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3803 // render shadow casters into 6 sided depth texture
3804 if (numshadowentities_noselfshadow)
3806 for (side = 0;side < 6;side++) if ((receivermask & castermask) & (1 << side))
3808 R_Shadow_RenderMode_ShadowMap(side, 0, size);
3809 for (i = 0;i < numshadowentities_noselfshadow;i++) if (entitysides_noselfshadow[i] & (1 << side))
3810 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3814 // render lighting using the depth texture as shadowmap
3815 // draw lighting in the unmasked areas
3816 R_Shadow_RenderMode_Lighting(false, false, true);
3817 // draw lighting in the unmasked areas
3819 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3820 for (i = 0;i < numlightentities;i++)
3821 R_Shadow_DrawEntityLight(lightentities[i]);
3823 else if (castshadows && vid.stencil)
3825 // draw stencil shadow volumes to mask off pixels that are in shadow
3826 // so that they won't receive lighting
3827 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
3828 R_Shadow_ClearStencil();
3831 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
3832 for (i = 0;i < numshadowentities;i++)
3833 R_Shadow_DrawEntityShadow(shadowentities[i]);
3835 // draw lighting in the unmasked areas
3836 R_Shadow_RenderMode_Lighting(true, false, false);
3837 for (i = 0;i < numlightentities_noselfshadow;i++)
3838 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3840 for (i = 0;i < numshadowentities_noselfshadow;i++)
3841 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3843 // draw lighting in the unmasked areas
3844 R_Shadow_RenderMode_Lighting(true, false, false);
3846 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3847 for (i = 0;i < numlightentities;i++)
3848 R_Shadow_DrawEntityLight(lightentities[i]);
3852 // draw lighting in the unmasked areas
3853 R_Shadow_RenderMode_Lighting(false, false, false);
3855 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3856 for (i = 0;i < numlightentities;i++)
3857 R_Shadow_DrawEntityLight(lightentities[i]);
3858 for (i = 0;i < numlightentities_noselfshadow;i++)
3859 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3862 if (r_shadow_usingdeferredprepass)
3864 // when rendering deferred lighting, we simply rasterize the box
3865 if (castshadows && (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE))
3866 R_Shadow_RenderMode_DrawDeferredLight(false, true);
3867 else if (castshadows && vid.stencil)
3868 R_Shadow_RenderMode_DrawDeferredLight(true, false);
3870 R_Shadow_RenderMode_DrawDeferredLight(false, false);
3874 static void R_Shadow_FreeDeferred(void)
3876 if (r_shadow_prepassgeometryfbo)
3877 qglDeleteFramebuffersEXT(1, &r_shadow_prepassgeometryfbo);CHECKGLERROR
3878 r_shadow_prepassgeometryfbo = 0;
3880 if (r_shadow_prepasslightingfbo)
3881 qglDeleteFramebuffersEXT(1, &r_shadow_prepasslightingfbo);CHECKGLERROR
3882 r_shadow_prepasslightingfbo = 0;
3884 if (r_shadow_prepassgeometrydepthtexture)
3885 R_FreeTexture(r_shadow_prepassgeometrydepthtexture);
3886 r_shadow_prepassgeometrydepthtexture = NULL;
3888 if (r_shadow_prepassgeometrynormalmaptexture)
3889 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
3890 r_shadow_prepassgeometrynormalmaptexture = NULL;
3892 if (r_shadow_prepasslightingdiffusetexture)
3893 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
3894 r_shadow_prepasslightingdiffusetexture = NULL;
3896 if (r_shadow_prepasslightingspeculartexture)
3897 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
3898 r_shadow_prepasslightingspeculartexture = NULL;
3901 void R_Shadow_DrawPrepass(void)
3909 entity_render_t *ent;
3911 GL_AlphaTest(false);
3912 R_Mesh_ColorPointer(NULL, 0, 0);
3913 R_Mesh_ResetTextureState();
3915 GL_ColorMask(1,1,1,1);
3916 GL_BlendFunc(GL_ONE, GL_ZERO);
3919 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepassgeometryfbo);CHECKGLERROR
3920 qglClearColor(0.5f,0.5f,0.5f,1.0f);CHECKGLERROR
3921 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);CHECKGLERROR
3923 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
3924 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
3925 if (r_timereport_active)
3926 R_TimeReport("prepassworld");
3928 for (i = 0;i < r_refdef.scene.numentities;i++)
3930 if (!r_refdef.viewcache.entityvisible[i])
3932 ent = r_refdef.scene.entities[i];
3933 if (ent->model && ent->model->DrawPrepass != NULL)
3934 ent->model->DrawPrepass(ent);
3937 if (r_timereport_active)
3938 R_TimeReport("prepassmodels");
3940 GL_DepthMask(false);
3941 GL_ColorMask(1,1,1,1);
3944 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepasslightingfbo);CHECKGLERROR
3945 qglClearColor(0.0f,0.0f,0.0f,0.0f);CHECKGLERROR
3946 GL_Clear(GL_COLOR_BUFFER_BIT);CHECKGLERROR
3947 if (r_refdef.fogenabled)
3948 qglClearColor(r_refdef.fogcolor[0],r_refdef.fogcolor[1],r_refdef.fogcolor[2],0);CHECKGLERROR
3950 R_Shadow_RenderMode_Begin();
3952 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3953 if (r_shadow_debuglight.integer >= 0)
3955 lightindex = r_shadow_debuglight.integer;
3956 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3957 if (light && (light->flags & flag))
3958 R_Shadow_DrawLight(&light->rtlight);
3962 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3963 for (lightindex = 0;lightindex < range;lightindex++)
3965 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3966 if (light && (light->flags & flag))
3967 R_Shadow_DrawLight(&light->rtlight);
3970 if (r_refdef.scene.rtdlight)
3971 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
3972 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
3974 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);CHECKGLERROR
3975 if (r_refdef.fogenabled)
3976 qglClearColor(r_refdef.fogcolor[0],r_refdef.fogcolor[1],r_refdef.fogcolor[2],0);CHECKGLERROR
3978 R_Shadow_RenderMode_End();
3980 if (r_timereport_active)
3981 R_TimeReport("prepasslights");
3984 void R_Shadow_DrawLightSprites(void);
3985 void R_Shadow_PrepareLights(void)
3995 if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4) ||
3996 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
3997 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0) ||
3998 r_shadow_shadowmaptexturetype != r_shadow_shadowmapping_texturetype.integer ||
3999 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
4000 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
4001 r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
4002 R_Shadow_FreeShadowMaps();
4004 switch (vid.renderpath)
4006 case RENDERPATH_GL20:
4007 case RENDERPATH_CGGL:
4008 if (!r_shadow_deferred.integer || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_STENCIL || !vid.support.ext_framebuffer_object || vid.maxdrawbuffers < 2)
4010 r_shadow_usingdeferredprepass = false;
4011 if (r_shadow_prepass_width)
4012 R_Shadow_FreeDeferred();
4013 r_shadow_prepass_width = r_shadow_prepass_height = 0;
4017 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
4019 R_Shadow_FreeDeferred();
4021 r_shadow_usingdeferredprepass = true;
4022 r_shadow_prepass_width = vid.width;
4023 r_shadow_prepass_height = vid.height;
4024 r_shadow_prepassgeometrydepthtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "prepassgeometrydepthmap", vid.width, vid.height, 24, false);
4025 r_shadow_prepassgeometrynormalmaptexture = R_LoadTexture2D(r_shadow_texturepool, "prepassgeometrynormalmap", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, NULL);
4026 r_shadow_prepasslightingdiffusetexture = R_LoadTexture2D(r_shadow_texturepool, "prepasslightingdiffuse", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, NULL);
4027 r_shadow_prepasslightingspeculartexture = R_LoadTexture2D(r_shadow_texturepool, "prepasslightingspecular", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, NULL);
4029 // set up the geometry pass fbo (depth + normalmap)
4030 qglGenFramebuffersEXT(1, &r_shadow_prepassgeometryfbo);CHECKGLERROR
4031 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepassgeometryfbo);CHECKGLERROR
4032 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_prepassgeometrydepthtexture), 0);CHECKGLERROR
4033 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_prepassgeometrynormalmaptexture), 0);CHECKGLERROR
4034 // render depth into one texture and normalmap into the other
4035 if (qglDrawBuffersARB)
4037 qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);CHECKGLERROR
4038 qglReadBuffer(GL_NONE);CHECKGLERROR
4040 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4041 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4043 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4044 Cvar_SetValueQuick(&r_shadow_deferred, 0);
4045 r_shadow_usingdeferredprepass = false;
4048 // set up the lighting pass fbo (diffuse + specular)
4049 qglGenFramebuffersEXT(1, &r_shadow_prepasslightingfbo);CHECKGLERROR
4050 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepasslightingfbo);CHECKGLERROR
4051 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_prepassgeometrydepthtexture), 0);CHECKGLERROR
4052 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_prepasslightingdiffusetexture), 0);CHECKGLERROR
4053 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_prepasslightingspeculartexture), 0);CHECKGLERROR
4054 // render diffuse into one texture and specular into another,
4055 // with depth and normalmap bound as textures,
4056 // with depth bound as attachment as well
4057 if (qglDrawBuffersARB)
4059 qglDrawBuffersARB(2, r_shadow_prepasslightingdrawbuffers);CHECKGLERROR
4060 qglReadBuffer(GL_NONE);CHECKGLERROR
4062 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4063 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4065 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4066 Cvar_SetValueQuick(&r_shadow_deferred, 0);
4067 r_shadow_usingdeferredprepass = false;
4071 case RENDERPATH_GL13:
4072 case RENDERPATH_GL11:
4073 r_shadow_usingdeferredprepass = false;
4077 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);
4079 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4080 if (r_shadow_debuglight.integer >= 0)
4082 lightindex = r_shadow_debuglight.integer;
4083 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4084 if (light && (light->flags & flag))
4085 R_Shadow_PrepareLight(&light->rtlight);
4089 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4090 for (lightindex = 0;lightindex < range;lightindex++)
4092 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4093 if (light && (light->flags & flag))
4094 R_Shadow_PrepareLight(&light->rtlight);
4097 if (r_refdef.scene.rtdlight)
4099 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4100 R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
4102 else if(gl_flashblend.integer)
4104 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4106 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
4107 f = (rtlight->style >= 0 ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4108 VectorScale(rtlight->color, f, rtlight->currentcolor);
4112 if (r_editlights.integer)
4113 R_Shadow_DrawLightSprites();
4116 void R_Shadow_DrawLights(void)
4124 R_Shadow_RenderMode_Begin();
4126 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4127 if (r_shadow_debuglight.integer >= 0)
4129 lightindex = r_shadow_debuglight.integer;
4130 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4131 if (light && (light->flags & flag))
4132 R_Shadow_DrawLight(&light->rtlight);
4136 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4137 for (lightindex = 0;lightindex < range;lightindex++)
4139 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4140 if (light && (light->flags & flag))
4141 R_Shadow_DrawLight(&light->rtlight);
4144 if (r_refdef.scene.rtdlight)
4145 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4146 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4148 R_Shadow_RenderMode_End();
4151 extern const float r_screenvertex3f[12];
4152 extern void R_SetupView(qboolean allowwaterclippingplane);
4153 extern void R_ResetViewRendering3D(void);
4154 extern void R_ResetViewRendering2D(void);
4155 extern cvar_t r_shadows;
4156 extern cvar_t r_shadows_darken;
4157 extern cvar_t r_shadows_drawafterrtlighting;
4158 extern cvar_t r_shadows_castfrombmodels;
4159 extern cvar_t r_shadows_throwdistance;
4160 extern cvar_t r_shadows_throwdirection;
4161 void R_DrawModelShadows(void)
4164 float relativethrowdistance;
4165 entity_render_t *ent;
4166 vec3_t relativelightorigin;
4167 vec3_t relativelightdirection;
4168 vec3_t relativeshadowmins, relativeshadowmaxs;
4169 vec3_t tmp, shadowdir;
4171 if (!r_refdef.scene.numentities || !vid.stencil)
4175 R_ResetViewRendering3D();
4176 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4177 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4178 R_Shadow_RenderMode_Begin();
4179 R_Shadow_RenderMode_ActiveLight(NULL);
4180 r_shadow_lightscissor[0] = r_refdef.view.x;
4181 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
4182 r_shadow_lightscissor[2] = r_refdef.view.width;
4183 r_shadow_lightscissor[3] = r_refdef.view.height;
4184 R_Shadow_RenderMode_StencilShadowVolumes(false);
4187 if (r_shadows.integer == 2)
4189 Math_atov(r_shadows_throwdirection.string, shadowdir);
4190 VectorNormalize(shadowdir);
4193 R_Shadow_ClearStencil();
4195 for (i = 0;i < r_refdef.scene.numentities;i++)
4197 ent = r_refdef.scene.entities[i];
4199 // cast shadows from anything of the map (submodels are optional)
4200 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4202 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4203 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
4204 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
4205 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
4206 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4209 if(ent->entitynumber != 0)
4211 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
4212 int entnum, entnum2, recursion;
4213 entnum = entnum2 = ent->entitynumber;
4214 for(recursion = 32; recursion > 0; --recursion)
4216 entnum2 = cl.entities[entnum].state_current.tagentity;
4217 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
4222 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
4224 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
4225 // transform into modelspace of OUR entity
4226 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
4227 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
4230 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4233 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4236 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
4237 RSurf_ActiveModelEntity(ent, false, false, false);
4238 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4239 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4243 // not really the right mode, but this will disable any silly stencil features
4244 R_Shadow_RenderMode_End();
4246 // set up ortho view for rendering this pass
4247 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4248 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4249 //GL_ScissorTest(true);
4250 //R_EntityMatrix(&identitymatrix);
4251 //R_Mesh_ResetTextureState();
4252 R_ResetViewRendering2D();
4253 R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
4254 R_Mesh_ColorPointer(NULL, 0, 0);
4255 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
4257 // set up a darkening blend on shadowed areas
4258 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4259 //GL_DepthRange(0, 1);
4260 //GL_DepthTest(false);
4261 //GL_DepthMask(false);
4262 //GL_PolygonOffset(0, 0);CHECKGLERROR
4263 GL_Color(0, 0, 0, r_shadows_darken.value);
4264 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4265 //qglDepthFunc(GL_ALWAYS);CHECKGLERROR
4266 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
4267 qglStencilMask(255);CHECKGLERROR
4268 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
4269 qglStencilFunc(GL_NOTEQUAL, 128, 255);CHECKGLERROR
4271 // apply the blend to the shadowed areas
4272 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
4274 // restore the viewport
4275 R_SetViewport(&r_refdef.view.viewport);
4277 // restore other state to normal
4278 //R_Shadow_RenderMode_End();
4281 void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4284 vec3_t centerorigin;
4286 // if it's too close, skip it
4287 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
4289 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4292 if (usequery && r_numqueries + 2 <= r_maxqueries)
4294 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4295 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4296 // 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
4297 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4300 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use qglDepthFunc instead
4301 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
4302 qglDepthFunc(GL_ALWAYS);
4303 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4304 R_Mesh_VertexPointer(vertex3f, 0, 0);
4305 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
4306 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4307 qglDepthFunc(GL_LEQUAL);
4308 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
4309 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4310 R_Mesh_VertexPointer(vertex3f, 0, 0);
4311 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
4312 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4315 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4318 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
4320 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4323 GLint allpixels = 0, visiblepixels = 0;
4324 // now we have to check the query result
4325 if (rtlight->corona_queryindex_visiblepixels)
4328 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
4329 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
4331 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
4332 if (visiblepixels < 1 || allpixels < 1)
4334 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
4335 cscale *= rtlight->corona_visibility;
4339 // FIXME: these traces should scan all render entities instead of cl.world
4340 if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
4343 VectorScale(rtlight->currentcolor, cscale, color);
4344 if (VectorLength(color) > (1.0f / 256.0f))
4347 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
4350 VectorNegate(color, color);
4351 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
4353 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4354 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);
4355 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4357 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
4361 void R_Shadow_DrawCoronas(void)
4369 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4371 if (r_waterstate.renderingscene)
4373 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4374 R_EntityMatrix(&identitymatrix);
4376 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4378 // check occlusion of coronas
4379 // use GL_ARB_occlusion_query if available
4380 // otherwise use raytraces
4382 usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
4385 GL_ColorMask(0,0,0,0);
4386 if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
4387 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
4390 r_maxqueries = (range + r_refdef.scene.numlights) * 4;
4391 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
4393 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
4396 RSurf_ActiveWorldEntity();
4397 GL_BlendFunc(GL_ONE, GL_ZERO);
4398 GL_CullFace(GL_NONE);
4399 GL_DepthMask(false);
4400 GL_DepthRange(0, 1);
4401 GL_PolygonOffset(0, 0);
4403 R_Mesh_ColorPointer(NULL, 0, 0);
4404 R_Mesh_ResetTextureState();
4405 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
4407 for (lightindex = 0;lightindex < range;lightindex++)
4409 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4412 rtlight = &light->rtlight;
4413 rtlight->corona_visibility = 0;
4414 rtlight->corona_queryindex_visiblepixels = 0;
4415 rtlight->corona_queryindex_allpixels = 0;
4416 if (!(rtlight->flags & flag))
4418 if (rtlight->corona <= 0)
4420 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4422 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4424 for (i = 0;i < r_refdef.scene.numlights;i++)
4426 rtlight = r_refdef.scene.lights[i];
4427 rtlight->corona_visibility = 0;
4428 rtlight->corona_queryindex_visiblepixels = 0;
4429 rtlight->corona_queryindex_allpixels = 0;
4430 if (!(rtlight->flags & flag))
4432 if (rtlight->corona <= 0)
4434 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4437 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4439 // now draw the coronas using the query data for intensity info
4440 for (lightindex = 0;lightindex < range;lightindex++)
4442 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4445 rtlight = &light->rtlight;
4446 if (rtlight->corona_visibility <= 0)
4448 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4450 for (i = 0;i < r_refdef.scene.numlights;i++)
4452 rtlight = r_refdef.scene.lights[i];
4453 if (rtlight->corona_visibility <= 0)
4455 if (gl_flashblend.integer)
4456 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4458 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4464 dlight_t *R_Shadow_NewWorldLight(void)
4466 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4469 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)
4472 // validate parameters
4473 if (style < 0 || style >= MAX_LIGHTSTYLES)
4475 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
4481 // copy to light properties
4482 VectorCopy(origin, light->origin);
4483 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4484 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4485 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4487 light->color[0] = max(color[0], 0);
4488 light->color[1] = max(color[1], 0);
4489 light->color[2] = max(color[2], 0);
4491 light->color[0] = color[0];
4492 light->color[1] = color[1];
4493 light->color[2] = color[2];
4494 light->radius = max(radius, 0);
4495 light->style = style;
4496 light->shadow = shadowenable;
4497 light->corona = corona;
4498 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4499 light->coronasizescale = coronasizescale;
4500 light->ambientscale = ambientscale;
4501 light->diffusescale = diffusescale;
4502 light->specularscale = specularscale;
4503 light->flags = flags;
4505 // update renderable light data
4506 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4507 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);
4510 void R_Shadow_FreeWorldLight(dlight_t *light)
4512 if (r_shadow_selectedlight == light)
4513 r_shadow_selectedlight = NULL;
4514 R_RTLight_Uncompile(&light->rtlight);
4515 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4518 void R_Shadow_ClearWorldLights(void)
4522 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4523 for (lightindex = 0;lightindex < range;lightindex++)
4525 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4527 R_Shadow_FreeWorldLight(light);
4529 r_shadow_selectedlight = NULL;
4532 void R_Shadow_SelectLight(dlight_t *light)
4534 if (r_shadow_selectedlight)
4535 r_shadow_selectedlight->selected = false;
4536 r_shadow_selectedlight = light;
4537 if (r_shadow_selectedlight)
4538 r_shadow_selectedlight->selected = true;
4541 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4543 // this is never batched (there can be only one)
4545 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
4546 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4547 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4550 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4555 skinframe_t *skinframe;
4558 // this is never batched (due to the ent parameter changing every time)
4559 // so numsurfaces == 1 and surfacelist[0] == lightnumber
4560 const dlight_t *light = (dlight_t *)ent;
4563 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
4566 VectorScale(light->color, intensity, spritecolor);
4567 if (VectorLength(spritecolor) < 0.1732f)
4568 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
4569 if (VectorLength(spritecolor) > 1.0f)
4570 VectorNormalize(spritecolor);
4572 // draw light sprite
4573 if (light->cubemapname[0] && !light->shadow)
4574 skinframe = r_editlights_sprcubemapnoshadowlight;
4575 else if (light->cubemapname[0])
4576 skinframe = r_editlights_sprcubemaplight;
4577 else if (!light->shadow)
4578 skinframe = r_editlights_sprnoshadowlight;
4580 skinframe = r_editlights_sprlight;
4582 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);
4583 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4585 // draw selection sprite if light is selected
4586 if (light->selected)
4588 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4589 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4590 // VorteX todo: add normalmode/realtime mode light overlay sprites?
4594 void R_Shadow_DrawLightSprites(void)
4598 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4599 for (lightindex = 0;lightindex < range;lightindex++)
4601 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4603 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
4605 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
4608 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
4613 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
4614 if (lightindex >= range)
4616 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4619 rtlight = &light->rtlight;
4620 //if (!(rtlight->flags & flag))
4622 VectorCopy(rtlight->shadoworigin, origin);
4623 *radius = rtlight->radius;
4624 VectorCopy(rtlight->color, color);
4628 void R_Shadow_SelectLightInView(void)
4630 float bestrating, rating, temp[3];
4634 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4637 for (lightindex = 0;lightindex < range;lightindex++)
4639 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4642 VectorSubtract(light->origin, r_refdef.view.origin, temp);
4643 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
4646 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
4647 if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1.0f)
4649 bestrating = rating;
4654 R_Shadow_SelectLight(best);
4657 void R_Shadow_LoadWorldLights(void)
4659 int n, a, style, shadow, flags;
4660 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
4661 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
4662 if (cl.worldmodel == NULL)
4664 Con_Print("No map loaded.\n");
4667 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4668 strlcat (name, ".rtlights", sizeof (name));
4669 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4679 for (;COM_Parse(t, true) && strcmp(
4680 if (COM_Parse(t, true))
4682 if (com_token[0] == '!')
4685 origin[0] = atof(com_token+1);
4688 origin[0] = atof(com_token);
4693 while (*s && *s != '\n' && *s != '\r')
4699 // check for modifier flags
4706 #if _MSC_VER >= 1400
4707 #define sscanf sscanf_s
4709 cubemapname[sizeof(cubemapname)-1] = 0;
4710 #if MAX_QPATH != 128
4711 #error update this code if MAX_QPATH changes
4713 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
4714 #if _MSC_VER >= 1400
4715 , sizeof(cubemapname)
4717 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
4720 flags = LIGHTFLAG_REALTIMEMODE;
4728 coronasizescale = 0.25f;
4730 VectorClear(angles);
4733 if (a < 9 || !strcmp(cubemapname, "\"\""))
4735 // remove quotes on cubemapname
4736 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
4739 namelen = strlen(cubemapname) - 2;
4740 memmove(cubemapname, cubemapname + 1, namelen);
4741 cubemapname[namelen] = '\0';
4745 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);
4748 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4756 Con_Printf("invalid rtlights file \"%s\"\n", name);
4757 Mem_Free(lightsstring);
4761 void R_Shadow_SaveWorldLights(void)
4765 size_t bufchars, bufmaxchars;
4767 char name[MAX_QPATH];
4768 char line[MAX_INPUTLINE];
4769 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
4770 // I hate lines which are 3 times my screen size :( --blub
4773 if (cl.worldmodel == NULL)
4775 Con_Print("No map loaded.\n");
4778 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4779 strlcat (name, ".rtlights", sizeof (name));
4780 bufchars = bufmaxchars = 0;
4782 for (lightindex = 0;lightindex < range;lightindex++)
4784 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4787 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
4788 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);
4789 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
4790 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]);
4792 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);
4793 if (bufchars + strlen(line) > bufmaxchars)
4795 bufmaxchars = bufchars + strlen(line) + 2048;
4797 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
4801 memcpy(buf, oldbuf, bufchars);
4807 memcpy(buf + bufchars, line, strlen(line));
4808 bufchars += strlen(line);
4812 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
4817 void R_Shadow_LoadLightsFile(void)
4820 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
4821 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
4822 if (cl.worldmodel == NULL)
4824 Con_Print("No map loaded.\n");
4827 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4828 strlcat (name, ".lights", sizeof (name));
4829 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4837 while (*s && *s != '\n' && *s != '\r')
4843 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);
4847 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);
4850 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
4851 radius = bound(15, radius, 4096);
4852 VectorScale(color, (2.0f / (8388608.0f)), color);
4853 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
4861 Con_Printf("invalid lights file \"%s\"\n", name);
4862 Mem_Free(lightsstring);
4866 // tyrlite/hmap2 light types in the delay field
4867 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
4869 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
4881 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
4882 char key[256], value[MAX_INPUTLINE];
4884 if (cl.worldmodel == NULL)
4886 Con_Print("No map loaded.\n");
4889 // try to load a .ent file first
4890 FS_StripExtension (cl.worldmodel->name, key, sizeof (key));
4891 strlcat (key, ".ent", sizeof (key));
4892 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
4893 // and if that is not found, fall back to the bsp file entity string
4895 data = cl.worldmodel->brush.entities;
4898 for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
4900 type = LIGHTTYPE_MINUSX;
4901 origin[0] = origin[1] = origin[2] = 0;
4902 originhack[0] = originhack[1] = originhack[2] = 0;
4903 angles[0] = angles[1] = angles[2] = 0;
4904 color[0] = color[1] = color[2] = 1;
4905 light[0] = light[1] = light[2] = 1;light[3] = 300;
4906 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
4916 if (!COM_ParseToken_Simple(&data, false, false))
4918 if (com_token[0] == '}')
4919 break; // end of entity
4920 if (com_token[0] == '_')
4921 strlcpy(key, com_token + 1, sizeof(key));
4923 strlcpy(key, com_token, sizeof(key));
4924 while (key[strlen(key)-1] == ' ') // remove trailing spaces
4925 key[strlen(key)-1] = 0;
4926 if (!COM_ParseToken_Simple(&data, false, false))
4928 strlcpy(value, com_token, sizeof(value));
4930 // now that we have the key pair worked out...
4931 if (!strcmp("light", key))
4933 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
4937 light[0] = vec[0] * (1.0f / 256.0f);
4938 light[1] = vec[0] * (1.0f / 256.0f);
4939 light[2] = vec[0] * (1.0f / 256.0f);
4945 light[0] = vec[0] * (1.0f / 255.0f);
4946 light[1] = vec[1] * (1.0f / 255.0f);
4947 light[2] = vec[2] * (1.0f / 255.0f);
4951 else if (!strcmp("delay", key))
4953 else if (!strcmp("origin", key))
4954 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
4955 else if (!strcmp("angle", key))
4956 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
4957 else if (!strcmp("angles", key))
4958 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
4959 else if (!strcmp("color", key))
4960 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
4961 else if (!strcmp("wait", key))
4962 fadescale = atof(value);
4963 else if (!strcmp("classname", key))
4965 if (!strncmp(value, "light", 5))
4968 if (!strcmp(value, "light_fluoro"))
4973 overridecolor[0] = 1;
4974 overridecolor[1] = 1;
4975 overridecolor[2] = 1;
4977 if (!strcmp(value, "light_fluorospark"))
4982 overridecolor[0] = 1;
4983 overridecolor[1] = 1;
4984 overridecolor[2] = 1;
4986 if (!strcmp(value, "light_globe"))
4991 overridecolor[0] = 1;
4992 overridecolor[1] = 0.8;
4993 overridecolor[2] = 0.4;
4995 if (!strcmp(value, "light_flame_large_yellow"))
5000 overridecolor[0] = 1;
5001 overridecolor[1] = 0.5;
5002 overridecolor[2] = 0.1;
5004 if (!strcmp(value, "light_flame_small_yellow"))
5009 overridecolor[0] = 1;
5010 overridecolor[1] = 0.5;
5011 overridecolor[2] = 0.1;
5013 if (!strcmp(value, "light_torch_small_white"))
5018 overridecolor[0] = 1;
5019 overridecolor[1] = 0.5;
5020 overridecolor[2] = 0.1;
5022 if (!strcmp(value, "light_torch_small_walltorch"))
5027 overridecolor[0] = 1;
5028 overridecolor[1] = 0.5;
5029 overridecolor[2] = 0.1;
5033 else if (!strcmp("style", key))
5034 style = atoi(value);
5035 else if (!strcmp("skin", key))
5036 skin = (int)atof(value);
5037 else if (!strcmp("pflags", key))
5038 pflags = (int)atof(value);
5039 //else if (!strcmp("effects", key))
5040 // effects = (int)atof(value);
5041 else if (cl.worldmodel->type == mod_brushq3)
5043 if (!strcmp("scale", key))
5044 lightscale = atof(value);
5045 if (!strcmp("fade", key))
5046 fadescale = atof(value);
5051 if (lightscale <= 0)
5055 if (color[0] == color[1] && color[0] == color[2])
5057 color[0] *= overridecolor[0];
5058 color[1] *= overridecolor[1];
5059 color[2] *= overridecolor[2];
5061 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5062 color[0] = color[0] * light[0];
5063 color[1] = color[1] * light[1];
5064 color[2] = color[2] * light[2];
5067 case LIGHTTYPE_MINUSX:
5069 case LIGHTTYPE_RECIPX:
5071 VectorScale(color, (1.0f / 16.0f), color);
5073 case LIGHTTYPE_RECIPXX:
5075 VectorScale(color, (1.0f / 16.0f), color);
5078 case LIGHTTYPE_NONE:
5082 case LIGHTTYPE_MINUSXX:
5085 VectorAdd(origin, originhack, origin);
5087 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);
5090 Mem_Free(entfiledata);
5094 void R_Shadow_SetCursorLocationForView(void)
5097 vec3_t dest, endpos;
5099 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5100 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
5101 if (trace.fraction < 1)
5103 dist = trace.fraction * r_editlights_cursordistance.value;
5104 push = r_editlights_cursorpushback.value;
5108 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5109 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5113 VectorClear( endpos );
5115 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5116 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5117 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5120 void R_Shadow_UpdateWorldLightSelection(void)
5122 if (r_editlights.integer)
5124 R_Shadow_SetCursorLocationForView();
5125 R_Shadow_SelectLightInView();
5128 R_Shadow_SelectLight(NULL);
5131 void R_Shadow_EditLights_Clear_f(void)
5133 R_Shadow_ClearWorldLights();
5136 void R_Shadow_EditLights_Reload_f(void)
5140 strlcpy(r_shadow_mapname, cl.worldmodel->name, sizeof(r_shadow_mapname));
5141 R_Shadow_ClearWorldLights();
5142 R_Shadow_LoadWorldLights();
5143 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5145 R_Shadow_LoadLightsFile();
5146 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5147 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5151 void R_Shadow_EditLights_Save_f(void)
5155 R_Shadow_SaveWorldLights();
5158 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
5160 R_Shadow_ClearWorldLights();
5161 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5164 void R_Shadow_EditLights_ImportLightsFile_f(void)
5166 R_Shadow_ClearWorldLights();
5167 R_Shadow_LoadLightsFile();
5170 void R_Shadow_EditLights_Spawn_f(void)
5173 if (!r_editlights.integer)
5175 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5178 if (Cmd_Argc() != 1)
5180 Con_Print("r_editlights_spawn does not take parameters\n");
5183 color[0] = color[1] = color[2] = 1;
5184 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5187 void R_Shadow_EditLights_Edit_f(void)
5189 vec3_t origin, angles, color;
5190 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5191 int style, shadows, flags, normalmode, realtimemode;
5192 char cubemapname[MAX_INPUTLINE];
5193 if (!r_editlights.integer)
5195 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5198 if (!r_shadow_selectedlight)
5200 Con_Print("No selected light.\n");
5203 VectorCopy(r_shadow_selectedlight->origin, origin);
5204 VectorCopy(r_shadow_selectedlight->angles, angles);
5205 VectorCopy(r_shadow_selectedlight->color, color);
5206 radius = r_shadow_selectedlight->radius;
5207 style = r_shadow_selectedlight->style;
5208 if (r_shadow_selectedlight->cubemapname)
5209 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5212 shadows = r_shadow_selectedlight->shadow;
5213 corona = r_shadow_selectedlight->corona;
5214 coronasizescale = r_shadow_selectedlight->coronasizescale;
5215 ambientscale = r_shadow_selectedlight->ambientscale;
5216 diffusescale = r_shadow_selectedlight->diffusescale;
5217 specularscale = r_shadow_selectedlight->specularscale;
5218 flags = r_shadow_selectedlight->flags;
5219 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5220 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5221 if (!strcmp(Cmd_Argv(1), "origin"))
5223 if (Cmd_Argc() != 5)
5225 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5228 origin[0] = atof(Cmd_Argv(2));
5229 origin[1] = atof(Cmd_Argv(3));
5230 origin[2] = atof(Cmd_Argv(4));
5232 else if (!strcmp(Cmd_Argv(1), "originx"))
5234 if (Cmd_Argc() != 3)
5236 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5239 origin[0] = atof(Cmd_Argv(2));
5241 else if (!strcmp(Cmd_Argv(1), "originy"))
5243 if (Cmd_Argc() != 3)
5245 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5248 origin[1] = atof(Cmd_Argv(2));
5250 else if (!strcmp(Cmd_Argv(1), "originz"))
5252 if (Cmd_Argc() != 3)
5254 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5257 origin[2] = atof(Cmd_Argv(2));
5259 else if (!strcmp(Cmd_Argv(1), "move"))
5261 if (Cmd_Argc() != 5)
5263 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5266 origin[0] += atof(Cmd_Argv(2));
5267 origin[1] += atof(Cmd_Argv(3));
5268 origin[2] += atof(Cmd_Argv(4));
5270 else if (!strcmp(Cmd_Argv(1), "movex"))
5272 if (Cmd_Argc() != 3)
5274 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5277 origin[0] += atof(Cmd_Argv(2));
5279 else if (!strcmp(Cmd_Argv(1), "movey"))
5281 if (Cmd_Argc() != 3)
5283 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5286 origin[1] += atof(Cmd_Argv(2));
5288 else if (!strcmp(Cmd_Argv(1), "movez"))
5290 if (Cmd_Argc() != 3)
5292 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5295 origin[2] += atof(Cmd_Argv(2));
5297 else if (!strcmp(Cmd_Argv(1), "angles"))
5299 if (Cmd_Argc() != 5)
5301 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5304 angles[0] = atof(Cmd_Argv(2));
5305 angles[1] = atof(Cmd_Argv(3));
5306 angles[2] = atof(Cmd_Argv(4));
5308 else if (!strcmp(Cmd_Argv(1), "anglesx"))
5310 if (Cmd_Argc() != 3)
5312 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5315 angles[0] = atof(Cmd_Argv(2));
5317 else if (!strcmp(Cmd_Argv(1), "anglesy"))
5319 if (Cmd_Argc() != 3)
5321 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5324 angles[1] = atof(Cmd_Argv(2));
5326 else if (!strcmp(Cmd_Argv(1), "anglesz"))
5328 if (Cmd_Argc() != 3)
5330 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5333 angles[2] = atof(Cmd_Argv(2));
5335 else if (!strcmp(Cmd_Argv(1), "color"))
5337 if (Cmd_Argc() != 5)
5339 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
5342 color[0] = atof(Cmd_Argv(2));
5343 color[1] = atof(Cmd_Argv(3));
5344 color[2] = atof(Cmd_Argv(4));
5346 else if (!strcmp(Cmd_Argv(1), "radius"))
5348 if (Cmd_Argc() != 3)
5350 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5353 radius = atof(Cmd_Argv(2));
5355 else if (!strcmp(Cmd_Argv(1), "colorscale"))
5357 if (Cmd_Argc() == 3)
5359 double scale = atof(Cmd_Argv(2));
5366 if (Cmd_Argc() != 5)
5368 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
5371 color[0] *= atof(Cmd_Argv(2));
5372 color[1] *= atof(Cmd_Argv(3));
5373 color[2] *= atof(Cmd_Argv(4));
5376 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
5378 if (Cmd_Argc() != 3)
5380 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5383 radius *= atof(Cmd_Argv(2));
5385 else if (!strcmp(Cmd_Argv(1), "style"))
5387 if (Cmd_Argc() != 3)
5389 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5392 style = atoi(Cmd_Argv(2));
5394 else if (!strcmp(Cmd_Argv(1), "cubemap"))
5398 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5401 if (Cmd_Argc() == 3)
5402 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
5406 else if (!strcmp(Cmd_Argv(1), "shadows"))
5408 if (Cmd_Argc() != 3)
5410 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5413 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5415 else if (!strcmp(Cmd_Argv(1), "corona"))
5417 if (Cmd_Argc() != 3)
5419 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5422 corona = atof(Cmd_Argv(2));
5424 else if (!strcmp(Cmd_Argv(1), "coronasize"))
5426 if (Cmd_Argc() != 3)
5428 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5431 coronasizescale = atof(Cmd_Argv(2));
5433 else if (!strcmp(Cmd_Argv(1), "ambient"))
5435 if (Cmd_Argc() != 3)
5437 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5440 ambientscale = atof(Cmd_Argv(2));
5442 else if (!strcmp(Cmd_Argv(1), "diffuse"))
5444 if (Cmd_Argc() != 3)
5446 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5449 diffusescale = atof(Cmd_Argv(2));
5451 else if (!strcmp(Cmd_Argv(1), "specular"))
5453 if (Cmd_Argc() != 3)
5455 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5458 specularscale = atof(Cmd_Argv(2));
5460 else if (!strcmp(Cmd_Argv(1), "normalmode"))
5462 if (Cmd_Argc() != 3)
5464 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5467 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5469 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
5471 if (Cmd_Argc() != 3)
5473 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5476 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5480 Con_Print("usage: r_editlights_edit [property] [value]\n");
5481 Con_Print("Selected light's properties:\n");
5482 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5483 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5484 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5485 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
5486 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
5487 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
5488 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5489 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
5490 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
5491 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
5492 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
5493 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
5494 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5495 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5498 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5499 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5502 void R_Shadow_EditLights_EditAll_f(void)
5508 if (!r_editlights.integer)
5510 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5514 // EditLights doesn't seem to have a "remove" command or something so:
5515 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5516 for (lightindex = 0;lightindex < range;lightindex++)
5518 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5521 R_Shadow_SelectLight(light);
5522 R_Shadow_EditLights_Edit_f();
5526 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
5528 int lightnumber, lightcount;
5529 size_t lightindex, range;
5533 if (!r_editlights.integer)
5535 x = vid_conwidth.value - 240;
5537 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
5540 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5541 for (lightindex = 0;lightindex < range;lightindex++)
5543 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5546 if (light == r_shadow_selectedlight)
5547 lightnumber = lightindex;
5550 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;
5551 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;
5553 if (r_shadow_selectedlight == NULL)
5555 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;
5556 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;
5557 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;
5558 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;
5559 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;
5560 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;
5561 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;
5562 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;
5563 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;
5564 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;
5565 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;
5566 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;
5567 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;
5568 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;
5569 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;
5572 void R_Shadow_EditLights_ToggleShadow_f(void)
5574 if (!r_editlights.integer)
5576 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5579 if (!r_shadow_selectedlight)
5581 Con_Print("No selected light.\n");
5584 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);
5587 void R_Shadow_EditLights_ToggleCorona_f(void)
5589 if (!r_editlights.integer)
5591 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5594 if (!r_shadow_selectedlight)
5596 Con_Print("No selected light.\n");
5599 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);
5602 void R_Shadow_EditLights_Remove_f(void)
5604 if (!r_editlights.integer)
5606 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
5609 if (!r_shadow_selectedlight)
5611 Con_Print("No selected light.\n");
5614 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
5615 r_shadow_selectedlight = NULL;
5618 void R_Shadow_EditLights_Help_f(void)
5621 "Documentation on r_editlights system:\n"
5623 "r_editlights : enable/disable editing mode\n"
5624 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
5625 "r_editlights_cursorpushback : push back cursor this far from surface\n"
5626 "r_editlights_cursorpushoff : push cursor off surface this far\n"
5627 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
5628 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
5630 "r_editlights_help : this help\n"
5631 "r_editlights_clear : remove all lights\n"
5632 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
5633 "r_editlights_save : save to .rtlights file\n"
5634 "r_editlights_spawn : create a light with default settings\n"
5635 "r_editlights_edit command : edit selected light - more documentation below\n"
5636 "r_editlights_remove : remove selected light\n"
5637 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
5638 "r_editlights_importlightentitiesfrommap : reload light entities\n"
5639 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
5641 "origin x y z : set light location\n"
5642 "originx x: set x component of light location\n"
5643 "originy y: set y component of light location\n"
5644 "originz z: set z component of light location\n"
5645 "move x y z : adjust light location\n"
5646 "movex x: adjust x component of light location\n"
5647 "movey y: adjust y component of light location\n"
5648 "movez z: adjust z component of light location\n"
5649 "angles x y z : set light angles\n"
5650 "anglesx x: set x component of light angles\n"
5651 "anglesy y: set y component of light angles\n"
5652 "anglesz z: set z component of light angles\n"
5653 "color r g b : set color of light (can be brighter than 1 1 1)\n"
5654 "radius radius : set radius (size) of light\n"
5655 "colorscale grey : multiply color of light (1 does nothing)\n"
5656 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
5657 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
5658 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
5659 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
5660 "cubemap basename : set filter cubemap of light (not yet supported)\n"
5661 "shadows 1/0 : turn on/off shadows\n"
5662 "corona n : set corona intensity\n"
5663 "coronasize n : set corona size (0-1)\n"
5664 "ambient n : set ambient intensity (0-1)\n"
5665 "diffuse n : set diffuse intensity (0-1)\n"
5666 "specular n : set specular intensity (0-1)\n"
5667 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
5668 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
5669 "<nothing> : print light properties to console\n"
5673 void R_Shadow_EditLights_CopyInfo_f(void)
5675 if (!r_editlights.integer)
5677 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
5680 if (!r_shadow_selectedlight)
5682 Con_Print("No selected light.\n");
5685 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
5686 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
5687 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
5688 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
5689 if (r_shadow_selectedlight->cubemapname)
5690 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
5692 r_shadow_bufferlight.cubemapname[0] = 0;
5693 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
5694 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
5695 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
5696 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
5697 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
5698 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
5699 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
5702 void R_Shadow_EditLights_PasteInfo_f(void)
5704 if (!r_editlights.integer)
5706 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
5709 if (!r_shadow_selectedlight)
5711 Con_Print("No selected light.\n");
5714 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);
5717 void R_Shadow_EditLights_Init(void)
5719 Cvar_RegisterVariable(&r_editlights);
5720 Cvar_RegisterVariable(&r_editlights_cursordistance);
5721 Cvar_RegisterVariable(&r_editlights_cursorpushback);
5722 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
5723 Cvar_RegisterVariable(&r_editlights_cursorgrid);
5724 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
5725 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
5726 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
5727 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)");
5728 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
5729 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
5730 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
5731 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)");
5732 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
5733 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
5734 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
5735 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
5736 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
5737 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
5738 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)");
5744 =============================================================================
5748 =============================================================================
5751 void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, int dynamic)
5753 VectorClear(diffusecolor);
5754 VectorClear(diffusenormal);
5756 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
5758 ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_refdef.scene.ambient;
5759 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
5762 VectorSet(ambientcolor, 1, 1, 1);
5769 for (i = 0;i < r_refdef.scene.numlights;i++)
5771 light = r_refdef.scene.lights[i];
5772 Matrix4x4_Transform(&light->matrix_worldtolight, p, v);
5773 f = 1 - VectorLength2(v);
5774 if (f > 0 && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
5775 VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);