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 void R_Shadow_RenderMode_ShadowMap(int side, int clear, int size)
2048 float nearclip, farclip, bias;
2049 r_viewport_t viewport;
2052 maxsize = r_shadow_shadowmapmaxsize;
2053 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
2055 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
2056 r_shadow_shadowmap_parameters[2] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
2057 r_shadow_shadowmap_parameters[3] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
2058 r_shadow_shadowmapside = side;
2059 r_shadow_shadowmapsize = size;
2060 if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
2062 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2063 r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2064 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
2065 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D) goto init_done;
2067 // complex unrolled cube approach (more flexible)
2068 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2069 R_Shadow_MakeVSDCT();
2070 if (!r_shadow_shadowmap2dtexture)
2073 int w = maxsize*2, h = vid.support.arb_texture_non_power_of_two ? maxsize*3 : maxsize*4;
2074 r_shadow_shadowmap2dtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "shadowmap", w, h, r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
2075 qglGenFramebuffersEXT(1, &r_shadow_fbo2d);CHECKGLERROR
2076 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbo2d);CHECKGLERROR
2077 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_shadowmap2dtexture), 0);CHECKGLERROR
2078 // render depth into the fbo, do not render color at all
2079 qglDrawBuffer(GL_NONE);CHECKGLERROR
2080 qglReadBuffer(GL_NONE);CHECKGLERROR
2081 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2082 if (status != GL_FRAMEBUFFER_COMPLETE_EXT && (r_shadow_shadowmapping.integer || r_shadow_deferred.integer))
2084 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2085 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2086 Cvar_SetValueQuick(&r_shadow_deferred, 0);
2091 if (r_shadow_shadowmap2dtexture) fbo = r_shadow_fbo2d;
2092 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
2093 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
2094 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
2096 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE)
2098 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2099 r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2100 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
2101 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE) goto init_done;
2103 // complex unrolled cube approach (more flexible)
2104 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2105 R_Shadow_MakeVSDCT();
2106 if (!r_shadow_shadowmaprectangletexture)
2109 r_shadow_shadowmaprectangletexture = R_LoadTextureShadowMapRectangle(r_shadow_texturepool, "shadowmap", maxsize*2, maxsize*3, r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
2110 qglGenFramebuffersEXT(1, &r_shadow_fborectangle);CHECKGLERROR
2111 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fborectangle);CHECKGLERROR
2112 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, R_GetTexture(r_shadow_shadowmaprectangletexture), 0);CHECKGLERROR
2113 // render depth into the fbo, do not render color at all
2114 qglDrawBuffer(GL_NONE);CHECKGLERROR
2115 qglReadBuffer(GL_NONE);CHECKGLERROR
2116 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2117 if (status != GL_FRAMEBUFFER_COMPLETE_EXT && (r_shadow_shadowmapping.integer || r_shadow_deferred.integer))
2119 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2120 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2121 Cvar_SetValueQuick(&r_shadow_deferred, 0);
2126 if(r_shadow_shadowmaprectangletexture) fbo = r_shadow_fborectangle;
2127 r_shadow_shadowmap_texturescale[0] = 1.0f;
2128 r_shadow_shadowmap_texturescale[1] = 1.0f;
2129 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE;
2131 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
2133 r_shadow_shadowmap_parameters[0] = 1.0f;
2134 r_shadow_shadowmap_parameters[1] = 1.0f;
2135 R_Viewport_InitCubeSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, nearclip, farclip, NULL);
2136 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE) goto init_done;
2138 // simple cube approach
2139 if (!r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod])
2142 r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod] = R_LoadTextureShadowMapCube(r_shadow_texturepool, "shadowmapcube", size, r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
2143 qglGenFramebuffersEXT(1, &r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR
2144 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR
2145 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
2146 // render depth into the fbo, do not render color at all
2147 qglDrawBuffer(GL_NONE);CHECKGLERROR
2148 qglReadBuffer(GL_NONE);CHECKGLERROR
2149 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2150 if (status != GL_FRAMEBUFFER_COMPLETE_EXT && (r_shadow_shadowmapping.integer || r_shadow_deferred.integer))
2152 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2153 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2154 Cvar_SetValueQuick(&r_shadow_deferred, 0);
2159 if (r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]) fbo = r_shadow_fbocubeside[r_shadow_shadowmaplod];
2160 r_shadow_shadowmap_texturescale[0] = 0.0f;
2161 r_shadow_shadowmap_texturescale[1] = 0.0f;
2162 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE;
2165 R_Shadow_RenderMode_Reset();
2168 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);CHECKGLERROR
2169 R_SetupShader_DepthOrShadow();
2173 R_SetupShader_ShowDepth();
2174 qglClearColor(1,1,1,1);CHECKGLERROR
2177 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
2184 R_SetViewport(&viewport);
2185 if(r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE)
2187 int flipped = (side & 1) ^ (side >> 2);
2188 r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
2189 r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
2190 GL_CullFace(r_refdef.view.cullface_back);
2191 if ((clear & ((2 << side) - 1)) == (1 << side)) // only clear if the side is the first in the mask
2193 // get tightest scissor rectangle that encloses all viewports in the clear mask
2194 int x1 = clear & 0x15 ? 0 : size;
2195 int x2 = clear & 0x2A ? 2 * size : size;
2196 int y1 = clear & 0x03 ? 0 : (clear & 0xC ? size : 2 * size);
2197 int y2 = clear & 0x30 ? 3 * size : (clear & 0xC ? 2 * size : size);
2198 GL_Scissor(x1, y1, x2 - x1, y2 - y1);
2199 GL_Clear(GL_DEPTH_BUFFER_BIT);
2201 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2203 else if(r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE)
2205 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
2206 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2208 GL_Clear(GL_DEPTH_BUFFER_BIT);
2213 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
2217 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2218 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2219 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2220 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2223 R_Shadow_RenderMode_Reset();
2224 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2227 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2231 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2232 // only draw light where this geometry was already rendered AND the
2233 // stencil is 128 (values other than this mean shadow)
2234 qglStencilFunc(GL_EQUAL, 128, 255);CHECKGLERROR
2236 r_shadow_rendermode = r_shadow_lightingrendermode;
2237 // do global setup needed for the chosen lighting mode
2238 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2240 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2245 if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
2246 r_shadow_usingshadowmap2d = true;
2247 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE)
2248 r_shadow_usingshadowmaprect = true;
2249 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
2250 r_shadow_usingshadowmapcube = true;
2252 R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
2256 static const unsigned short bboxelements[36] =
2266 static const float bboxpoints[8][3] =
2278 void R_Shadow_RenderMode_DrawDeferredLight(qboolean stenciltest, qboolean shadowmapping)
2281 float vertex3f[8*3];
2282 const matrix4x4_t *matrix = &rsurface.rtlight->matrix_lighttoworld;
2284 R_Shadow_RenderMode_Reset();
2285 r_shadow_rendermode = r_shadow_lightingrendermode;
2286 // do global setup needed for the chosen lighting mode
2288 R_EntityMatrix(&identitymatrix);
2289 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2292 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2293 // only draw light where this geometry was already rendered AND the
2294 // stencil is 128 (values other than this mean shadow)
2295 qglStencilFunc(GL_EQUAL, 128, 255);CHECKGLERROR
2297 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepasslightingfbo);CHECKGLERROR
2300 if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
2301 r_shadow_usingshadowmap2d = true;
2302 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE)
2303 r_shadow_usingshadowmaprect = true;
2304 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
2305 r_shadow_usingshadowmapcube = true;
2308 // render the lighting
2309 R_SetupShader_DeferredLight(rsurface.rtlight);
2310 for (i = 0;i < 8;i++)
2311 Matrix4x4_Transform(matrix, bboxpoints[i], vertex3f + i*3);
2313 R_Mesh_VertexPointer(vertex3f, 0, 0);
2314 R_Mesh_ColorPointer(NULL, 0, 0);
2315 GL_ColorMask(1,1,1,1);
2316 GL_DepthMask(false);
2317 GL_DepthRange(0, 1);
2318 GL_PolygonOffset(0, 0);
2320 qglDepthFunc(GL_GREATER);CHECKGLERROR
2321 GL_CullFace(r_refdef.view.cullface_back);
2322 R_Mesh_Draw(0, 8, 0, 12, NULL, bboxelements, 0, 0);
2326 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
2329 R_Shadow_RenderMode_Reset();
2330 GL_BlendFunc(GL_ONE, GL_ONE);
2331 GL_DepthRange(0, 1);
2332 GL_DepthTest(r_showshadowvolumes.integer < 2);
2333 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
2334 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2335 GL_CullFace(GL_NONE);
2336 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
2339 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
2342 R_Shadow_RenderMode_Reset();
2343 GL_BlendFunc(GL_ONE, GL_ONE);
2344 GL_DepthRange(0, 1);
2345 GL_DepthTest(r_showlighting.integer < 2);
2346 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2349 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2353 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2354 qglStencilFunc(GL_EQUAL, 128, 255);CHECKGLERROR
2356 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2359 void R_Shadow_RenderMode_End(void)
2362 R_Shadow_RenderMode_Reset();
2363 R_Shadow_RenderMode_ActiveLight(NULL);
2365 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2366 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2369 int bboxedges[12][2] =
2388 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2390 int i, ix1, iy1, ix2, iy2;
2391 float x1, y1, x2, y2;
2393 float vertex[20][3];
2402 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2403 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2404 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2405 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2407 if (!r_shadow_scissor.integer)
2410 // if view is inside the light box, just say yes it's visible
2411 if (BoxesOverlap(r_refdef.view.origin, r_refdef.view.origin, mins, maxs))
2414 x1 = y1 = x2 = y2 = 0;
2416 // transform all corners that are infront of the nearclip plane
2417 VectorNegate(r_refdef.view.frustum[4].normal, plane4f);
2418 plane4f[3] = r_refdef.view.frustum[4].dist;
2420 for (i = 0;i < 8;i++)
2422 Vector4Set(corner[i], (i & 1) ? maxs[0] : mins[0], (i & 2) ? maxs[1] : mins[1], (i & 4) ? maxs[2] : mins[2], 1);
2423 dist[i] = DotProduct4(corner[i], plane4f);
2424 sign[i] = dist[i] > 0;
2427 VectorCopy(corner[i], vertex[numvertices]);
2431 // if some points are behind the nearclip, add clipped edge points to make
2432 // sure that the scissor boundary is complete
2433 if (numvertices > 0 && numvertices < 8)
2435 // add clipped edge points
2436 for (i = 0;i < 12;i++)
2438 j = bboxedges[i][0];
2439 k = bboxedges[i][1];
2440 if (sign[j] != sign[k])
2442 f = dist[j] / (dist[j] - dist[k]);
2443 VectorLerp(corner[j], f, corner[k], vertex[numvertices]);
2449 // if we have no points to check, the light is behind the view plane
2453 // if we have some points to transform, check what screen area is covered
2454 x1 = y1 = x2 = y2 = 0;
2456 //Con_Printf("%i vertices to transform...\n", numvertices);
2457 for (i = 0;i < numvertices;i++)
2459 VectorCopy(vertex[i], v);
2460 R_Viewport_TransformToScreen(&r_refdef.view.viewport, v, v2);
2461 //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]);
2464 if (x1 > v2[0]) x1 = v2[0];
2465 if (x2 < v2[0]) x2 = v2[0];
2466 if (y1 > v2[1]) y1 = v2[1];
2467 if (y2 < v2[1]) y2 = v2[1];
2476 // now convert the scissor rectangle to integer screen coordinates
2477 ix1 = (int)(x1 - 1.0f);
2478 iy1 = vid.height - (int)(y2 - 1.0f);
2479 ix2 = (int)(x2 + 1.0f);
2480 iy2 = vid.height - (int)(y1 + 1.0f);
2481 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
2483 // clamp it to the screen
2484 if (ix1 < r_refdef.view.viewport.x) ix1 = r_refdef.view.viewport.x;
2485 if (iy1 < r_refdef.view.viewport.y) iy1 = r_refdef.view.viewport.y;
2486 if (ix2 > r_refdef.view.viewport.x + r_refdef.view.viewport.width) ix2 = r_refdef.view.viewport.x + r_refdef.view.viewport.width;
2487 if (iy2 > r_refdef.view.viewport.y + r_refdef.view.viewport.height) iy2 = r_refdef.view.viewport.y + r_refdef.view.viewport.height;
2489 // if it is inside out, it's not visible
2490 if (ix2 <= ix1 || iy2 <= iy1)
2493 // the light area is visible, set up the scissor rectangle
2494 r_shadow_lightscissor[0] = ix1;
2495 r_shadow_lightscissor[1] = iy1;
2496 r_shadow_lightscissor[2] = ix2 - ix1;
2497 r_shadow_lightscissor[3] = iy2 - iy1;
2499 r_refdef.stats.lights_scissored++;
2503 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, int numtriangles, const int *element3i, const float *diffusecolor, const float *ambientcolor)
2505 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
2506 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
2507 float *color4f = rsurface.array_color4f + 4 * firstvertex;
2508 float dist, dot, distintensity, shadeintensity, v[3], n[3];
2509 switch (r_shadow_rendermode)
2511 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2512 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2513 if (VectorLength2(diffusecolor) > 0)
2515 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2517 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2518 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2519 if ((dot = DotProduct(n, v)) < 0)
2521 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2522 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
2525 VectorCopy(ambientcolor, color4f);
2526 if (r_refdef.fogenabled)
2529 f = RSurf_FogVertex(vertex3f);
2530 VectorScale(color4f, f, color4f);
2537 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2539 VectorCopy(ambientcolor, color4f);
2540 if (r_refdef.fogenabled)
2543 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2544 f = RSurf_FogVertex(vertex3f);
2545 VectorScale(color4f, f, color4f);
2551 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2552 if (VectorLength2(diffusecolor) > 0)
2554 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2556 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2557 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2559 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2560 if ((dot = DotProduct(n, v)) < 0)
2562 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2563 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2564 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2565 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2569 color4f[0] = ambientcolor[0] * distintensity;
2570 color4f[1] = ambientcolor[1] * distintensity;
2571 color4f[2] = ambientcolor[2] * distintensity;
2573 if (r_refdef.fogenabled)
2576 f = RSurf_FogVertex(vertex3f);
2577 VectorScale(color4f, f, color4f);
2581 VectorClear(color4f);
2587 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2589 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2590 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2592 color4f[0] = ambientcolor[0] * distintensity;
2593 color4f[1] = ambientcolor[1] * distintensity;
2594 color4f[2] = ambientcolor[2] * distintensity;
2595 if (r_refdef.fogenabled)
2598 f = RSurf_FogVertex(vertex3f);
2599 VectorScale(color4f, f, color4f);
2603 VectorClear(color4f);
2608 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2609 if (VectorLength2(diffusecolor) > 0)
2611 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2613 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2614 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2616 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2617 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2618 if ((dot = DotProduct(n, v)) < 0)
2620 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2621 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2622 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2623 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2627 color4f[0] = ambientcolor[0] * distintensity;
2628 color4f[1] = ambientcolor[1] * distintensity;
2629 color4f[2] = ambientcolor[2] * distintensity;
2631 if (r_refdef.fogenabled)
2634 f = RSurf_FogVertex(vertex3f);
2635 VectorScale(color4f, f, color4f);
2639 VectorClear(color4f);
2645 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2647 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2648 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2650 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2651 color4f[0] = ambientcolor[0] * distintensity;
2652 color4f[1] = ambientcolor[1] * distintensity;
2653 color4f[2] = ambientcolor[2] * distintensity;
2654 if (r_refdef.fogenabled)
2657 f = RSurf_FogVertex(vertex3f);
2658 VectorScale(color4f, f, color4f);
2662 VectorClear(color4f);
2672 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)
2674 // used to display how many times a surface is lit for level design purposes
2675 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2678 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)
2680 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2681 R_SetupShader_Surface(lightcolor, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT);
2682 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2684 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2686 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2687 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2689 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
2693 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
2700 int newnumtriangles;
2704 int maxtriangles = 4096;
2705 static int newelements[4096*3];
2706 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, numtriangles, element3i, diffusecolor2, ambientcolor2);
2707 for (renders = 0;renders < 4;renders++)
2712 newnumtriangles = 0;
2714 // due to low fillrate on the cards this vertex lighting path is
2715 // designed for, we manually cull all triangles that do not
2716 // contain a lit vertex
2717 // this builds batches of triangles from multiple surfaces and
2718 // renders them at once
2719 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
2721 if (VectorLength2(rsurface.array_color4f + e[0] * 4) + VectorLength2(rsurface.array_color4f + e[1] * 4) + VectorLength2(rsurface.array_color4f + e[2] * 4) >= 0.01)
2723 if (newnumtriangles)
2725 newfirstvertex = min(newfirstvertex, e[0]);
2726 newlastvertex = max(newlastvertex, e[0]);
2730 newfirstvertex = e[0];
2731 newlastvertex = e[0];
2733 newfirstvertex = min(newfirstvertex, e[1]);
2734 newlastvertex = max(newlastvertex, e[1]);
2735 newfirstvertex = min(newfirstvertex, e[2]);
2736 newlastvertex = max(newlastvertex, e[2]);
2742 if (newnumtriangles >= maxtriangles)
2744 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
2745 newnumtriangles = 0;
2751 if (newnumtriangles >= 1)
2753 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
2756 // if we couldn't find any lit triangles, exit early
2759 // now reduce the intensity for the next overbright pass
2760 // we have to clamp to 0 here incase the drivers have improper
2761 // handling of negative colors
2762 // (some old drivers even have improper handling of >1 color)
2764 for (i = 0, c = rsurface.array_color4f + 4 * firstvertex;i < numvertices;i++, c += 4)
2766 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
2768 c[0] = max(0, c[0] - 1);
2769 c[1] = max(0, c[1] - 1);
2770 c[2] = max(0, c[2] - 1);
2782 static void R_Shadow_RenderLighting_Light_Vertex(int firstvertex, int numvertices, int numtriangles, const int *element3i, const vec3_t lightcolor, float ambientscale, float diffusescale)
2784 // OpenGL 1.1 path (anything)
2785 float ambientcolorbase[3], diffusecolorbase[3];
2786 float ambientcolorpants[3], diffusecolorpants[3];
2787 float ambientcolorshirt[3], diffusecolorshirt[3];
2788 const float *surfacecolor = rsurface.texture->dlightcolor;
2789 const float *surfacepants = rsurface.colormap_pantscolor;
2790 const float *surfaceshirt = rsurface.colormap_shirtcolor;
2791 rtexture_t *basetexture = rsurface.texture->basetexture;
2792 rtexture_t *pantstexture = rsurface.texture->pantstexture;
2793 rtexture_t *shirttexture = rsurface.texture->shirttexture;
2794 qboolean dopants = pantstexture && VectorLength2(surfacepants) >= (1.0f / 1048576.0f);
2795 qboolean doshirt = shirttexture && VectorLength2(surfaceshirt) >= (1.0f / 1048576.0f);
2796 ambientscale *= 2 * r_refdef.view.colorscale;
2797 diffusescale *= 2 * r_refdef.view.colorscale;
2798 ambientcolorbase[0] = lightcolor[0] * ambientscale * surfacecolor[0];ambientcolorbase[1] = lightcolor[1] * ambientscale * surfacecolor[1];ambientcolorbase[2] = lightcolor[2] * ambientscale * surfacecolor[2];
2799 diffusecolorbase[0] = lightcolor[0] * diffusescale * surfacecolor[0];diffusecolorbase[1] = lightcolor[1] * diffusescale * surfacecolor[1];diffusecolorbase[2] = lightcolor[2] * diffusescale * surfacecolor[2];
2800 ambientcolorpants[0] = ambientcolorbase[0] * surfacepants[0];ambientcolorpants[1] = ambientcolorbase[1] * surfacepants[1];ambientcolorpants[2] = ambientcolorbase[2] * surfacepants[2];
2801 diffusecolorpants[0] = diffusecolorbase[0] * surfacepants[0];diffusecolorpants[1] = diffusecolorbase[1] * surfacepants[1];diffusecolorpants[2] = diffusecolorbase[2] * surfacepants[2];
2802 ambientcolorshirt[0] = ambientcolorbase[0] * surfaceshirt[0];ambientcolorshirt[1] = ambientcolorbase[1] * surfaceshirt[1];ambientcolorshirt[2] = ambientcolorbase[2] * surfaceshirt[2];
2803 diffusecolorshirt[0] = diffusecolorbase[0] * surfaceshirt[0];diffusecolorshirt[1] = diffusecolorbase[1] * surfaceshirt[1];diffusecolorshirt[2] = diffusecolorbase[2] * surfaceshirt[2];
2804 R_Mesh_TexBind(0, basetexture);
2805 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
2806 R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
2807 R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
2808 switch(r_shadow_rendermode)
2810 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2811 R_Mesh_TexBind(1, r_shadow_attenuation3dtexture);
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_VERTEX2D1DATTEN:
2817 R_Mesh_TexBind(2, r_shadow_attenuation2dtexture);
2818 R_Mesh_TexMatrix(2, &rsurface.entitytoattenuationz);
2819 R_Mesh_TexCombine(2, GL_MODULATE, GL_MODULATE, 1, 1);
2820 R_Mesh_TexCoordPointer(2, 3, rsurface.vertex3f, rsurface.vertex3f_bufferobject, rsurface.vertex3f_bufferoffset);
2822 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2823 R_Mesh_TexBind(1, r_shadow_attenuation2dtexture);
2824 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
2825 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
2826 R_Mesh_TexCoordPointer(1, 3, rsurface.vertex3f, rsurface.vertex3f_bufferobject, rsurface.vertex3f_bufferoffset);
2828 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2833 //R_Mesh_TexBind(0, basetexture);
2834 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorbase, ambientcolorbase);
2837 R_Mesh_TexBind(0, pantstexture);
2838 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorpants, ambientcolorpants);
2842 R_Mesh_TexBind(0, shirttexture);
2843 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorshirt, ambientcolorshirt);
2847 extern cvar_t gl_lightmaps;
2848 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)
2850 float ambientscale, diffusescale, specularscale;
2852 float lightcolor[3];
2853 VectorCopy(rsurface.rtlight->currentcolor, lightcolor);
2854 ambientscale = rsurface.rtlight->ambientscale;
2855 diffusescale = rsurface.rtlight->diffusescale;
2856 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
2857 if (!r_shadow_usenormalmap.integer)
2859 ambientscale += 1.0f * diffusescale;
2863 if ((ambientscale + diffusescale) * VectorLength2(lightcolor) + specularscale * VectorLength2(lightcolor) < (1.0f / 1048576.0f))
2865 negated = (lightcolor[0] + lightcolor[1] + lightcolor[2] < 0) && vid.support.ext_blend_subtract;
2868 VectorNegate(lightcolor, lightcolor);
2869 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
2871 RSurf_SetupDepthAndCulling();
2872 switch (r_shadow_rendermode)
2874 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2875 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2876 R_Shadow_RenderLighting_VisibleLighting(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2878 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2879 R_Shadow_RenderLighting_Light_GLSL(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolor, ambientscale, diffusescale, specularscale);
2881 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2882 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2883 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2884 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2885 R_Shadow_RenderLighting_Light_Vertex(firstvertex, numvertices, numtriangles, element3i + firsttriangle * 3, lightcolor, ambientscale, diffusescale);
2888 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2892 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
2895 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)
2897 matrix4x4_t tempmatrix = *matrix;
2898 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
2900 // if this light has been compiled before, free the associated data
2901 R_RTLight_Uncompile(rtlight);
2903 // clear it completely to avoid any lingering data
2904 memset(rtlight, 0, sizeof(*rtlight));
2906 // copy the properties
2907 rtlight->matrix_lighttoworld = tempmatrix;
2908 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
2909 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
2910 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
2911 VectorCopy(color, rtlight->color);
2912 rtlight->cubemapname[0] = 0;
2913 if (cubemapname && cubemapname[0])
2914 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
2915 rtlight->shadow = shadow;
2916 rtlight->corona = corona;
2917 rtlight->style = style;
2918 rtlight->isstatic = isstatic;
2919 rtlight->coronasizescale = coronasizescale;
2920 rtlight->ambientscale = ambientscale;
2921 rtlight->diffusescale = diffusescale;
2922 rtlight->specularscale = specularscale;
2923 rtlight->flags = flags;
2925 // compute derived data
2926 //rtlight->cullradius = rtlight->radius;
2927 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2928 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2929 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2930 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2931 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2932 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2933 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2936 // compiles rtlight geometry
2937 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2938 void R_RTLight_Compile(rtlight_t *rtlight)
2941 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
2942 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
2943 entity_render_t *ent = r_refdef.scene.worldentity;
2944 dp_model_t *model = r_refdef.scene.worldmodel;
2945 unsigned char *data;
2948 // compile the light
2949 rtlight->compiled = true;
2950 rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
2951 rtlight->static_numleafs = 0;
2952 rtlight->static_numleafpvsbytes = 0;
2953 rtlight->static_leaflist = NULL;
2954 rtlight->static_leafpvs = NULL;
2955 rtlight->static_numsurfaces = 0;
2956 rtlight->static_surfacelist = NULL;
2957 rtlight->static_shadowmap_receivers = 0x3F;
2958 rtlight->static_shadowmap_casters = 0x3F;
2959 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2960 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2961 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2962 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2963 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2964 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2966 if (model && model->GetLightInfo)
2968 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
2969 r_shadow_compilingrtlight = rtlight;
2970 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);
2971 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2972 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
2973 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
2974 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
2975 rtlight->static_numsurfaces = numsurfaces;
2976 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
2977 rtlight->static_numleafs = numleafs;
2978 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
2979 rtlight->static_numleafpvsbytes = numleafpvsbytes;
2980 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
2981 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
2982 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
2983 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
2984 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
2985 if (rtlight->static_numsurfaces)
2986 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
2987 if (rtlight->static_numleafs)
2988 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
2989 if (rtlight->static_numleafpvsbytes)
2990 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
2991 if (rtlight->static_numshadowtrispvsbytes)
2992 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
2993 if (rtlight->static_numlighttrispvsbytes)
2994 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
2995 switch (rtlight->shadowmode)
2997 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2998 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
2999 case R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE:
3000 if (model->CompileShadowMap && rtlight->shadow)
3001 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3004 if (model->CompileShadowVolume && rtlight->shadow)
3005 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3008 // now we're done compiling the rtlight
3009 r_shadow_compilingrtlight = NULL;
3013 // use smallest available cullradius - box radius or light radius
3014 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3015 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3017 shadowzpasstris = 0;
3018 if (rtlight->static_meshchain_shadow_zpass)
3019 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
3020 shadowzpasstris += mesh->numtriangles;
3022 shadowzfailtris = 0;
3023 if (rtlight->static_meshchain_shadow_zfail)
3024 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
3025 shadowzfailtris += mesh->numtriangles;
3028 if (rtlight->static_numlighttrispvsbytes)
3029 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3030 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3034 if (rtlight->static_numlighttrispvsbytes)
3035 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3036 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3039 if (developer_extra.integer)
3040 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);
3043 void R_RTLight_Uncompile(rtlight_t *rtlight)
3045 if (rtlight->compiled)
3047 if (rtlight->static_meshchain_shadow_zpass)
3048 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
3049 rtlight->static_meshchain_shadow_zpass = NULL;
3050 if (rtlight->static_meshchain_shadow_zfail)
3051 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
3052 rtlight->static_meshchain_shadow_zfail = NULL;
3053 if (rtlight->static_meshchain_shadow_shadowmap)
3054 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
3055 rtlight->static_meshchain_shadow_shadowmap = NULL;
3056 // these allocations are grouped
3057 if (rtlight->static_surfacelist)
3058 Mem_Free(rtlight->static_surfacelist);
3059 rtlight->static_numleafs = 0;
3060 rtlight->static_numleafpvsbytes = 0;
3061 rtlight->static_leaflist = NULL;
3062 rtlight->static_leafpvs = NULL;
3063 rtlight->static_numsurfaces = 0;
3064 rtlight->static_surfacelist = NULL;
3065 rtlight->static_numshadowtrispvsbytes = 0;
3066 rtlight->static_shadowtrispvs = NULL;
3067 rtlight->static_numlighttrispvsbytes = 0;
3068 rtlight->static_lighttrispvs = NULL;
3069 rtlight->compiled = false;
3073 void R_Shadow_UncompileWorldLights(void)
3077 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3078 for (lightindex = 0;lightindex < range;lightindex++)
3080 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3083 R_RTLight_Uncompile(&light->rtlight);
3087 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3091 // reset the count of frustum planes
3092 // see rtlight->cached_frustumplanes definition for how much this array
3094 rtlight->cached_numfrustumplanes = 0;
3096 // haven't implemented a culling path for ortho rendering
3097 if (!r_refdef.view.useperspective)
3099 // check if the light is on screen and copy the 4 planes if it is
3100 for (i = 0;i < 4;i++)
3101 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3104 for (i = 0;i < 4;i++)
3105 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3110 // generate a deformed frustum that includes the light origin, this is
3111 // used to cull shadow casting surfaces that can not possibly cast a
3112 // shadow onto the visible light-receiving surfaces, which can be a
3115 // if the light origin is onscreen the result will be 4 planes exactly
3116 // if the light origin is offscreen on only one axis the result will
3117 // be exactly 5 planes (split-side case)
3118 // if the light origin is offscreen on two axes the result will be
3119 // exactly 4 planes (stretched corner case)
3120 for (i = 0;i < 4;i++)
3122 // quickly reject standard frustum planes that put the light
3123 // origin outside the frustum
3124 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3127 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3129 // if all the standard frustum planes were accepted, the light is onscreen
3130 // otherwise we need to generate some more planes below...
3131 if (rtlight->cached_numfrustumplanes < 4)
3133 // at least one of the stock frustum planes failed, so we need to
3134 // create one or two custom planes to enclose the light origin
3135 for (i = 0;i < 4;i++)
3137 // create a plane using the view origin and light origin, and a
3138 // single point from the frustum corner set
3139 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3140 VectorNormalize(plane.normal);
3141 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3142 // see if this plane is backwards and flip it if so
3143 for (j = 0;j < 4;j++)
3144 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3148 VectorNegate(plane.normal, plane.normal);
3150 // flipped plane, test again to see if it is now valid
3151 for (j = 0;j < 4;j++)
3152 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3154 // if the plane is still not valid, then it is dividing the
3155 // frustum and has to be rejected
3159 // we have created a valid plane, compute extra info
3160 PlaneClassify(&plane);
3162 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3164 // if we've found 5 frustum planes then we have constructed a
3165 // proper split-side case and do not need to keep searching for
3166 // planes to enclose the light origin
3167 if (rtlight->cached_numfrustumplanes == 5)
3175 for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
3177 plane = rtlight->cached_frustumplanes[i];
3178 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));
3183 // now add the light-space box planes if the light box is rotated, as any
3184 // caster outside the oriented light box is irrelevant (even if it passed
3185 // the worldspace light box, which is axial)
3186 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3188 for (i = 0;i < 6;i++)
3192 v[i >> 1] = (i & 1) ? -1 : 1;
3193 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3194 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3195 plane.dist = VectorNormalizeLength(plane.normal);
3196 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3197 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3203 // add the world-space reduced box planes
3204 for (i = 0;i < 6;i++)
3206 VectorClear(plane.normal);
3207 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3208 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
3209 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3218 // reduce all plane distances to tightly fit the rtlight cull box, which
3220 VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3221 VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3222 VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3223 VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3224 VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3225 VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3226 VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3227 VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3228 oldnum = rtlight->cached_numfrustumplanes;
3229 rtlight->cached_numfrustumplanes = 0;
3230 for (j = 0;j < oldnum;j++)
3232 // find the nearest point on the box to this plane
3233 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
3234 for (i = 1;i < 8;i++)
3236 dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
3237 if (bestdist > dist)
3240 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);
3241 // if the nearest point is near or behind the plane, we want this
3242 // plane, otherwise the plane is useless as it won't cull anything
3243 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
3245 PlaneClassify(&rtlight->cached_frustumplanes[j]);
3246 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
3253 void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
3257 RSurf_ActiveWorldEntity();
3259 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3262 GL_CullFace(GL_NONE);
3263 mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3264 for (;mesh;mesh = mesh->next)
3266 if (!mesh->sidetotals[r_shadow_shadowmapside])
3268 r_refdef.stats.lights_shadowtriangles += mesh->sidetotals[r_shadow_shadowmapside];
3269 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
3270 R_Mesh_Draw(0, mesh->numverts, mesh->sideoffsets[r_shadow_shadowmapside], mesh->sidetotals[r_shadow_shadowmapside], mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3274 else if (r_refdef.scene.worldentity->model)
3275 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);
3277 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3280 void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3282 qboolean zpass = false;
3285 int surfacelistindex;
3286 msurface_t *surface;
3288 RSurf_ActiveWorldEntity();
3290 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3293 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
3295 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
3296 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
3298 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
3299 for (;mesh;mesh = mesh->next)
3301 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
3302 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
3303 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
3305 // increment stencil if frontface is infront of depthbuffer
3306 GL_CullFace(r_refdef.view.cullface_back);
3307 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
3308 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3309 // decrement stencil if backface is infront of depthbuffer
3310 GL_CullFace(r_refdef.view.cullface_front);
3311 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
3313 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
3315 // decrement stencil if backface is behind depthbuffer
3316 GL_CullFace(r_refdef.view.cullface_front);
3317 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
3318 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3319 // increment stencil if frontface is behind depthbuffer
3320 GL_CullFace(r_refdef.view.cullface_back);
3321 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
3323 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3327 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh)
3329 // use the shadow trispvs calculated earlier by GetLightInfo to cull world triangles on this dynamic light
3330 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
3331 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
3333 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
3334 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
3335 if (CHECKPVSBIT(trispvs, t))
3336 shadowmarklist[numshadowmark++] = t;
3338 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);
3340 else if (numsurfaces)
3341 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);
3343 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3346 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3348 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3349 vec_t relativeshadowradius;
3350 RSurf_ActiveModelEntity(ent, false, false, false);
3351 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3352 // we need to re-init the shader for each entity because the matrix changed
3353 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3354 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3355 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3356 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3357 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3358 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3359 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3360 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D)
3362 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
3365 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3366 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3369 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3371 // set up properties for rendering light onto this entity
3372 RSurf_ActiveModelEntity(ent, true, true, false);
3373 GL_AlphaTest(false);
3374 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3375 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3376 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3377 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3380 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
3382 if (!r_refdef.scene.worldmodel->DrawLight)
3385 // set up properties for rendering light onto this entity
3386 RSurf_ActiveWorldEntity();
3387 GL_AlphaTest(false);
3388 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3389 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3390 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3391 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3393 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
3395 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3398 void R_Shadow_DrawEntityLight(entity_render_t *ent)
3400 dp_model_t *model = ent->model;
3401 if (!model->DrawLight)
3404 R_Shadow_SetupEntityLight(ent);
3406 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3408 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3411 void R_Shadow_PrepareLight(rtlight_t *rtlight)
3415 int numleafs, numsurfaces;
3416 int *leaflist, *surfacelist;
3417 unsigned char *leafpvs, *shadowtrispvs, *lighttrispvs, *surfacesides;
3418 int numlightentities;
3419 int numlightentities_noselfshadow;
3420 int numshadowentities;
3421 int numshadowentities_noselfshadow;
3422 static entity_render_t *lightentities[MAX_EDICTS];
3423 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3424 static entity_render_t *shadowentities[MAX_EDICTS];
3425 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3427 rtlight->draw = false;
3429 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3430 // skip lights that are basically invisible (color 0 0 0)
3431 if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
3434 // loading is done before visibility checks because loading should happen
3435 // all at once at the start of a level, not when it stalls gameplay.
3436 // (especially important to benchmarks)
3438 if (rtlight->isstatic && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
3440 if (rtlight->compiled)
3441 R_RTLight_Uncompile(rtlight);
3442 R_RTLight_Compile(rtlight);
3446 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
3448 // look up the light style value at this time
3449 f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3450 VectorScale(rtlight->color, f, rtlight->currentcolor);
3452 if (rtlight->selected)
3454 f = 2 + sin(realtime * M_PI * 4.0);
3455 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3459 // if lightstyle is currently off, don't draw the light
3460 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3463 // if the light box is offscreen, skip it
3464 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3467 VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
3468 VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
3470 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3472 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3474 // compiled light, world available and can receive realtime lighting
3475 // retrieve leaf information
3476 numleafs = rtlight->static_numleafs;
3477 leaflist = rtlight->static_leaflist;
3478 leafpvs = rtlight->static_leafpvs;
3479 numsurfaces = rtlight->static_numsurfaces;
3480 surfacelist = rtlight->static_surfacelist;
3481 surfacesides = NULL;
3482 shadowtrispvs = rtlight->static_shadowtrispvs;
3483 lighttrispvs = rtlight->static_lighttrispvs;
3485 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3487 // dynamic light, world available and can receive realtime lighting
3488 // calculate lit surfaces and leafs
3489 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);
3490 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3491 leaflist = r_shadow_buffer_leaflist;
3492 leafpvs = r_shadow_buffer_leafpvs;
3493 surfacelist = r_shadow_buffer_surfacelist;
3494 surfacesides = r_shadow_buffer_surfacesides;
3495 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3496 lighttrispvs = r_shadow_buffer_lighttrispvs;
3497 // if the reduced leaf bounds are offscreen, skip it
3498 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3509 surfacesides = NULL;
3510 shadowtrispvs = NULL;
3511 lighttrispvs = NULL;
3513 // check if light is illuminating any visible leafs
3516 for (i = 0;i < numleafs;i++)
3517 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3523 // make a list of lit entities and shadow casting entities
3524 numlightentities = 0;
3525 numlightentities_noselfshadow = 0;
3526 numshadowentities = 0;
3527 numshadowentities_noselfshadow = 0;
3529 // add dynamic entities that are lit by the light
3530 for (i = 0;i < r_refdef.scene.numentities;i++)
3533 entity_render_t *ent = r_refdef.scene.entities[i];
3535 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3537 // skip the object entirely if it is not within the valid
3538 // shadow-casting region (which includes the lit region)
3539 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
3541 if (!(model = ent->model))
3543 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
3545 // this entity wants to receive light, is visible, and is
3546 // inside the light box
3547 // TODO: check if the surfaces in the model can receive light
3548 // so now check if it's in a leaf seen by the light
3549 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))
3551 if (ent->flags & RENDER_NOSELFSHADOW)
3552 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
3554 lightentities[numlightentities++] = ent;
3555 // since it is lit, it probably also casts a shadow...
3556 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3557 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3558 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3560 // note: exterior models without the RENDER_NOSELFSHADOW
3561 // flag still create a RENDER_NOSELFSHADOW shadow but
3562 // are lit normally, this means that they are
3563 // self-shadowing but do not shadow other
3564 // RENDER_NOSELFSHADOW entities such as the gun
3565 // (very weird, but keeps the player shadow off the gun)
3566 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3567 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3569 shadowentities[numshadowentities++] = ent;
3572 else if (ent->flags & RENDER_SHADOW)
3574 // this entity is not receiving light, but may still need to
3576 // TODO: check if the surfaces in the model can cast shadow
3577 // now check if it is in a leaf seen by the light
3578 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))
3580 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3581 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3582 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3584 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3585 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3587 shadowentities[numshadowentities++] = ent;
3592 // return if there's nothing at all to light
3593 if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
3596 // count this light in the r_speeds
3597 r_refdef.stats.lights++;
3599 // flag it as worth drawing later
3600 rtlight->draw = true;
3602 // cache all the animated entities that cast a shadow but are not visible
3603 for (i = 0;i < numshadowentities;i++)
3604 if (!shadowentities[i]->animcache_vertex3f)
3605 R_AnimCache_GetEntity(shadowentities[i], false, false);
3606 for (i = 0;i < numshadowentities_noselfshadow;i++)
3607 if (!shadowentities_noselfshadow[i]->animcache_vertex3f)
3608 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
3610 // allocate some temporary memory for rendering this light later in the frame
3611 // reusable buffers need to be copied, static data can be used as-is
3612 rtlight->cached_numlightentities = numlightentities;
3613 rtlight->cached_numlightentities_noselfshadow = numlightentities_noselfshadow;
3614 rtlight->cached_numshadowentities = numshadowentities;
3615 rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
3616 rtlight->cached_numsurfaces = numsurfaces;
3617 rtlight->cached_lightentities = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
3618 rtlight->cached_lightentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
3619 rtlight->cached_shadowentities = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
3620 rtlight->cached_shadowentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
3621 if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
3623 int numshadowtrispvsbytes = (((r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles) + 7) >> 3);
3624 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
3625 rtlight->cached_shadowtrispvs = (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
3626 rtlight->cached_lighttrispvs = (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
3627 rtlight->cached_surfacelist = (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
3631 // compiled light data
3632 rtlight->cached_shadowtrispvs = shadowtrispvs;
3633 rtlight->cached_lighttrispvs = lighttrispvs;
3634 rtlight->cached_surfacelist = surfacelist;
3638 void R_Shadow_DrawLight(rtlight_t *rtlight)
3642 unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
3643 int numlightentities;
3644 int numlightentities_noselfshadow;
3645 int numshadowentities;
3646 int numshadowentities_noselfshadow;
3647 entity_render_t **lightentities;
3648 entity_render_t **lightentities_noselfshadow;
3649 entity_render_t **shadowentities;
3650 entity_render_t **shadowentities_noselfshadow;
3652 static unsigned char entitysides[MAX_EDICTS];
3653 static unsigned char entitysides_noselfshadow[MAX_EDICTS];
3654 vec3_t nearestpoint;
3656 qboolean castshadows;
3659 // check if we cached this light this frame (meaning it is worth drawing)
3663 // if R_FrameData_Store ran out of space we skip anything dependent on it
3664 if (r_framedata_failed)
3667 numlightentities = rtlight->cached_numlightentities;
3668 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
3669 numshadowentities = rtlight->cached_numshadowentities;
3670 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
3671 numsurfaces = rtlight->cached_numsurfaces;
3672 lightentities = rtlight->cached_lightentities;
3673 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
3674 shadowentities = rtlight->cached_shadowentities;
3675 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
3676 shadowtrispvs = rtlight->cached_shadowtrispvs;
3677 lighttrispvs = rtlight->cached_lighttrispvs;
3678 surfacelist = rtlight->cached_surfacelist;
3680 // set up a scissor rectangle for this light
3681 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3684 // don't let sound skip if going slow
3685 if (r_refdef.scene.extraupdate)
3688 // make this the active rtlight for rendering purposes
3689 R_Shadow_RenderMode_ActiveLight(rtlight);
3691 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
3693 // optionally draw visible shape of the shadow volumes
3694 // for performance analysis by level designers
3695 R_Shadow_RenderMode_VisibleShadowVolumes();
3697 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
3698 for (i = 0;i < numshadowentities;i++)
3699 R_Shadow_DrawEntityShadow(shadowentities[i]);
3700 for (i = 0;i < numshadowentities_noselfshadow;i++)
3701 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3702 R_Shadow_RenderMode_VisibleLighting(false, false);
3705 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
3707 // optionally draw the illuminated areas
3708 // for performance analysis by level designers
3709 R_Shadow_RenderMode_VisibleLighting(false, false);
3711 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3712 for (i = 0;i < numlightentities;i++)
3713 R_Shadow_DrawEntityLight(lightentities[i]);
3714 for (i = 0;i < numlightentities_noselfshadow;i++)
3715 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3718 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
3720 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
3721 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
3722 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
3723 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
3725 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance/rtlight->radius));
3726 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
3727 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
3729 if (castshadows && (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE))
3735 int receivermask = 0;
3736 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
3737 Matrix4x4_Abs(&radiustolight);
3739 r_shadow_shadowmaplod = 0;
3740 for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
3741 if ((r_shadow_shadowmapmaxsize >> i) > lodlinear)
3742 r_shadow_shadowmaplod = i;
3744 if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
3745 size = max(1, r_shadow_shadowmapmaxsize >> r_shadow_shadowmaplod);
3747 size = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
3749 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
3751 surfacesides = NULL;
3754 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3756 castermask = rtlight->static_shadowmap_casters;
3757 receivermask = rtlight->static_shadowmap_receivers;
3761 surfacesides = r_shadow_buffer_surfacesides;
3762 for(i = 0;i < numsurfaces;i++)
3764 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
3765 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3766 castermask |= surfacesides[i];
3767 receivermask |= surfacesides[i];
3771 if (receivermask < 0x3F)
3773 for (i = 0;i < numlightentities;i++)
3774 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3775 if (receivermask < 0x3F)
3776 for(i = 0; i < numlightentities_noselfshadow;i++)
3777 receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3780 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
3784 for (i = 0;i < numshadowentities;i++)
3785 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3786 for (i = 0;i < numshadowentities_noselfshadow;i++)
3787 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3790 //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
3792 // render shadow casters into 6 sided depth texture
3793 for (side = 0;side < 6;side++) if (receivermask & (1 << side))
3795 R_Shadow_RenderMode_ShadowMap(side, receivermask, size);
3796 if (! (castermask & (1 << side))) continue;
3798 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
3799 for (i = 0;i < numshadowentities;i++) if (entitysides[i] & (1 << side))
3800 R_Shadow_DrawEntityShadow(shadowentities[i]);
3803 if (numlightentities_noselfshadow)
3805 // render lighting using the depth texture as shadowmap
3806 // draw lighting in the unmasked areas
3807 R_Shadow_RenderMode_Lighting(false, false, true);
3808 for (i = 0;i < numlightentities_noselfshadow;i++)
3809 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3812 // render shadow casters into 6 sided depth texture
3813 if (numshadowentities_noselfshadow)
3815 for (side = 0;side < 6;side++) if ((receivermask & castermask) & (1 << side))
3817 R_Shadow_RenderMode_ShadowMap(side, 0, size);
3818 for (i = 0;i < numshadowentities_noselfshadow;i++) if (entitysides_noselfshadow[i] & (1 << side))
3819 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3823 // render lighting using the depth texture as shadowmap
3824 // draw lighting in the unmasked areas
3825 R_Shadow_RenderMode_Lighting(false, false, true);
3826 // draw lighting in the unmasked areas
3828 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3829 for (i = 0;i < numlightentities;i++)
3830 R_Shadow_DrawEntityLight(lightentities[i]);
3832 else if (castshadows && vid.stencil)
3834 // draw stencil shadow volumes to mask off pixels that are in shadow
3835 // so that they won't receive lighting
3836 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
3837 R_Shadow_ClearStencil();
3840 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
3841 for (i = 0;i < numshadowentities;i++)
3842 R_Shadow_DrawEntityShadow(shadowentities[i]);
3844 // draw lighting in the unmasked areas
3845 R_Shadow_RenderMode_Lighting(true, false, false);
3846 for (i = 0;i < numlightentities_noselfshadow;i++)
3847 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3849 for (i = 0;i < numshadowentities_noselfshadow;i++)
3850 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3852 // draw lighting in the unmasked areas
3853 R_Shadow_RenderMode_Lighting(true, false, false);
3855 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3856 for (i = 0;i < numlightentities;i++)
3857 R_Shadow_DrawEntityLight(lightentities[i]);
3861 // draw lighting in the unmasked areas
3862 R_Shadow_RenderMode_Lighting(false, false, false);
3864 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3865 for (i = 0;i < numlightentities;i++)
3866 R_Shadow_DrawEntityLight(lightentities[i]);
3867 for (i = 0;i < numlightentities_noselfshadow;i++)
3868 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3871 if (r_shadow_usingdeferredprepass)
3873 // when rendering deferred lighting, we simply rasterize the box
3874 if (castshadows && (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE))
3875 R_Shadow_RenderMode_DrawDeferredLight(false, true);
3876 else if (castshadows && vid.stencil)
3877 R_Shadow_RenderMode_DrawDeferredLight(true, false);
3879 R_Shadow_RenderMode_DrawDeferredLight(false, false);
3883 static void R_Shadow_FreeDeferred(void)
3885 if (r_shadow_prepassgeometryfbo)
3886 qglDeleteFramebuffersEXT(1, &r_shadow_prepassgeometryfbo);CHECKGLERROR
3887 r_shadow_prepassgeometryfbo = 0;
3889 if (r_shadow_prepasslightingfbo)
3890 qglDeleteFramebuffersEXT(1, &r_shadow_prepasslightingfbo);CHECKGLERROR
3891 r_shadow_prepasslightingfbo = 0;
3893 if (r_shadow_prepassgeometrydepthtexture)
3894 R_FreeTexture(r_shadow_prepassgeometrydepthtexture);
3895 r_shadow_prepassgeometrydepthtexture = NULL;
3897 if (r_shadow_prepassgeometrynormalmaptexture)
3898 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
3899 r_shadow_prepassgeometrynormalmaptexture = NULL;
3901 if (r_shadow_prepasslightingdiffusetexture)
3902 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
3903 r_shadow_prepasslightingdiffusetexture = NULL;
3905 if (r_shadow_prepasslightingspeculartexture)
3906 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
3907 r_shadow_prepasslightingspeculartexture = NULL;
3910 void R_Shadow_DrawPrepass(void)
3918 entity_render_t *ent;
3920 GL_AlphaTest(false);
3921 R_Mesh_ColorPointer(NULL, 0, 0);
3922 R_Mesh_ResetTextureState();
3924 GL_ColorMask(1,1,1,1);
3925 GL_BlendFunc(GL_ONE, GL_ZERO);
3928 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepassgeometryfbo);CHECKGLERROR
3929 qglClearColor(0.5f,0.5f,0.5f,1.0f);CHECKGLERROR
3930 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);CHECKGLERROR
3932 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
3933 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
3934 if (r_timereport_active)
3935 R_TimeReport("prepassworld");
3937 for (i = 0;i < r_refdef.scene.numentities;i++)
3939 if (!r_refdef.viewcache.entityvisible[i])
3941 ent = r_refdef.scene.entities[i];
3942 if (ent->model && ent->model->DrawPrepass != NULL)
3943 ent->model->DrawPrepass(ent);
3946 if (r_timereport_active)
3947 R_TimeReport("prepassmodels");
3949 GL_DepthMask(false);
3950 GL_ColorMask(1,1,1,1);
3953 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepasslightingfbo);CHECKGLERROR
3954 qglClearColor(0.0f,0.0f,0.0f,0.0f);CHECKGLERROR
3955 GL_Clear(GL_COLOR_BUFFER_BIT);CHECKGLERROR
3956 if (r_refdef.fogenabled)
3957 qglClearColor(r_refdef.fogcolor[0],r_refdef.fogcolor[1],r_refdef.fogcolor[2],0);CHECKGLERROR
3959 R_Shadow_RenderMode_Begin();
3961 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3962 if (r_shadow_debuglight.integer >= 0)
3964 lightindex = r_shadow_debuglight.integer;
3965 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3966 if (light && (light->flags & flag))
3967 R_Shadow_DrawLight(&light->rtlight);
3971 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3972 for (lightindex = 0;lightindex < range;lightindex++)
3974 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3975 if (light && (light->flags & flag))
3976 R_Shadow_DrawLight(&light->rtlight);
3979 if (r_refdef.scene.rtdlight)
3980 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
3981 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
3983 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);CHECKGLERROR
3984 if (r_refdef.fogenabled)
3985 qglClearColor(r_refdef.fogcolor[0],r_refdef.fogcolor[1],r_refdef.fogcolor[2],0);CHECKGLERROR
3987 R_Shadow_RenderMode_End();
3989 if (r_timereport_active)
3990 R_TimeReport("prepasslights");
3993 void R_Shadow_DrawLightSprites(void);
3994 void R_Shadow_PrepareLights(void)
4004 if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4) ||
4005 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
4006 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0) ||
4007 r_shadow_shadowmaptexturetype != r_shadow_shadowmapping_texturetype.integer ||
4008 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
4009 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
4010 r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
4011 R_Shadow_FreeShadowMaps();
4013 switch (vid.renderpath)
4015 case RENDERPATH_GL20:
4016 case RENDERPATH_CGGL:
4017 if (!r_shadow_deferred.integer || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_STENCIL || !vid.support.ext_framebuffer_object || vid.maxdrawbuffers < 2)
4019 r_shadow_usingdeferredprepass = false;
4020 if (r_shadow_prepass_width)
4021 R_Shadow_FreeDeferred();
4022 r_shadow_prepass_width = r_shadow_prepass_height = 0;
4026 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
4028 R_Shadow_FreeDeferred();
4030 r_shadow_usingdeferredprepass = true;
4031 r_shadow_prepass_width = vid.width;
4032 r_shadow_prepass_height = vid.height;
4033 r_shadow_prepassgeometrydepthtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "prepassgeometrydepthmap", vid.width, vid.height, 24, false);
4034 r_shadow_prepassgeometrynormalmaptexture = R_LoadTexture2D(r_shadow_texturepool, "prepassgeometrynormalmap", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, NULL);
4035 r_shadow_prepasslightingdiffusetexture = R_LoadTexture2D(r_shadow_texturepool, "prepasslightingdiffuse", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, NULL);
4036 r_shadow_prepasslightingspeculartexture = R_LoadTexture2D(r_shadow_texturepool, "prepasslightingspecular", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, NULL);
4038 // set up the geometry pass fbo (depth + normalmap)
4039 qglGenFramebuffersEXT(1, &r_shadow_prepassgeometryfbo);CHECKGLERROR
4040 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepassgeometryfbo);CHECKGLERROR
4041 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_prepassgeometrydepthtexture), 0);CHECKGLERROR
4042 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_prepassgeometrynormalmaptexture), 0);CHECKGLERROR
4043 // render depth into one texture and normalmap into the other
4044 if (qglDrawBuffersARB)
4046 qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);CHECKGLERROR
4047 qglReadBuffer(GL_NONE);CHECKGLERROR
4049 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4050 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4052 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4053 Cvar_SetValueQuick(&r_shadow_deferred, 0);
4054 r_shadow_usingdeferredprepass = false;
4057 // set up the lighting pass fbo (diffuse + specular)
4058 qglGenFramebuffersEXT(1, &r_shadow_prepasslightingfbo);CHECKGLERROR
4059 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepasslightingfbo);CHECKGLERROR
4060 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_prepassgeometrydepthtexture), 0);CHECKGLERROR
4061 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_prepasslightingdiffusetexture), 0);CHECKGLERROR
4062 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_prepasslightingspeculartexture), 0);CHECKGLERROR
4063 // render diffuse into one texture and specular into another,
4064 // with depth and normalmap bound as textures,
4065 // with depth bound as attachment as well
4066 if (qglDrawBuffersARB)
4068 qglDrawBuffersARB(2, r_shadow_prepasslightingdrawbuffers);CHECKGLERROR
4069 qglReadBuffer(GL_NONE);CHECKGLERROR
4071 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4072 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4074 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4075 Cvar_SetValueQuick(&r_shadow_deferred, 0);
4076 r_shadow_usingdeferredprepass = false;
4080 case RENDERPATH_GL13:
4081 case RENDERPATH_GL11:
4082 r_shadow_usingdeferredprepass = false;
4086 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);
4088 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4089 if (r_shadow_debuglight.integer >= 0)
4091 lightindex = r_shadow_debuglight.integer;
4092 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4093 if (light && (light->flags & flag))
4094 R_Shadow_PrepareLight(&light->rtlight);
4098 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4099 for (lightindex = 0;lightindex < range;lightindex++)
4101 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4102 if (light && (light->flags & flag))
4103 R_Shadow_PrepareLight(&light->rtlight);
4106 if (r_refdef.scene.rtdlight)
4108 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4109 R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
4111 else if(gl_flashblend.integer)
4113 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4115 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
4116 f = (rtlight->style >= 0 ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4117 VectorScale(rtlight->color, f, rtlight->currentcolor);
4121 if (r_editlights.integer)
4122 R_Shadow_DrawLightSprites();
4125 void R_Shadow_DrawLights(void)
4133 R_Shadow_RenderMode_Begin();
4135 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4136 if (r_shadow_debuglight.integer >= 0)
4138 lightindex = r_shadow_debuglight.integer;
4139 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4140 if (light && (light->flags & flag))
4141 R_Shadow_DrawLight(&light->rtlight);
4145 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4146 for (lightindex = 0;lightindex < range;lightindex++)
4148 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4149 if (light && (light->flags & flag))
4150 R_Shadow_DrawLight(&light->rtlight);
4153 if (r_refdef.scene.rtdlight)
4154 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4155 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4157 R_Shadow_RenderMode_End();
4160 extern const float r_screenvertex3f[12];
4161 extern void R_SetupView(qboolean allowwaterclippingplane);
4162 extern void R_ResetViewRendering3D(void);
4163 extern void R_ResetViewRendering2D(void);
4164 extern cvar_t r_shadows;
4165 extern cvar_t r_shadows_darken;
4166 extern cvar_t r_shadows_drawafterrtlighting;
4167 extern cvar_t r_shadows_castfrombmodels;
4168 extern cvar_t r_shadows_throwdistance;
4169 extern cvar_t r_shadows_throwdirection;
4170 void R_DrawModelShadows(void)
4173 float relativethrowdistance;
4174 entity_render_t *ent;
4175 vec3_t relativelightorigin;
4176 vec3_t relativelightdirection;
4177 vec3_t relativeshadowmins, relativeshadowmaxs;
4178 vec3_t tmp, shadowdir;
4180 if (!r_refdef.scene.numentities || !vid.stencil)
4184 R_ResetViewRendering3D();
4185 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4186 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4187 R_Shadow_RenderMode_Begin();
4188 R_Shadow_RenderMode_ActiveLight(NULL);
4189 r_shadow_lightscissor[0] = r_refdef.view.x;
4190 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
4191 r_shadow_lightscissor[2] = r_refdef.view.width;
4192 r_shadow_lightscissor[3] = r_refdef.view.height;
4193 R_Shadow_RenderMode_StencilShadowVolumes(false);
4196 if (r_shadows.integer == 2)
4198 Math_atov(r_shadows_throwdirection.string, shadowdir);
4199 VectorNormalize(shadowdir);
4202 R_Shadow_ClearStencil();
4204 for (i = 0;i < r_refdef.scene.numentities;i++)
4206 ent = r_refdef.scene.entities[i];
4208 // cast shadows from anything of the map (submodels are optional)
4209 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4211 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4212 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
4213 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
4214 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
4215 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4218 if(ent->entitynumber != 0)
4220 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
4221 int entnum, entnum2, recursion;
4222 entnum = entnum2 = ent->entitynumber;
4223 for(recursion = 32; recursion > 0; --recursion)
4225 entnum2 = cl.entities[entnum].state_current.tagentity;
4226 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
4231 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
4233 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
4234 // transform into modelspace of OUR entity
4235 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
4236 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
4239 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4242 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4245 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
4246 RSurf_ActiveModelEntity(ent, false, false, false);
4247 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4248 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4252 // not really the right mode, but this will disable any silly stencil features
4253 R_Shadow_RenderMode_End();
4255 // set up ortho view for rendering this pass
4256 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4257 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4258 //GL_ScissorTest(true);
4259 //R_EntityMatrix(&identitymatrix);
4260 //R_Mesh_ResetTextureState();
4261 R_ResetViewRendering2D();
4262 R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
4263 R_Mesh_ColorPointer(NULL, 0, 0);
4264 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
4266 // set up a darkening blend on shadowed areas
4267 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4268 //GL_DepthRange(0, 1);
4269 //GL_DepthTest(false);
4270 //GL_DepthMask(false);
4271 //GL_PolygonOffset(0, 0);CHECKGLERROR
4272 GL_Color(0, 0, 0, r_shadows_darken.value);
4273 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4274 //qglDepthFunc(GL_ALWAYS);CHECKGLERROR
4275 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
4276 qglStencilMask(255);CHECKGLERROR
4277 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
4278 qglStencilFunc(GL_NOTEQUAL, 128, 255);CHECKGLERROR
4280 // apply the blend to the shadowed areas
4281 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
4283 // restore the viewport
4284 R_SetViewport(&r_refdef.view.viewport);
4286 // restore other state to normal
4287 //R_Shadow_RenderMode_End();
4290 void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4293 vec3_t centerorigin;
4295 // if it's too close, skip it
4296 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
4298 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4301 if (usequery && r_numqueries + 2 <= r_maxqueries)
4303 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4304 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4305 // 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
4306 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4309 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use qglDepthFunc instead
4310 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
4311 qglDepthFunc(GL_ALWAYS);
4312 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4313 R_Mesh_VertexPointer(vertex3f, 0, 0);
4314 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
4315 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4316 qglDepthFunc(GL_LEQUAL);
4317 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
4318 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4319 R_Mesh_VertexPointer(vertex3f, 0, 0);
4320 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
4321 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4324 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4327 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
4329 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4332 GLint allpixels = 0, visiblepixels = 0;
4333 // now we have to check the query result
4334 if (rtlight->corona_queryindex_visiblepixels)
4337 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
4338 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
4340 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
4341 if (visiblepixels < 1 || allpixels < 1)
4343 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
4344 cscale *= rtlight->corona_visibility;
4348 // FIXME: these traces should scan all render entities instead of cl.world
4349 if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
4352 VectorScale(rtlight->currentcolor, cscale, color);
4353 if (VectorLength(color) > (1.0f / 256.0f))
4356 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
4359 VectorNegate(color, color);
4360 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
4362 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4363 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);
4364 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4366 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
4370 void R_Shadow_DrawCoronas(void)
4378 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4380 if (r_waterstate.renderingscene)
4382 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4383 R_EntityMatrix(&identitymatrix);
4385 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4387 // check occlusion of coronas
4388 // use GL_ARB_occlusion_query if available
4389 // otherwise use raytraces
4391 usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
4394 GL_ColorMask(0,0,0,0);
4395 if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
4396 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
4399 r_maxqueries = (range + r_refdef.scene.numlights) * 4;
4400 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
4402 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
4405 RSurf_ActiveWorldEntity();
4406 GL_BlendFunc(GL_ONE, GL_ZERO);
4407 GL_CullFace(GL_NONE);
4408 GL_DepthMask(false);
4409 GL_DepthRange(0, 1);
4410 GL_PolygonOffset(0, 0);
4412 R_Mesh_ColorPointer(NULL, 0, 0);
4413 R_Mesh_ResetTextureState();
4414 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
4416 for (lightindex = 0;lightindex < range;lightindex++)
4418 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4421 rtlight = &light->rtlight;
4422 rtlight->corona_visibility = 0;
4423 rtlight->corona_queryindex_visiblepixels = 0;
4424 rtlight->corona_queryindex_allpixels = 0;
4425 if (!(rtlight->flags & flag))
4427 if (rtlight->corona <= 0)
4429 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4431 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4433 for (i = 0;i < r_refdef.scene.numlights;i++)
4435 rtlight = r_refdef.scene.lights[i];
4436 rtlight->corona_visibility = 0;
4437 rtlight->corona_queryindex_visiblepixels = 0;
4438 rtlight->corona_queryindex_allpixels = 0;
4439 if (!(rtlight->flags & flag))
4441 if (rtlight->corona <= 0)
4443 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4446 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4448 // now draw the coronas using the query data for intensity info
4449 for (lightindex = 0;lightindex < range;lightindex++)
4451 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4454 rtlight = &light->rtlight;
4455 if (rtlight->corona_visibility <= 0)
4457 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4459 for (i = 0;i < r_refdef.scene.numlights;i++)
4461 rtlight = r_refdef.scene.lights[i];
4462 if (rtlight->corona_visibility <= 0)
4464 if (gl_flashblend.integer)
4465 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4467 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4473 dlight_t *R_Shadow_NewWorldLight(void)
4475 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4478 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)
4481 // validate parameters
4482 if (style < 0 || style >= MAX_LIGHTSTYLES)
4484 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
4490 // copy to light properties
4491 VectorCopy(origin, light->origin);
4492 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4493 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4494 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4496 light->color[0] = max(color[0], 0);
4497 light->color[1] = max(color[1], 0);
4498 light->color[2] = max(color[2], 0);
4500 light->color[0] = color[0];
4501 light->color[1] = color[1];
4502 light->color[2] = color[2];
4503 light->radius = max(radius, 0);
4504 light->style = style;
4505 light->shadow = shadowenable;
4506 light->corona = corona;
4507 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4508 light->coronasizescale = coronasizescale;
4509 light->ambientscale = ambientscale;
4510 light->diffusescale = diffusescale;
4511 light->specularscale = specularscale;
4512 light->flags = flags;
4514 // update renderable light data
4515 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4516 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);
4519 void R_Shadow_FreeWorldLight(dlight_t *light)
4521 if (r_shadow_selectedlight == light)
4522 r_shadow_selectedlight = NULL;
4523 R_RTLight_Uncompile(&light->rtlight);
4524 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4527 void R_Shadow_ClearWorldLights(void)
4531 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4532 for (lightindex = 0;lightindex < range;lightindex++)
4534 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4536 R_Shadow_FreeWorldLight(light);
4538 r_shadow_selectedlight = NULL;
4541 void R_Shadow_SelectLight(dlight_t *light)
4543 if (r_shadow_selectedlight)
4544 r_shadow_selectedlight->selected = false;
4545 r_shadow_selectedlight = light;
4546 if (r_shadow_selectedlight)
4547 r_shadow_selectedlight->selected = true;
4550 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4552 // this is never batched (there can be only one)
4554 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
4555 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4556 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4559 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4564 skinframe_t *skinframe;
4567 // this is never batched (due to the ent parameter changing every time)
4568 // so numsurfaces == 1 and surfacelist[0] == lightnumber
4569 const dlight_t *light = (dlight_t *)ent;
4572 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
4575 VectorScale(light->color, intensity, spritecolor);
4576 if (VectorLength(spritecolor) < 0.1732f)
4577 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
4578 if (VectorLength(spritecolor) > 1.0f)
4579 VectorNormalize(spritecolor);
4581 // draw light sprite
4582 if (light->cubemapname[0] && !light->shadow)
4583 skinframe = r_editlights_sprcubemapnoshadowlight;
4584 else if (light->cubemapname[0])
4585 skinframe = r_editlights_sprcubemaplight;
4586 else if (!light->shadow)
4587 skinframe = r_editlights_sprnoshadowlight;
4589 skinframe = r_editlights_sprlight;
4591 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);
4592 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4594 // draw selection sprite if light is selected
4595 if (light->selected)
4597 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4598 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4599 // VorteX todo: add normalmode/realtime mode light overlay sprites?
4603 void R_Shadow_DrawLightSprites(void)
4607 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4608 for (lightindex = 0;lightindex < range;lightindex++)
4610 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4612 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
4614 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
4617 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
4622 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
4623 if (lightindex >= range)
4625 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4628 rtlight = &light->rtlight;
4629 //if (!(rtlight->flags & flag))
4631 VectorCopy(rtlight->shadoworigin, origin);
4632 *radius = rtlight->radius;
4633 VectorCopy(rtlight->color, color);
4637 void R_Shadow_SelectLightInView(void)
4639 float bestrating, rating, temp[3];
4643 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4646 for (lightindex = 0;lightindex < range;lightindex++)
4648 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4651 VectorSubtract(light->origin, r_refdef.view.origin, temp);
4652 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
4655 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
4656 if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1.0f)
4658 bestrating = rating;
4663 R_Shadow_SelectLight(best);
4666 void R_Shadow_LoadWorldLights(void)
4668 int n, a, style, shadow, flags;
4669 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
4670 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
4671 if (cl.worldmodel == NULL)
4673 Con_Print("No map loaded.\n");
4676 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4677 strlcat (name, ".rtlights", sizeof (name));
4678 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4688 for (;COM_Parse(t, true) && strcmp(
4689 if (COM_Parse(t, true))
4691 if (com_token[0] == '!')
4694 origin[0] = atof(com_token+1);
4697 origin[0] = atof(com_token);
4702 while (*s && *s != '\n' && *s != '\r')
4708 // check for modifier flags
4715 #if _MSC_VER >= 1400
4716 #define sscanf sscanf_s
4718 cubemapname[sizeof(cubemapname)-1] = 0;
4719 #if MAX_QPATH != 128
4720 #error update this code if MAX_QPATH changes
4722 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
4723 #if _MSC_VER >= 1400
4724 , sizeof(cubemapname)
4726 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
4729 flags = LIGHTFLAG_REALTIMEMODE;
4737 coronasizescale = 0.25f;
4739 VectorClear(angles);
4742 if (a < 9 || !strcmp(cubemapname, "\"\""))
4744 // remove quotes on cubemapname
4745 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
4748 namelen = strlen(cubemapname) - 2;
4749 memmove(cubemapname, cubemapname + 1, namelen);
4750 cubemapname[namelen] = '\0';
4754 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);
4757 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4765 Con_Printf("invalid rtlights file \"%s\"\n", name);
4766 Mem_Free(lightsstring);
4770 void R_Shadow_SaveWorldLights(void)
4774 size_t bufchars, bufmaxchars;
4776 char name[MAX_QPATH];
4777 char line[MAX_INPUTLINE];
4778 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
4779 // I hate lines which are 3 times my screen size :( --blub
4782 if (cl.worldmodel == NULL)
4784 Con_Print("No map loaded.\n");
4787 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4788 strlcat (name, ".rtlights", sizeof (name));
4789 bufchars = bufmaxchars = 0;
4791 for (lightindex = 0;lightindex < range;lightindex++)
4793 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4796 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
4797 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);
4798 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
4799 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]);
4801 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);
4802 if (bufchars + strlen(line) > bufmaxchars)
4804 bufmaxchars = bufchars + strlen(line) + 2048;
4806 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
4810 memcpy(buf, oldbuf, bufchars);
4816 memcpy(buf + bufchars, line, strlen(line));
4817 bufchars += strlen(line);
4821 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
4826 void R_Shadow_LoadLightsFile(void)
4829 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
4830 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
4831 if (cl.worldmodel == NULL)
4833 Con_Print("No map loaded.\n");
4836 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4837 strlcat (name, ".lights", sizeof (name));
4838 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4846 while (*s && *s != '\n' && *s != '\r')
4852 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);
4856 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);
4859 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
4860 radius = bound(15, radius, 4096);
4861 VectorScale(color, (2.0f / (8388608.0f)), color);
4862 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
4870 Con_Printf("invalid lights file \"%s\"\n", name);
4871 Mem_Free(lightsstring);
4875 // tyrlite/hmap2 light types in the delay field
4876 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
4878 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
4880 int entnum, style, islight, skin, pflags, effects, type, n;
4883 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
4884 char key[256], value[MAX_INPUTLINE];
4886 if (cl.worldmodel == NULL)
4888 Con_Print("No map loaded.\n");
4891 // try to load a .ent file first
4892 FS_StripExtension (cl.worldmodel->name, key, sizeof (key));
4893 strlcat (key, ".ent", sizeof (key));
4894 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
4895 // and if that is not found, fall back to the bsp file entity string
4897 data = cl.worldmodel->brush.entities;
4900 for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
4902 type = LIGHTTYPE_MINUSX;
4903 origin[0] = origin[1] = origin[2] = 0;
4904 originhack[0] = originhack[1] = originhack[2] = 0;
4905 angles[0] = angles[1] = angles[2] = 0;
4906 color[0] = color[1] = color[2] = 1;
4907 light[0] = light[1] = light[2] = 1;light[3] = 300;
4908 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
4918 if (!COM_ParseToken_Simple(&data, false, false))
4920 if (com_token[0] == '}')
4921 break; // end of entity
4922 if (com_token[0] == '_')
4923 strlcpy(key, com_token + 1, sizeof(key));
4925 strlcpy(key, com_token, sizeof(key));
4926 while (key[strlen(key)-1] == ' ') // remove trailing spaces
4927 key[strlen(key)-1] = 0;
4928 if (!COM_ParseToken_Simple(&data, false, false))
4930 strlcpy(value, com_token, sizeof(value));
4932 // now that we have the key pair worked out...
4933 if (!strcmp("light", key))
4935 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
4939 light[0] = vec[0] * (1.0f / 256.0f);
4940 light[1] = vec[0] * (1.0f / 256.0f);
4941 light[2] = vec[0] * (1.0f / 256.0f);
4947 light[0] = vec[0] * (1.0f / 255.0f);
4948 light[1] = vec[1] * (1.0f / 255.0f);
4949 light[2] = vec[2] * (1.0f / 255.0f);
4953 else if (!strcmp("delay", key))
4955 else if (!strcmp("origin", key))
4956 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
4957 else if (!strcmp("angle", key))
4958 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
4959 else if (!strcmp("angles", key))
4960 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
4961 else if (!strcmp("color", key))
4962 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
4963 else if (!strcmp("wait", key))
4964 fadescale = atof(value);
4965 else if (!strcmp("classname", key))
4967 if (!strncmp(value, "light", 5))
4970 if (!strcmp(value, "light_fluoro"))
4975 overridecolor[0] = 1;
4976 overridecolor[1] = 1;
4977 overridecolor[2] = 1;
4979 if (!strcmp(value, "light_fluorospark"))
4984 overridecolor[0] = 1;
4985 overridecolor[1] = 1;
4986 overridecolor[2] = 1;
4988 if (!strcmp(value, "light_globe"))
4993 overridecolor[0] = 1;
4994 overridecolor[1] = 0.8;
4995 overridecolor[2] = 0.4;
4997 if (!strcmp(value, "light_flame_large_yellow"))
5002 overridecolor[0] = 1;
5003 overridecolor[1] = 0.5;
5004 overridecolor[2] = 0.1;
5006 if (!strcmp(value, "light_flame_small_yellow"))
5011 overridecolor[0] = 1;
5012 overridecolor[1] = 0.5;
5013 overridecolor[2] = 0.1;
5015 if (!strcmp(value, "light_torch_small_white"))
5020 overridecolor[0] = 1;
5021 overridecolor[1] = 0.5;
5022 overridecolor[2] = 0.1;
5024 if (!strcmp(value, "light_torch_small_walltorch"))
5029 overridecolor[0] = 1;
5030 overridecolor[1] = 0.5;
5031 overridecolor[2] = 0.1;
5035 else if (!strcmp("style", key))
5036 style = atoi(value);
5037 else if (!strcmp("skin", key))
5038 skin = (int)atof(value);
5039 else if (!strcmp("pflags", key))
5040 pflags = (int)atof(value);
5041 else if (!strcmp("effects", key))
5042 effects = (int)atof(value);
5043 else if (cl.worldmodel->type == mod_brushq3)
5045 if (!strcmp("scale", key))
5046 lightscale = atof(value);
5047 if (!strcmp("fade", key))
5048 fadescale = atof(value);
5053 if (lightscale <= 0)
5057 if (color[0] == color[1] && color[0] == color[2])
5059 color[0] *= overridecolor[0];
5060 color[1] *= overridecolor[1];
5061 color[2] *= overridecolor[2];
5063 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5064 color[0] = color[0] * light[0];
5065 color[1] = color[1] * light[1];
5066 color[2] = color[2] * light[2];
5069 case LIGHTTYPE_MINUSX:
5071 case LIGHTTYPE_RECIPX:
5073 VectorScale(color, (1.0f / 16.0f), color);
5075 case LIGHTTYPE_RECIPXX:
5077 VectorScale(color, (1.0f / 16.0f), color);
5080 case LIGHTTYPE_NONE:
5084 case LIGHTTYPE_MINUSXX:
5087 VectorAdd(origin, originhack, origin);
5089 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);
5092 Mem_Free(entfiledata);
5096 void R_Shadow_SetCursorLocationForView(void)
5099 vec3_t dest, endpos;
5101 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5102 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
5103 if (trace.fraction < 1)
5105 dist = trace.fraction * r_editlights_cursordistance.value;
5106 push = r_editlights_cursorpushback.value;
5110 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5111 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5115 VectorClear( endpos );
5117 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5118 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5119 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5122 void R_Shadow_UpdateWorldLightSelection(void)
5124 if (r_editlights.integer)
5126 R_Shadow_SetCursorLocationForView();
5127 R_Shadow_SelectLightInView();
5130 R_Shadow_SelectLight(NULL);
5133 void R_Shadow_EditLights_Clear_f(void)
5135 R_Shadow_ClearWorldLights();
5138 void R_Shadow_EditLights_Reload_f(void)
5142 strlcpy(r_shadow_mapname, cl.worldmodel->name, sizeof(r_shadow_mapname));
5143 R_Shadow_ClearWorldLights();
5144 R_Shadow_LoadWorldLights();
5145 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5147 R_Shadow_LoadLightsFile();
5148 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5149 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5153 void R_Shadow_EditLights_Save_f(void)
5157 R_Shadow_SaveWorldLights();
5160 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
5162 R_Shadow_ClearWorldLights();
5163 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5166 void R_Shadow_EditLights_ImportLightsFile_f(void)
5168 R_Shadow_ClearWorldLights();
5169 R_Shadow_LoadLightsFile();
5172 void R_Shadow_EditLights_Spawn_f(void)
5175 if (!r_editlights.integer)
5177 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5180 if (Cmd_Argc() != 1)
5182 Con_Print("r_editlights_spawn does not take parameters\n");
5185 color[0] = color[1] = color[2] = 1;
5186 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5189 void R_Shadow_EditLights_Edit_f(void)
5191 vec3_t origin, angles, color;
5192 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5193 int style, shadows, flags, normalmode, realtimemode;
5194 char cubemapname[MAX_INPUTLINE];
5195 if (!r_editlights.integer)
5197 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5200 if (!r_shadow_selectedlight)
5202 Con_Print("No selected light.\n");
5205 VectorCopy(r_shadow_selectedlight->origin, origin);
5206 VectorCopy(r_shadow_selectedlight->angles, angles);
5207 VectorCopy(r_shadow_selectedlight->color, color);
5208 radius = r_shadow_selectedlight->radius;
5209 style = r_shadow_selectedlight->style;
5210 if (r_shadow_selectedlight->cubemapname)
5211 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5214 shadows = r_shadow_selectedlight->shadow;
5215 corona = r_shadow_selectedlight->corona;
5216 coronasizescale = r_shadow_selectedlight->coronasizescale;
5217 ambientscale = r_shadow_selectedlight->ambientscale;
5218 diffusescale = r_shadow_selectedlight->diffusescale;
5219 specularscale = r_shadow_selectedlight->specularscale;
5220 flags = r_shadow_selectedlight->flags;
5221 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5222 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5223 if (!strcmp(Cmd_Argv(1), "origin"))
5225 if (Cmd_Argc() != 5)
5227 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5230 origin[0] = atof(Cmd_Argv(2));
5231 origin[1] = atof(Cmd_Argv(3));
5232 origin[2] = atof(Cmd_Argv(4));
5234 else if (!strcmp(Cmd_Argv(1), "originx"))
5236 if (Cmd_Argc() != 3)
5238 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5241 origin[0] = atof(Cmd_Argv(2));
5243 else if (!strcmp(Cmd_Argv(1), "originy"))
5245 if (Cmd_Argc() != 3)
5247 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5250 origin[1] = atof(Cmd_Argv(2));
5252 else if (!strcmp(Cmd_Argv(1), "originz"))
5254 if (Cmd_Argc() != 3)
5256 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5259 origin[2] = atof(Cmd_Argv(2));
5261 else if (!strcmp(Cmd_Argv(1), "move"))
5263 if (Cmd_Argc() != 5)
5265 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5268 origin[0] += atof(Cmd_Argv(2));
5269 origin[1] += atof(Cmd_Argv(3));
5270 origin[2] += atof(Cmd_Argv(4));
5272 else if (!strcmp(Cmd_Argv(1), "movex"))
5274 if (Cmd_Argc() != 3)
5276 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5279 origin[0] += atof(Cmd_Argv(2));
5281 else if (!strcmp(Cmd_Argv(1), "movey"))
5283 if (Cmd_Argc() != 3)
5285 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5288 origin[1] += atof(Cmd_Argv(2));
5290 else if (!strcmp(Cmd_Argv(1), "movez"))
5292 if (Cmd_Argc() != 3)
5294 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5297 origin[2] += atof(Cmd_Argv(2));
5299 else if (!strcmp(Cmd_Argv(1), "angles"))
5301 if (Cmd_Argc() != 5)
5303 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5306 angles[0] = atof(Cmd_Argv(2));
5307 angles[1] = atof(Cmd_Argv(3));
5308 angles[2] = atof(Cmd_Argv(4));
5310 else if (!strcmp(Cmd_Argv(1), "anglesx"))
5312 if (Cmd_Argc() != 3)
5314 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5317 angles[0] = atof(Cmd_Argv(2));
5319 else if (!strcmp(Cmd_Argv(1), "anglesy"))
5321 if (Cmd_Argc() != 3)
5323 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5326 angles[1] = atof(Cmd_Argv(2));
5328 else if (!strcmp(Cmd_Argv(1), "anglesz"))
5330 if (Cmd_Argc() != 3)
5332 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5335 angles[2] = atof(Cmd_Argv(2));
5337 else if (!strcmp(Cmd_Argv(1), "color"))
5339 if (Cmd_Argc() != 5)
5341 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
5344 color[0] = atof(Cmd_Argv(2));
5345 color[1] = atof(Cmd_Argv(3));
5346 color[2] = atof(Cmd_Argv(4));
5348 else if (!strcmp(Cmd_Argv(1), "radius"))
5350 if (Cmd_Argc() != 3)
5352 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5355 radius = atof(Cmd_Argv(2));
5357 else if (!strcmp(Cmd_Argv(1), "colorscale"))
5359 if (Cmd_Argc() == 3)
5361 double scale = atof(Cmd_Argv(2));
5368 if (Cmd_Argc() != 5)
5370 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
5373 color[0] *= atof(Cmd_Argv(2));
5374 color[1] *= atof(Cmd_Argv(3));
5375 color[2] *= atof(Cmd_Argv(4));
5378 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
5380 if (Cmd_Argc() != 3)
5382 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5385 radius *= atof(Cmd_Argv(2));
5387 else if (!strcmp(Cmd_Argv(1), "style"))
5389 if (Cmd_Argc() != 3)
5391 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5394 style = atoi(Cmd_Argv(2));
5396 else if (!strcmp(Cmd_Argv(1), "cubemap"))
5400 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5403 if (Cmd_Argc() == 3)
5404 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
5408 else if (!strcmp(Cmd_Argv(1), "shadows"))
5410 if (Cmd_Argc() != 3)
5412 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5415 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5417 else if (!strcmp(Cmd_Argv(1), "corona"))
5419 if (Cmd_Argc() != 3)
5421 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5424 corona = atof(Cmd_Argv(2));
5426 else if (!strcmp(Cmd_Argv(1), "coronasize"))
5428 if (Cmd_Argc() != 3)
5430 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5433 coronasizescale = atof(Cmd_Argv(2));
5435 else if (!strcmp(Cmd_Argv(1), "ambient"))
5437 if (Cmd_Argc() != 3)
5439 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5442 ambientscale = atof(Cmd_Argv(2));
5444 else if (!strcmp(Cmd_Argv(1), "diffuse"))
5446 if (Cmd_Argc() != 3)
5448 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5451 diffusescale = atof(Cmd_Argv(2));
5453 else if (!strcmp(Cmd_Argv(1), "specular"))
5455 if (Cmd_Argc() != 3)
5457 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5460 specularscale = atof(Cmd_Argv(2));
5462 else if (!strcmp(Cmd_Argv(1), "normalmode"))
5464 if (Cmd_Argc() != 3)
5466 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5469 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5471 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
5473 if (Cmd_Argc() != 3)
5475 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5478 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5482 Con_Print("usage: r_editlights_edit [property] [value]\n");
5483 Con_Print("Selected light's properties:\n");
5484 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5485 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5486 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5487 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
5488 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
5489 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
5490 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5491 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
5492 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
5493 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
5494 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
5495 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
5496 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5497 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5500 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5501 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5504 void R_Shadow_EditLights_EditAll_f(void)
5510 if (!r_editlights.integer)
5512 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5516 // EditLights doesn't seem to have a "remove" command or something so:
5517 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5518 for (lightindex = 0;lightindex < range;lightindex++)
5520 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5523 R_Shadow_SelectLight(light);
5524 R_Shadow_EditLights_Edit_f();
5528 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
5530 int lightnumber, lightcount;
5531 size_t lightindex, range;
5535 if (!r_editlights.integer)
5537 x = vid_conwidth.value - 240;
5539 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
5542 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5543 for (lightindex = 0;lightindex < range;lightindex++)
5545 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5548 if (light == r_shadow_selectedlight)
5549 lightnumber = lightindex;
5552 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;
5553 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;
5555 if (r_shadow_selectedlight == NULL)
5557 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;
5558 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;
5559 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;
5560 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;
5561 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;
5562 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;
5563 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;
5564 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;
5565 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;
5566 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;
5567 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;
5568 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;
5569 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;
5570 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;
5571 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;
5574 void R_Shadow_EditLights_ToggleShadow_f(void)
5576 if (!r_editlights.integer)
5578 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5581 if (!r_shadow_selectedlight)
5583 Con_Print("No selected light.\n");
5586 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);
5589 void R_Shadow_EditLights_ToggleCorona_f(void)
5591 if (!r_editlights.integer)
5593 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5596 if (!r_shadow_selectedlight)
5598 Con_Print("No selected light.\n");
5601 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);
5604 void R_Shadow_EditLights_Remove_f(void)
5606 if (!r_editlights.integer)
5608 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
5611 if (!r_shadow_selectedlight)
5613 Con_Print("No selected light.\n");
5616 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
5617 r_shadow_selectedlight = NULL;
5620 void R_Shadow_EditLights_Help_f(void)
5623 "Documentation on r_editlights system:\n"
5625 "r_editlights : enable/disable editing mode\n"
5626 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
5627 "r_editlights_cursorpushback : push back cursor this far from surface\n"
5628 "r_editlights_cursorpushoff : push cursor off surface this far\n"
5629 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
5630 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
5632 "r_editlights_help : this help\n"
5633 "r_editlights_clear : remove all lights\n"
5634 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
5635 "r_editlights_save : save to .rtlights file\n"
5636 "r_editlights_spawn : create a light with default settings\n"
5637 "r_editlights_edit command : edit selected light - more documentation below\n"
5638 "r_editlights_remove : remove selected light\n"
5639 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
5640 "r_editlights_importlightentitiesfrommap : reload light entities\n"
5641 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
5643 "origin x y z : set light location\n"
5644 "originx x: set x component of light location\n"
5645 "originy y: set y component of light location\n"
5646 "originz z: set z component of light location\n"
5647 "move x y z : adjust light location\n"
5648 "movex x: adjust x component of light location\n"
5649 "movey y: adjust y component of light location\n"
5650 "movez z: adjust z component of light location\n"
5651 "angles x y z : set light angles\n"
5652 "anglesx x: set x component of light angles\n"
5653 "anglesy y: set y component of light angles\n"
5654 "anglesz z: set z component of light angles\n"
5655 "color r g b : set color of light (can be brighter than 1 1 1)\n"
5656 "radius radius : set radius (size) of light\n"
5657 "colorscale grey : multiply color of light (1 does nothing)\n"
5658 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
5659 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
5660 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
5661 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
5662 "cubemap basename : set filter cubemap of light (not yet supported)\n"
5663 "shadows 1/0 : turn on/off shadows\n"
5664 "corona n : set corona intensity\n"
5665 "coronasize n : set corona size (0-1)\n"
5666 "ambient n : set ambient intensity (0-1)\n"
5667 "diffuse n : set diffuse intensity (0-1)\n"
5668 "specular n : set specular intensity (0-1)\n"
5669 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
5670 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
5671 "<nothing> : print light properties to console\n"
5675 void R_Shadow_EditLights_CopyInfo_f(void)
5677 if (!r_editlights.integer)
5679 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
5682 if (!r_shadow_selectedlight)
5684 Con_Print("No selected light.\n");
5687 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
5688 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
5689 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
5690 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
5691 if (r_shadow_selectedlight->cubemapname)
5692 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
5694 r_shadow_bufferlight.cubemapname[0] = 0;
5695 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
5696 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
5697 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
5698 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
5699 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
5700 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
5701 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
5704 void R_Shadow_EditLights_PasteInfo_f(void)
5706 if (!r_editlights.integer)
5708 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
5711 if (!r_shadow_selectedlight)
5713 Con_Print("No selected light.\n");
5716 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);
5719 void R_Shadow_EditLights_Init(void)
5721 Cvar_RegisterVariable(&r_editlights);
5722 Cvar_RegisterVariable(&r_editlights_cursordistance);
5723 Cvar_RegisterVariable(&r_editlights_cursorpushback);
5724 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
5725 Cvar_RegisterVariable(&r_editlights_cursorgrid);
5726 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
5727 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
5728 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
5729 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)");
5730 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
5731 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
5732 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
5733 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)");
5734 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
5735 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
5736 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
5737 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
5738 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
5739 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
5740 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)");
5746 =============================================================================
5750 =============================================================================
5753 void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, int dynamic)
5755 VectorClear(diffusecolor);
5756 VectorClear(diffusenormal);
5758 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
5760 ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_refdef.scene.ambient;
5761 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
5764 VectorSet(ambientcolor, 1, 1, 1);
5771 for (i = 0;i < r_refdef.scene.numlights;i++)
5773 light = r_refdef.scene.lights[i];
5774 Matrix4x4_Transform(&light->matrix_worldtolight, p, v);
5775 f = 1 - VectorLength2(v);
5776 if (f > 0 && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
5777 VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);