3 Terminology: Stencil Shadow Volume (sometimes called Stencil Shadows)
4 An extrusion of the lit faces, beginning at the original geometry and ending
5 further from the light source than the original geometry (presumably at least
6 as far as the light's radius, if the light has a radius at all), capped at
7 both front and back to avoid any problems (extrusion from dark faces also
8 works but has a different set of problems)
10 This is normally rendered using Carmack's Reverse technique, in which
11 backfaces behind zbuffer (zfail) increment the stencil, and frontfaces behind
12 zbuffer (zfail) decrement the stencil, the result is a stencil value of zero
13 where shadows did not intersect the visible geometry, suitable as a stencil
14 mask for rendering lighting everywhere but shadow.
16 In our case to hopefully avoid the Creative Labs patent, we draw the backfaces
17 as decrement and the frontfaces as increment, and we redefine the DepthFunc to
18 GL_LESS (the patent uses GL_GEQUAL) which causes zfail when behind surfaces
19 and zpass when infront (the patent draws where zpass with a GL_GEQUAL test),
20 additionally we clear stencil to 128 to avoid the need for the unclamped
21 incr/decr extension (not related to patent).
24 This algorithm may be covered by Creative's patent (US Patent #6384822),
25 however that patent is quite specific about increment on backfaces and
26 decrement on frontfaces where zpass with GL_GEQUAL depth test, which is
27 opposite this implementation and partially opposite Carmack's Reverse paper
28 (which uses GL_LESS, but increments on backfaces and decrements on frontfaces).
32 Terminology: Stencil Light Volume (sometimes called Light Volumes)
33 Similar to a Stencil Shadow Volume, but inverted; rather than containing the
34 areas in shadow it contains the areas in light, this can only be built
35 quickly for certain limited cases (such as portal visibility from a point),
36 but is quite useful for some effects (sunlight coming from sky polygons is
37 one possible example, translucent occluders is another example).
41 Terminology: Optimized Stencil Shadow Volume
42 A Stencil Shadow Volume that has been processed sufficiently to ensure it has
43 no duplicate coverage of areas (no need to shadow an area twice), often this
44 greatly improves performance but is an operation too costly to use on moving
45 lights (however completely optimal Stencil Light Volumes can be constructed
50 Terminology: Per Pixel Lighting (sometimes abbreviated PPL)
51 Per pixel evaluation of lighting equations, at a bare minimum this involves
52 DOT3 shading of diffuse lighting (per pixel dotproduct of negated incidence
53 vector and surface normal, using a texture of the surface bumps, called a
54 NormalMap) if supported by hardware; in our case there is support for cards
55 which are incapable of DOT3, the quality is quite poor however. Additionally
56 it is desirable to have specular evaluation per pixel, per vertex
57 normalization of specular halfangle vectors causes noticable distortion but
58 is unavoidable on hardware without GL_ARB_fragment_program or
59 GL_ARB_fragment_shader.
63 Terminology: Normalization CubeMap
64 A cubemap containing normalized dot3-encoded (vectors of length 1 or less
65 encoded as RGB colors) for any possible direction, this technique allows per
66 pixel calculation of incidence vector for per pixel lighting purposes, which
67 would not otherwise be possible per pixel without GL_ARB_fragment_program or
68 GL_ARB_fragment_shader.
72 Terminology: 2D+1D Attenuation Texturing
73 A very crude approximation of light attenuation with distance which results
74 in cylindrical light shapes which fade vertically as a streak (some games
75 such as Doom3 allow this to be rotated to be less noticable in specific
76 cases), the technique is simply modulating lighting by two 2D textures (which
77 can be the same) on different axes of projection (XY and Z, typically), this
78 is the second best technique available without 3D Attenuation Texturing,
79 GL_ARB_fragment_program or GL_ARB_fragment_shader technology.
83 Terminology: 2D+1D Inverse Attenuation Texturing
84 A clever method described in papers on the Abducted engine, this has a squared
85 distance texture (bright on the outside, black in the middle), which is used
86 twice using GL_ADD blending, the result of this is used in an inverse modulate
87 (GL_ONE_MINUS_DST_ALPHA, GL_ZERO) to implement the equation
88 lighting*=(1-((X*X+Y*Y)+(Z*Z))) which is spherical (unlike 2D+1D attenuation
93 Terminology: 3D Attenuation Texturing
94 A slightly crude approximation of light attenuation with distance, its flaws
95 are limited radius and resolution (performance tradeoffs).
99 Terminology: 3D Attenuation-Normalization Texturing
100 A 3D Attenuation Texture merged with a Normalization CubeMap, by making the
101 vectors shorter the lighting becomes darker, a very effective optimization of
102 diffuse lighting if 3D Attenuation Textures are already used.
106 Terminology: Light Cubemap Filtering
107 A technique for modeling non-uniform light distribution according to
108 direction, for example a lantern may use a cubemap to describe the light
109 emission pattern of the cage around the lantern (as well as soot buildup
110 discoloring the light in certain areas), often also used for softened grate
111 shadows and light shining through a stained glass window (done crudely by
112 texturing the lighting with a cubemap), another good example would be a disco
113 light. This technique is used heavily in many games (Doom3 does not support
118 Terminology: Light Projection Filtering
119 A technique for modeling shadowing of light passing through translucent
120 surfaces, allowing stained glass windows and other effects to be done more
121 elegantly than possible with Light Cubemap Filtering by applying an occluder
122 texture to the lighting combined with a stencil light volume to limit the lit
123 area, this technique is used by Doom3 for spotlights and flashlights, among
124 other things, this can also be used more generally to render light passing
125 through multiple translucent occluders in a scene (using a light volume to
126 describe the area beyond the occluder, and thus mask off rendering of all
131 Terminology: Doom3 Lighting
132 A combination of Stencil Shadow Volume, Per Pixel Lighting, Normalization
133 CubeMap, 2D+1D Attenuation Texturing, and Light Projection Filtering, as
134 demonstrated by the game Doom3.
137 #include "quakedef.h"
138 #include "r_shadow.h"
139 #include "cl_collision.h"
143 extern void R_Shadow_EditLights_Init(void);
145 typedef enum r_shadow_rendermode_e
147 R_SHADOW_RENDERMODE_NONE,
148 R_SHADOW_RENDERMODE_ZPASS_STENCIL,
149 R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL,
150 R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE,
151 R_SHADOW_RENDERMODE_ZFAIL_STENCIL,
152 R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL,
153 R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE,
154 R_SHADOW_RENDERMODE_LIGHT_VERTEX,
155 R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN,
156 R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN,
157 R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN,
158 R_SHADOW_RENDERMODE_LIGHT_GLSL,
159 R_SHADOW_RENDERMODE_VISIBLEVOLUMES,
160 R_SHADOW_RENDERMODE_VISIBLELIGHTING,
161 R_SHADOW_RENDERMODE_SHADOWMAP2D,
162 R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE,
163 R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE,
165 r_shadow_rendermode_t;
167 typedef enum r_shadow_shadowmode_e
169 R_SHADOW_SHADOWMODE_STENCIL,
170 R_SHADOW_SHADOWMODE_SHADOWMAP2D,
171 R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE,
172 R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE
174 r_shadow_shadowmode_t;
176 r_shadow_rendermode_t r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
177 r_shadow_rendermode_t r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_NONE;
178 r_shadow_rendermode_t r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_NONE;
179 r_shadow_rendermode_t r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_NONE;
180 qboolean r_shadow_usingshadowmaprect;
181 qboolean r_shadow_usingshadowmap2d;
182 qboolean r_shadow_usingshadowmapcube;
183 int r_shadow_shadowmapside;
184 float r_shadow_shadowmap_texturescale[2];
185 float r_shadow_shadowmap_parameters[4];
187 int r_shadow_drawbuffer;
188 int r_shadow_readbuffer;
190 int r_shadow_cullface_front, r_shadow_cullface_back;
191 GLuint r_shadow_fborectangle;
192 GLuint r_shadow_fbocubeside[R_SHADOW_SHADOWMAP_NUMCUBEMAPS];
193 GLuint r_shadow_fbo2d;
194 r_shadow_shadowmode_t r_shadow_shadowmode;
195 int r_shadow_shadowmapfilterquality;
196 int r_shadow_shadowmaptexturetype;
197 int r_shadow_shadowmapdepthbits;
198 int r_shadow_shadowmapmaxsize;
199 qboolean r_shadow_shadowmapvsdct;
200 qboolean r_shadow_shadowmapsampler;
201 int r_shadow_shadowmappcf;
202 int r_shadow_shadowmapborder;
203 int r_shadow_lightscissor[4];
204 qboolean r_shadow_usingdeferredprepass;
206 int maxshadowtriangles;
209 int maxshadowvertices;
210 float *shadowvertex3f;
220 unsigned char *shadowsides;
221 int *shadowsideslist;
228 int r_shadow_buffer_numleafpvsbytes;
229 unsigned char *r_shadow_buffer_visitingleafpvs;
230 unsigned char *r_shadow_buffer_leafpvs;
231 int *r_shadow_buffer_leaflist;
233 int r_shadow_buffer_numsurfacepvsbytes;
234 unsigned char *r_shadow_buffer_surfacepvs;
235 int *r_shadow_buffer_surfacelist;
236 unsigned char *r_shadow_buffer_surfacesides;
238 int r_shadow_buffer_numshadowtrispvsbytes;
239 unsigned char *r_shadow_buffer_shadowtrispvs;
240 int r_shadow_buffer_numlighttrispvsbytes;
241 unsigned char *r_shadow_buffer_lighttrispvs;
243 rtexturepool_t *r_shadow_texturepool;
244 rtexture_t *r_shadow_attenuationgradienttexture;
245 rtexture_t *r_shadow_attenuation2dtexture;
246 rtexture_t *r_shadow_attenuation3dtexture;
247 skinframe_t *r_shadow_lightcorona;
248 rtexture_t *r_shadow_shadowmaprectangletexture;
249 rtexture_t *r_shadow_shadowmap2dtexture;
250 rtexture_t *r_shadow_shadowmapcubetexture[R_SHADOW_SHADOWMAP_NUMCUBEMAPS];
251 rtexture_t *r_shadow_shadowmapvsdcttexture;
252 int r_shadow_shadowmapsize; // changes for each light based on distance
253 int r_shadow_shadowmaplod; // changes for each light based on distance
255 GLuint r_shadow_prepassgeometryfbo;
256 GLuint r_shadow_prepasslightingfbo;
257 int r_shadow_prepass_width;
258 int r_shadow_prepass_height;
259 rtexture_t *r_shadow_prepassgeometrydepthtexture;
260 rtexture_t *r_shadow_prepassgeometrynormalmaptexture;
261 rtexture_t *r_shadow_prepasslightingdiffusetexture;
262 rtexture_t *r_shadow_prepasslightingspeculartexture;
264 // lights are reloaded when this changes
265 char r_shadow_mapname[MAX_QPATH];
267 // used only for light filters (cubemaps)
268 rtexturepool_t *r_shadow_filters_texturepool;
270 static const GLenum r_shadow_prepasslightingdrawbuffers[2] = {GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT};
272 cvar_t r_shadow_bumpscale_basetexture = {0, "r_shadow_bumpscale_basetexture", "0", "generate fake bumpmaps from diffuse textures at this bumpyness, try 4 to match tenebrae, higher values increase depth, requires r_restart to take effect"};
273 cvar_t r_shadow_bumpscale_bumpmap = {0, "r_shadow_bumpscale_bumpmap", "4", "what magnitude to interpret _bump.tga textures as, higher values increase depth, requires r_restart to take effect"};
274 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
275 cvar_t r_shadow_deferred = {CVAR_SAVE, "r_shadow_deferred", "0", "uses image-based lighting instead of geometry-based lighting, the method used renders a depth image and a normalmap image, renders lights into separate diffuse and specular images, and then combines this into the normal rendering, requires r_shadow_shadowmapping"};
276 cvar_t r_shadow_deferred_8bitrange = {CVAR_SAVE, "r_shadow_deferred_8bitrange", "2", "dynamic range of image-based lighting when using 32bit color (does not apply to fp)"};
277 //cvar_t r_shadow_deferred_fp = {CVAR_SAVE, "r_shadow_deferred_fp", "0", "use 16bit (1) or 32bit (2) floating point for accumulation of image-based lighting"};
278 cvar_t r_shadow_usenormalmap = {CVAR_SAVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"};
279 cvar_t r_shadow_gloss = {CVAR_SAVE, "r_shadow_gloss", "1", "0 disables gloss (specularity) rendering, 1 uses gloss if textures are found, 2 forces a flat metallic specular effect on everything without textures (similar to tenebrae)"};
280 cvar_t r_shadow_gloss2intensity = {0, "r_shadow_gloss2intensity", "0.125", "how bright the forced flat gloss should look if r_shadow_gloss is 2"};
281 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
282 cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
283 cvar_t r_shadow_gloss2exponent = {0, "r_shadow_gloss2exponent", "32", "same as r_shadow_glossexponent but for forced gloss (gloss 2) surfaces"};
284 cvar_t r_shadow_glossexact = {0, "r_shadow_glossexact", "0", "use exact reflection math for gloss (slightly slower, but should look a tad better)"};
285 cvar_t r_shadow_lightattenuationdividebias = {0, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"};
286 cvar_t r_shadow_lightattenuationlinearscale = {0, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"};
287 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
288 cvar_t r_shadow_lightradiusscale = {0, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
289 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1", "use portal culling to exactly determine lit triangles when compiling world lights"};
290 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "0", "how far to cast shadows"};
291 cvar_t r_shadow_frontsidecasting = {0, "r_shadow_frontsidecasting", "1", "whether to cast shadows from illuminated triangles (front side of model) or unlit triangles (back side of model)"};
292 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
293 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
294 cvar_t r_shadow_realtime_dlight_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
295 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
296 cvar_t r_shadow_realtime_world = {CVAR_SAVE, "r_shadow_realtime_world", "0", "enables rendering of full world lighting (whether loaded from the map, or a .rtlights file, or a .ent file, or a .lights file produced by hlight)"};
297 cvar_t r_shadow_realtime_world_lightmaps = {CVAR_SAVE, "r_shadow_realtime_world_lightmaps", "0", "brightness to render lightmaps when using full world lighting, try 0.5 for a tenebrae-like appearance"};
298 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
299 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
300 cvar_t r_shadow_realtime_world_compileshadow = {0, "r_shadow_realtime_world_compileshadow", "1", "enables compilation of shadows from world lights for higher performance rendering"};
301 cvar_t r_shadow_realtime_world_compilesvbsp = {0, "r_shadow_realtime_world_compilesvbsp", "1", "enables svbsp optimization during compilation"};
302 cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "1", "enables portal-based culling optimization during compilation"};
303 cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1", "use scissor optimization of light rendering (restricts rendering to the portion of the screen affected by the light)"};
304 cvar_t r_shadow_shadowmapping = {CVAR_SAVE, "r_shadow_shadowmapping", "0", "enables use of shadowmapping (depth texture sampling) instead of stencil shadow volumes, requires gl_fbo 1"};
305 cvar_t r_shadow_shadowmapping_texturetype = {CVAR_SAVE, "r_shadow_shadowmapping_texturetype", "-1", "shadowmap texture types: -1 = auto-select, 0 = 2D, 1 = rectangle, 2 = cubemap"};
306 cvar_t r_shadow_shadowmapping_filterquality = {CVAR_SAVE, "r_shadow_shadowmapping_filterquality", "-1", "shadowmap filter modes: -1 = auto-select, 0 = no filtering, 1 = bilinear, 2 = bilinear 2x2 blur (fast), 3 = 3x3 blur (moderate), 4 = 4x4 blur (slow)"};
307 cvar_t r_shadow_shadowmapping_depthbits = {CVAR_SAVE, "r_shadow_shadowmapping_depthbits", "24", "requested minimum shadowmap texture depth bits"};
308 cvar_t r_shadow_shadowmapping_vsdct = {CVAR_SAVE, "r_shadow_shadowmapping_vsdct", "1", "enables use of virtual shadow depth cube texture"};
309 cvar_t r_shadow_shadowmapping_minsize = {CVAR_SAVE, "r_shadow_shadowmapping_minsize", "32", "shadowmap size limit"};
310 cvar_t r_shadow_shadowmapping_maxsize = {CVAR_SAVE, "r_shadow_shadowmapping_maxsize", "512", "shadowmap size limit"};
311 cvar_t r_shadow_shadowmapping_precision = {CVAR_SAVE, "r_shadow_shadowmapping_precision", "1", "makes shadowmaps have a maximum resolution of this number of pixels per light source radius unit such that, for example, at precision 0.5 a light with radius 200 will have a maximum resolution of 100 pixels"};
312 //cvar_t r_shadow_shadowmapping_lod_bias = {CVAR_SAVE, "r_shadow_shadowmapping_lod_bias", "16", "shadowmap size bias"};
313 //cvar_t r_shadow_shadowmapping_lod_scale = {CVAR_SAVE, "r_shadow_shadowmapping_lod_scale", "128", "shadowmap size scaling parameter"};
314 cvar_t r_shadow_shadowmapping_bordersize = {CVAR_SAVE, "r_shadow_shadowmapping_bordersize", "4", "shadowmap size bias for filtering"};
315 cvar_t r_shadow_shadowmapping_nearclip = {CVAR_SAVE, "r_shadow_shadowmapping_nearclip", "1", "shadowmap nearclip in world units"};
316 cvar_t r_shadow_shadowmapping_bias = {CVAR_SAVE, "r_shadow_shadowmapping_bias", "0.03", "shadowmap bias parameter (this is multiplied by nearclip * 1024 / lodsize)"};
317 cvar_t r_shadow_shadowmapping_polygonfactor = {CVAR_SAVE, "r_shadow_shadowmapping_polygonfactor", "2", "slope-dependent shadowmapping bias"};
318 cvar_t r_shadow_shadowmapping_polygonoffset = {CVAR_SAVE, "r_shadow_shadowmapping_polygonoffset", "0", "constant shadowmapping bias"};
319 cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
320 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)"};
321 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)"};
322 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "1", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
323 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"};
324 cvar_t r_coronas_occlusionquery = {CVAR_SAVE, "r_coronas_occlusionquery", "1", "use GL_ARB_occlusion_query extension if supported (fades coronas according to visibility)"};
325 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
326 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
327 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
328 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
329 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
330 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
331 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
332 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
333 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
335 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
336 #define ATTENTABLESIZE 256
337 // 1D gradient, 2D circle and 3D sphere attenuation textures
338 #define ATTEN1DSIZE 32
339 #define ATTEN2DSIZE 64
340 #define ATTEN3DSIZE 32
342 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
343 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
344 static float r_shadow_attentable[ATTENTABLESIZE+1];
346 rtlight_t *r_shadow_compilingrtlight;
347 static memexpandablearray_t r_shadow_worldlightsarray;
348 dlight_t *r_shadow_selectedlight;
349 dlight_t r_shadow_bufferlight;
350 vec3_t r_editlights_cursorlocation;
352 extern int con_vislines;
354 typedef struct cubemapinfo_s
361 static int numcubemaps;
362 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
364 void R_Shadow_UncompileWorldLights(void);
365 void R_Shadow_ClearWorldLights(void);
366 void R_Shadow_SaveWorldLights(void);
367 void R_Shadow_LoadWorldLights(void);
368 void R_Shadow_LoadLightsFile(void);
369 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
370 void R_Shadow_EditLights_Reload_f(void);
371 void R_Shadow_ValidateCvars(void);
372 static void R_Shadow_MakeTextures(void);
374 #define EDLIGHTSPRSIZE 8
375 skinframe_t *r_editlights_sprcursor;
376 skinframe_t *r_editlights_sprlight;
377 skinframe_t *r_editlights_sprnoshadowlight;
378 skinframe_t *r_editlights_sprcubemaplight;
379 skinframe_t *r_editlights_sprcubemapnoshadowlight;
380 skinframe_t *r_editlights_sprselection;
382 void R_Shadow_SetShadowMode(void)
384 r_shadow_shadowmapmaxsize = bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4);
385 r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer != 0;
386 r_shadow_shadowmapfilterquality = r_shadow_shadowmapping_filterquality.integer;
387 r_shadow_shadowmaptexturetype = r_shadow_shadowmapping_texturetype.integer;
388 r_shadow_shadowmapdepthbits = r_shadow_shadowmapping_depthbits.integer;
389 r_shadow_shadowmapborder = bound(0, r_shadow_shadowmapping_bordersize.integer, 16);
390 r_shadow_shadowmaplod = -1;
391 r_shadow_shadowmapsize = 0;
392 r_shadow_shadowmapsampler = false;
393 r_shadow_shadowmappcf = 0;
394 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
395 switch(vid.renderpath)
397 case RENDERPATH_GL20:
398 case RENDERPATH_CGGL:
399 if ((r_shadow_shadowmapping.integer || r_shadow_deferred.integer) && vid.support.ext_framebuffer_object)
401 if(r_shadow_shadowmapfilterquality < 0)
403 if(strstr(gl_vendor, "NVIDIA"))
405 r_shadow_shadowmapsampler = vid.support.arb_shadow;
406 r_shadow_shadowmappcf = 1;
408 else if(vid.support.amd_texture_texture4 || vid.support.arb_texture_gather)
409 r_shadow_shadowmappcf = 1;
410 else if(strstr(gl_vendor, "ATI"))
411 r_shadow_shadowmappcf = 1;
413 r_shadow_shadowmapsampler = vid.support.arb_shadow;
417 switch (r_shadow_shadowmapfilterquality)
420 r_shadow_shadowmapsampler = vid.support.arb_shadow;
423 r_shadow_shadowmapsampler = vid.support.arb_shadow;
424 r_shadow_shadowmappcf = 1;
427 r_shadow_shadowmappcf = 1;
430 r_shadow_shadowmappcf = 2;
434 switch (r_shadow_shadowmaptexturetype)
437 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
440 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE;
443 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE;
446 if((vid.support.amd_texture_texture4 || vid.support.arb_texture_gather) && r_shadow_shadowmappcf && !r_shadow_shadowmapsampler)
447 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
448 else if(vid.support.arb_texture_rectangle)
449 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE;
451 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
456 case RENDERPATH_GL13:
458 case RENDERPATH_GL11:
463 void R_Shadow_FreeShadowMaps(void)
467 R_Shadow_SetShadowMode();
469 if (!vid.support.ext_framebuffer_object || !vid.support.arb_fragment_shader)
474 if (r_shadow_fborectangle)
475 qglDeleteFramebuffersEXT(1, &r_shadow_fborectangle);CHECKGLERROR
476 r_shadow_fborectangle = 0;
479 qglDeleteFramebuffersEXT(1, &r_shadow_fbo2d);CHECKGLERROR
481 for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
482 if (r_shadow_fbocubeside[i])
483 qglDeleteFramebuffersEXT(1, &r_shadow_fbocubeside[i]);CHECKGLERROR
484 memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
486 if (r_shadow_shadowmaprectangletexture)
487 R_FreeTexture(r_shadow_shadowmaprectangletexture);
488 r_shadow_shadowmaprectangletexture = NULL;
490 if (r_shadow_shadowmap2dtexture)
491 R_FreeTexture(r_shadow_shadowmap2dtexture);
492 r_shadow_shadowmap2dtexture = NULL;
494 for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
495 if (r_shadow_shadowmapcubetexture[i])
496 R_FreeTexture(r_shadow_shadowmapcubetexture[i]);
497 memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
499 if (r_shadow_shadowmapvsdcttexture)
500 R_FreeTexture(r_shadow_shadowmapvsdcttexture);
501 r_shadow_shadowmapvsdcttexture = NULL;
506 void r_shadow_start(void)
508 // allocate vertex processing arrays
510 r_shadow_attenuationgradienttexture = NULL;
511 r_shadow_attenuation2dtexture = NULL;
512 r_shadow_attenuation3dtexture = NULL;
513 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
514 r_shadow_shadowmaprectangletexture = NULL;
515 r_shadow_shadowmap2dtexture = NULL;
516 memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
517 r_shadow_shadowmapvsdcttexture = NULL;
518 r_shadow_shadowmapmaxsize = 0;
519 r_shadow_shadowmapsize = 0;
520 r_shadow_shadowmaplod = 0;
521 r_shadow_shadowmapfilterquality = -1;
522 r_shadow_shadowmaptexturetype = -1;
523 r_shadow_shadowmapdepthbits = 0;
524 r_shadow_shadowmapvsdct = false;
525 r_shadow_shadowmapsampler = false;
526 r_shadow_shadowmappcf = 0;
527 r_shadow_fborectangle = 0;
529 memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
531 R_Shadow_FreeShadowMaps();
533 r_shadow_texturepool = NULL;
534 r_shadow_filters_texturepool = NULL;
535 R_Shadow_ValidateCvars();
536 R_Shadow_MakeTextures();
537 maxshadowtriangles = 0;
538 shadowelements = NULL;
539 maxshadowvertices = 0;
540 shadowvertex3f = NULL;
548 shadowmarklist = NULL;
553 shadowsideslist = NULL;
554 r_shadow_buffer_numleafpvsbytes = 0;
555 r_shadow_buffer_visitingleafpvs = NULL;
556 r_shadow_buffer_leafpvs = NULL;
557 r_shadow_buffer_leaflist = NULL;
558 r_shadow_buffer_numsurfacepvsbytes = 0;
559 r_shadow_buffer_surfacepvs = NULL;
560 r_shadow_buffer_surfacelist = NULL;
561 r_shadow_buffer_surfacesides = NULL;
562 r_shadow_buffer_numshadowtrispvsbytes = 0;
563 r_shadow_buffer_shadowtrispvs = NULL;
564 r_shadow_buffer_numlighttrispvsbytes = 0;
565 r_shadow_buffer_lighttrispvs = NULL;
567 r_shadow_usingdeferredprepass = false;
568 r_shadow_prepass_width = r_shadow_prepass_height = 0;
571 static void R_Shadow_FreeDeferred(void);
572 void r_shadow_shutdown(void)
575 R_Shadow_UncompileWorldLights();
577 R_Shadow_FreeShadowMaps();
579 r_shadow_usingdeferredprepass = false;
580 if (r_shadow_prepass_width)
581 R_Shadow_FreeDeferred();
582 r_shadow_prepass_width = r_shadow_prepass_height = 0;
586 r_shadow_attenuationgradienttexture = NULL;
587 r_shadow_attenuation2dtexture = NULL;
588 r_shadow_attenuation3dtexture = NULL;
589 R_FreeTexturePool(&r_shadow_texturepool);
590 R_FreeTexturePool(&r_shadow_filters_texturepool);
591 maxshadowtriangles = 0;
593 Mem_Free(shadowelements);
594 shadowelements = NULL;
596 Mem_Free(shadowvertex3f);
597 shadowvertex3f = NULL;
600 Mem_Free(vertexupdate);
603 Mem_Free(vertexremap);
609 Mem_Free(shadowmark);
612 Mem_Free(shadowmarklist);
613 shadowmarklist = NULL;
618 Mem_Free(shadowsides);
621 Mem_Free(shadowsideslist);
622 shadowsideslist = NULL;
623 r_shadow_buffer_numleafpvsbytes = 0;
624 if (r_shadow_buffer_visitingleafpvs)
625 Mem_Free(r_shadow_buffer_visitingleafpvs);
626 r_shadow_buffer_visitingleafpvs = NULL;
627 if (r_shadow_buffer_leafpvs)
628 Mem_Free(r_shadow_buffer_leafpvs);
629 r_shadow_buffer_leafpvs = NULL;
630 if (r_shadow_buffer_leaflist)
631 Mem_Free(r_shadow_buffer_leaflist);
632 r_shadow_buffer_leaflist = NULL;
633 r_shadow_buffer_numsurfacepvsbytes = 0;
634 if (r_shadow_buffer_surfacepvs)
635 Mem_Free(r_shadow_buffer_surfacepvs);
636 r_shadow_buffer_surfacepvs = NULL;
637 if (r_shadow_buffer_surfacelist)
638 Mem_Free(r_shadow_buffer_surfacelist);
639 r_shadow_buffer_surfacelist = NULL;
640 if (r_shadow_buffer_surfacesides)
641 Mem_Free(r_shadow_buffer_surfacesides);
642 r_shadow_buffer_surfacesides = NULL;
643 r_shadow_buffer_numshadowtrispvsbytes = 0;
644 if (r_shadow_buffer_shadowtrispvs)
645 Mem_Free(r_shadow_buffer_shadowtrispvs);
646 r_shadow_buffer_numlighttrispvsbytes = 0;
647 if (r_shadow_buffer_lighttrispvs)
648 Mem_Free(r_shadow_buffer_lighttrispvs);
651 void r_shadow_newmap(void)
653 if (r_shadow_lightcorona) R_SkinFrame_MarkUsed(r_shadow_lightcorona);
654 if (r_editlights_sprcursor) R_SkinFrame_MarkUsed(r_editlights_sprcursor);
655 if (r_editlights_sprlight) R_SkinFrame_MarkUsed(r_editlights_sprlight);
656 if (r_editlights_sprnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprnoshadowlight);
657 if (r_editlights_sprcubemaplight) R_SkinFrame_MarkUsed(r_editlights_sprcubemaplight);
658 if (r_editlights_sprcubemapnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprcubemapnoshadowlight);
659 if (r_editlights_sprselection) R_SkinFrame_MarkUsed(r_editlights_sprselection);
660 if (cl.worldmodel && strncmp(cl.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
661 R_Shadow_EditLights_Reload_f();
664 void R_Shadow_Init(void)
666 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
667 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
668 Cvar_RegisterVariable(&r_shadow_usenormalmap);
669 Cvar_RegisterVariable(&r_shadow_debuglight);
670 Cvar_RegisterVariable(&r_shadow_deferred);
671 Cvar_RegisterVariable(&r_shadow_deferred_8bitrange);
672 // Cvar_RegisterVariable(&r_shadow_deferred_fp);
673 Cvar_RegisterVariable(&r_shadow_gloss);
674 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
675 Cvar_RegisterVariable(&r_shadow_glossintensity);
676 Cvar_RegisterVariable(&r_shadow_glossexponent);
677 Cvar_RegisterVariable(&r_shadow_gloss2exponent);
678 Cvar_RegisterVariable(&r_shadow_glossexact);
679 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
680 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
681 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
682 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
683 Cvar_RegisterVariable(&r_shadow_portallight);
684 Cvar_RegisterVariable(&r_shadow_projectdistance);
685 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
686 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
687 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
688 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
689 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
690 Cvar_RegisterVariable(&r_shadow_realtime_world);
691 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
692 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
693 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
694 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
695 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
696 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
697 Cvar_RegisterVariable(&r_shadow_scissor);
698 Cvar_RegisterVariable(&r_shadow_shadowmapping);
699 Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
700 Cvar_RegisterVariable(&r_shadow_shadowmapping_texturetype);
701 Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
702 Cvar_RegisterVariable(&r_shadow_shadowmapping_depthbits);
703 Cvar_RegisterVariable(&r_shadow_shadowmapping_precision);
704 Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
705 Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
706 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
707 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
708 Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
709 Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
710 Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
711 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonfactor);
712 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonoffset);
713 Cvar_RegisterVariable(&r_shadow_polygonfactor);
714 Cvar_RegisterVariable(&r_shadow_polygonoffset);
715 Cvar_RegisterVariable(&r_shadow_texture3d);
716 Cvar_RegisterVariable(&r_coronas);
717 Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
718 Cvar_RegisterVariable(&r_coronas_occlusionquery);
719 Cvar_RegisterVariable(&gl_flashblend);
720 Cvar_RegisterVariable(&gl_ext_separatestencil);
721 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
722 if (gamemode == GAME_TENEBRAE)
724 Cvar_SetValue("r_shadow_gloss", 2);
725 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
727 R_Shadow_EditLights_Init();
728 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
729 maxshadowtriangles = 0;
730 shadowelements = NULL;
731 maxshadowvertices = 0;
732 shadowvertex3f = NULL;
740 shadowmarklist = NULL;
745 shadowsideslist = NULL;
746 r_shadow_buffer_numleafpvsbytes = 0;
747 r_shadow_buffer_visitingleafpvs = NULL;
748 r_shadow_buffer_leafpvs = NULL;
749 r_shadow_buffer_leaflist = NULL;
750 r_shadow_buffer_numsurfacepvsbytes = 0;
751 r_shadow_buffer_surfacepvs = NULL;
752 r_shadow_buffer_surfacelist = NULL;
753 r_shadow_buffer_surfacesides = NULL;
754 r_shadow_buffer_shadowtrispvs = NULL;
755 r_shadow_buffer_lighttrispvs = NULL;
756 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
759 matrix4x4_t matrix_attenuationxyz =
762 {0.5, 0.0, 0.0, 0.5},
763 {0.0, 0.5, 0.0, 0.5},
764 {0.0, 0.0, 0.5, 0.5},
769 matrix4x4_t matrix_attenuationz =
772 {0.0, 0.0, 0.5, 0.5},
773 {0.0, 0.0, 0.0, 0.5},
774 {0.0, 0.0, 0.0, 0.5},
779 void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles, int vertscale, int triscale)
781 numvertices = ((numvertices + 255) & ~255) * vertscale;
782 numtriangles = ((numtriangles + 255) & ~255) * triscale;
783 // make sure shadowelements is big enough for this volume
784 if (maxshadowtriangles < numtriangles)
786 maxshadowtriangles = numtriangles;
788 Mem_Free(shadowelements);
789 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[3]));
791 // make sure shadowvertex3f is big enough for this volume
792 if (maxshadowvertices < numvertices)
794 maxshadowvertices = numvertices;
796 Mem_Free(shadowvertex3f);
797 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[3]));
801 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
803 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
804 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
805 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
806 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
807 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
809 if (r_shadow_buffer_visitingleafpvs)
810 Mem_Free(r_shadow_buffer_visitingleafpvs);
811 if (r_shadow_buffer_leafpvs)
812 Mem_Free(r_shadow_buffer_leafpvs);
813 if (r_shadow_buffer_leaflist)
814 Mem_Free(r_shadow_buffer_leaflist);
815 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
816 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
817 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
818 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
820 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
822 if (r_shadow_buffer_surfacepvs)
823 Mem_Free(r_shadow_buffer_surfacepvs);
824 if (r_shadow_buffer_surfacelist)
825 Mem_Free(r_shadow_buffer_surfacelist);
826 if (r_shadow_buffer_surfacesides)
827 Mem_Free(r_shadow_buffer_surfacesides);
828 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
829 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
830 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
831 r_shadow_buffer_surfacesides = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
833 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
835 if (r_shadow_buffer_shadowtrispvs)
836 Mem_Free(r_shadow_buffer_shadowtrispvs);
837 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
838 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
840 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
842 if (r_shadow_buffer_lighttrispvs)
843 Mem_Free(r_shadow_buffer_lighttrispvs);
844 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
845 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
849 void R_Shadow_PrepareShadowMark(int numtris)
851 // make sure shadowmark is big enough for this volume
852 if (maxshadowmark < numtris)
854 maxshadowmark = numtris;
856 Mem_Free(shadowmark);
858 Mem_Free(shadowmarklist);
859 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
860 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
864 // if shadowmarkcount wrapped we clear the array and adjust accordingly
865 if (shadowmarkcount == 0)
868 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
873 void R_Shadow_PrepareShadowSides(int numtris)
875 if (maxshadowsides < numtris)
877 maxshadowsides = numtris;
879 Mem_Free(shadowsides);
881 Mem_Free(shadowsideslist);
882 shadowsides = (unsigned char *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsides));
883 shadowsideslist = (int *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsideslist));
888 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)
891 int outtriangles = 0, outvertices = 0;
894 float ratio, direction[3], projectvector[3];
896 if (projectdirection)
897 VectorScale(projectdirection, projectdistance, projectvector);
899 VectorClear(projectvector);
901 // create the vertices
902 if (projectdirection)
904 for (i = 0;i < numshadowmarktris;i++)
906 element = inelement3i + shadowmarktris[i] * 3;
907 for (j = 0;j < 3;j++)
909 if (vertexupdate[element[j]] != vertexupdatenum)
911 vertexupdate[element[j]] = vertexupdatenum;
912 vertexremap[element[j]] = outvertices;
913 vertex = invertex3f + element[j] * 3;
914 // project one copy of the vertex according to projectvector
915 VectorCopy(vertex, outvertex3f);
916 VectorAdd(vertex, projectvector, (outvertex3f + 3));
925 for (i = 0;i < numshadowmarktris;i++)
927 element = inelement3i + shadowmarktris[i] * 3;
928 for (j = 0;j < 3;j++)
930 if (vertexupdate[element[j]] != vertexupdatenum)
932 vertexupdate[element[j]] = vertexupdatenum;
933 vertexremap[element[j]] = outvertices;
934 vertex = invertex3f + element[j] * 3;
935 // project one copy of the vertex to the sphere radius of the light
936 // (FIXME: would projecting it to the light box be better?)
937 VectorSubtract(vertex, projectorigin, direction);
938 ratio = projectdistance / VectorLength(direction);
939 VectorCopy(vertex, outvertex3f);
940 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
948 if (r_shadow_frontsidecasting.integer)
950 for (i = 0;i < numshadowmarktris;i++)
952 int remappedelement[3];
954 const int *neighbortriangle;
956 markindex = shadowmarktris[i] * 3;
957 element = inelement3i + markindex;
958 neighbortriangle = inneighbor3i + markindex;
959 // output the front and back triangles
960 outelement3i[0] = vertexremap[element[0]];
961 outelement3i[1] = vertexremap[element[1]];
962 outelement3i[2] = vertexremap[element[2]];
963 outelement3i[3] = vertexremap[element[2]] + 1;
964 outelement3i[4] = vertexremap[element[1]] + 1;
965 outelement3i[5] = vertexremap[element[0]] + 1;
969 // output the sides (facing outward from this triangle)
970 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
972 remappedelement[0] = vertexremap[element[0]];
973 remappedelement[1] = vertexremap[element[1]];
974 outelement3i[0] = remappedelement[1];
975 outelement3i[1] = remappedelement[0];
976 outelement3i[2] = remappedelement[0] + 1;
977 outelement3i[3] = remappedelement[1];
978 outelement3i[4] = remappedelement[0] + 1;
979 outelement3i[5] = remappedelement[1] + 1;
984 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
986 remappedelement[1] = vertexremap[element[1]];
987 remappedelement[2] = vertexremap[element[2]];
988 outelement3i[0] = remappedelement[2];
989 outelement3i[1] = remappedelement[1];
990 outelement3i[2] = remappedelement[1] + 1;
991 outelement3i[3] = remappedelement[2];
992 outelement3i[4] = remappedelement[1] + 1;
993 outelement3i[5] = remappedelement[2] + 1;
998 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1000 remappedelement[0] = vertexremap[element[0]];
1001 remappedelement[2] = vertexremap[element[2]];
1002 outelement3i[0] = remappedelement[0];
1003 outelement3i[1] = remappedelement[2];
1004 outelement3i[2] = remappedelement[2] + 1;
1005 outelement3i[3] = remappedelement[0];
1006 outelement3i[4] = remappedelement[2] + 1;
1007 outelement3i[5] = remappedelement[0] + 1;
1016 for (i = 0;i < numshadowmarktris;i++)
1018 int remappedelement[3];
1020 const int *neighbortriangle;
1022 markindex = shadowmarktris[i] * 3;
1023 element = inelement3i + markindex;
1024 neighbortriangle = inneighbor3i + markindex;
1025 // output the front and back triangles
1026 outelement3i[0] = vertexremap[element[2]];
1027 outelement3i[1] = vertexremap[element[1]];
1028 outelement3i[2] = vertexremap[element[0]];
1029 outelement3i[3] = vertexremap[element[0]] + 1;
1030 outelement3i[4] = vertexremap[element[1]] + 1;
1031 outelement3i[5] = vertexremap[element[2]] + 1;
1035 // output the sides (facing outward from this triangle)
1036 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
1038 remappedelement[0] = vertexremap[element[0]];
1039 remappedelement[1] = vertexremap[element[1]];
1040 outelement3i[0] = remappedelement[0];
1041 outelement3i[1] = remappedelement[1];
1042 outelement3i[2] = remappedelement[1] + 1;
1043 outelement3i[3] = remappedelement[0];
1044 outelement3i[4] = remappedelement[1] + 1;
1045 outelement3i[5] = remappedelement[0] + 1;
1050 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1052 remappedelement[1] = vertexremap[element[1]];
1053 remappedelement[2] = vertexremap[element[2]];
1054 outelement3i[0] = remappedelement[1];
1055 outelement3i[1] = remappedelement[2];
1056 outelement3i[2] = remappedelement[2] + 1;
1057 outelement3i[3] = remappedelement[1];
1058 outelement3i[4] = remappedelement[2] + 1;
1059 outelement3i[5] = remappedelement[1] + 1;
1064 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1066 remappedelement[0] = vertexremap[element[0]];
1067 remappedelement[2] = vertexremap[element[2]];
1068 outelement3i[0] = remappedelement[2];
1069 outelement3i[1] = remappedelement[0];
1070 outelement3i[2] = remappedelement[0] + 1;
1071 outelement3i[3] = remappedelement[2];
1072 outelement3i[4] = remappedelement[0] + 1;
1073 outelement3i[5] = remappedelement[2] + 1;
1081 *outnumvertices = outvertices;
1082 return outtriangles;
1085 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)
1088 int outtriangles = 0, outvertices = 0;
1090 const float *vertex;
1091 float ratio, direction[3], projectvector[3];
1094 if (projectdirection)
1095 VectorScale(projectdirection, projectdistance, projectvector);
1097 VectorClear(projectvector);
1099 for (i = 0;i < numshadowmarktris;i++)
1101 int remappedelement[3];
1103 const int *neighbortriangle;
1105 markindex = shadowmarktris[i] * 3;
1106 neighbortriangle = inneighbor3i + markindex;
1107 side[0] = shadowmark[neighbortriangle[0]] == shadowmarkcount;
1108 side[1] = shadowmark[neighbortriangle[1]] == shadowmarkcount;
1109 side[2] = shadowmark[neighbortriangle[2]] == shadowmarkcount;
1110 if (side[0] + side[1] + side[2] == 0)
1114 element = inelement3i + markindex;
1116 // create the vertices
1117 for (j = 0;j < 3;j++)
1119 if (side[j] + side[j+1] == 0)
1122 if (vertexupdate[k] != vertexupdatenum)
1124 vertexupdate[k] = vertexupdatenum;
1125 vertexremap[k] = outvertices;
1126 vertex = invertex3f + k * 3;
1127 VectorCopy(vertex, outvertex3f);
1128 if (projectdirection)
1130 // project one copy of the vertex according to projectvector
1131 VectorAdd(vertex, projectvector, (outvertex3f + 3));
1135 // project one copy of the vertex to the sphere radius of the light
1136 // (FIXME: would projecting it to the light box be better?)
1137 VectorSubtract(vertex, projectorigin, direction);
1138 ratio = projectdistance / VectorLength(direction);
1139 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1146 // output the sides (facing outward from this triangle)
1149 remappedelement[0] = vertexremap[element[0]];
1150 remappedelement[1] = vertexremap[element[1]];
1151 outelement3i[0] = remappedelement[1];
1152 outelement3i[1] = remappedelement[0];
1153 outelement3i[2] = remappedelement[0] + 1;
1154 outelement3i[3] = remappedelement[1];
1155 outelement3i[4] = remappedelement[0] + 1;
1156 outelement3i[5] = remappedelement[1] + 1;
1163 remappedelement[1] = vertexremap[element[1]];
1164 remappedelement[2] = vertexremap[element[2]];
1165 outelement3i[0] = remappedelement[2];
1166 outelement3i[1] = remappedelement[1];
1167 outelement3i[2] = remappedelement[1] + 1;
1168 outelement3i[3] = remappedelement[2];
1169 outelement3i[4] = remappedelement[1] + 1;
1170 outelement3i[5] = remappedelement[2] + 1;
1177 remappedelement[0] = vertexremap[element[0]];
1178 remappedelement[2] = vertexremap[element[2]];
1179 outelement3i[0] = remappedelement[0];
1180 outelement3i[1] = remappedelement[2];
1181 outelement3i[2] = remappedelement[2] + 1;
1182 outelement3i[3] = remappedelement[0];
1183 outelement3i[4] = remappedelement[2] + 1;
1184 outelement3i[5] = remappedelement[0] + 1;
1191 *outnumvertices = outvertices;
1192 return outtriangles;
1195 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)
1201 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1203 tend = firsttriangle + numtris;
1204 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1206 // surface box entirely inside light box, no box cull
1207 if (projectdirection)
1209 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1211 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
1212 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1213 shadowmarklist[numshadowmark++] = t;
1218 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1219 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
1220 shadowmarklist[numshadowmark++] = t;
1225 // surface box not entirely inside light box, cull each triangle
1226 if (projectdirection)
1228 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1230 v[0] = invertex3f + e[0] * 3;
1231 v[1] = invertex3f + e[1] * 3;
1232 v[2] = invertex3f + e[2] * 3;
1233 TriangleNormal(v[0], v[1], v[2], normal);
1234 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1235 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1236 shadowmarklist[numshadowmark++] = t;
1241 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1243 v[0] = invertex3f + e[0] * 3;
1244 v[1] = invertex3f + e[1] * 3;
1245 v[2] = invertex3f + e[2] * 3;
1246 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1247 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1248 shadowmarklist[numshadowmark++] = t;
1254 qboolean R_Shadow_UseZPass(vec3_t mins, vec3_t maxs)
1259 if (r_shadow_compilingrtlight || !r_shadow_frontsidecasting.integer || !r_shadow_usezpassifpossible.integer)
1261 // check if the shadow volume intersects the near plane
1263 // a ray between the eye and light origin may intersect the caster,
1264 // indicating that the shadow may touch the eye location, however we must
1265 // test the near plane (a polygon), not merely the eye location, so it is
1266 // easiest to enlarge the caster bounding shape slightly for this.
1272 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)
1274 int i, tris, outverts;
1275 if (projectdistance < 0.1)
1277 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
1280 if (!numverts || !nummarktris)
1282 // make sure shadowelements is big enough for this volume
1283 if (maxshadowtriangles < nummarktris*8 || maxshadowvertices < numverts*2)
1284 R_Shadow_ResizeShadowArrays(numverts, nummarktris, 2, 8);
1286 if (maxvertexupdate < numverts)
1288 maxvertexupdate = numverts;
1290 Mem_Free(vertexupdate);
1292 Mem_Free(vertexremap);
1293 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1294 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1295 vertexupdatenum = 0;
1298 if (vertexupdatenum == 0)
1300 vertexupdatenum = 1;
1301 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
1302 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
1305 for (i = 0;i < nummarktris;i++)
1306 shadowmark[marktris[i]] = shadowmarkcount;
1308 if (r_shadow_compilingrtlight)
1310 // if we're compiling an rtlight, capture the mesh
1311 //tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1312 //Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zpass, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1313 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1314 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zfail, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1316 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
1318 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1319 R_Mesh_VertexPointer(shadowvertex3f, 0, 0);
1320 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1324 // decide which type of shadow to generate and set stencil mode
1325 R_Shadow_RenderMode_StencilShadowVolumes(R_Shadow_UseZPass(trismins, trismaxs));
1326 // generate the sides or a solid volume, depending on type
1327 if (r_shadow_rendermode >= R_SHADOW_RENDERMODE_ZPASS_STENCIL && r_shadow_rendermode <= R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE)
1328 tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1330 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1331 r_refdef.stats.lights_dynamicshadowtriangles += tris;
1332 r_refdef.stats.lights_shadowtriangles += tris;
1334 R_Mesh_VertexPointer(shadowvertex3f, 0, 0);
1335 GL_LockArrays(0, outverts);
1336 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
1338 // increment stencil if frontface is infront of depthbuffer
1339 GL_CullFace(r_refdef.view.cullface_front);
1340 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1341 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1342 // decrement stencil if backface is infront of depthbuffer
1343 GL_CullFace(r_refdef.view.cullface_back);
1344 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1346 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
1348 // decrement stencil if backface is behind depthbuffer
1349 GL_CullFace(r_refdef.view.cullface_front);
1350 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1351 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1352 // increment stencil if frontface is behind depthbuffer
1353 GL_CullFace(r_refdef.view.cullface_back);
1354 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1356 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1357 GL_LockArrays(0, 0);
1362 int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias)
1364 // p1, p2, p3 are in the cubemap's local coordinate system
1365 // bias = border/(size - border)
1368 float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1369 dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2),
1370 dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3);
1371 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1373 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1374 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1375 | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1376 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1378 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1379 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1380 | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1382 dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1383 dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2),
1384 dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3);
1385 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1387 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1388 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1389 | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1390 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1392 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1393 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1394 | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1396 dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1397 dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2),
1398 dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3);
1399 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1401 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1402 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1403 | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1404 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1406 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1407 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1408 | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1413 int R_Shadow_CalcBBoxSideMask(const vec3_t mins, const vec3_t maxs, const matrix4x4_t *worldtolight, const matrix4x4_t *radiustolight, float bias)
1415 vec3_t center, radius, lightcenter, lightradius, pmin, pmax;
1416 float dp1, dn1, ap1, an1, dp2, dn2, ap2, an2;
1419 VectorSubtract(maxs, mins, radius);
1420 VectorScale(radius, 0.5f, radius);
1421 VectorAdd(mins, radius, center);
1422 Matrix4x4_Transform(worldtolight, center, lightcenter);
1423 Matrix4x4_Transform3x3(radiustolight, radius, lightradius);
1424 VectorSubtract(lightcenter, lightradius, pmin);
1425 VectorAdd(lightcenter, lightradius, pmax);
1427 dp1 = pmax[0] + pmax[1], dn1 = pmax[0] - pmin[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1428 dp2 = pmin[0] + pmin[1], dn2 = pmin[0] - pmax[1], ap2 = fabs(dp2), an2 = fabs(dn2);
1429 if(ap1 > bias*an1 && ap2 > bias*an2)
1431 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1432 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1433 if(an1 > bias*ap1 && an2 > bias*ap2)
1435 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1436 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1438 dp1 = pmax[1] + pmax[2], dn1 = pmax[1] - pmin[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1439 dp2 = pmin[1] + pmin[2], dn2 = pmin[1] - pmax[2], ap2 = fabs(dp2), an2 = fabs(dn2);
1440 if(ap1 > bias*an1 && ap2 > bias*an2)
1442 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1443 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1444 if(an1 > bias*ap1 && an2 > bias*ap2)
1446 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1447 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1449 dp1 = pmax[2] + pmax[0], dn1 = pmax[2] - pmin[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1450 dp2 = pmin[2] + pmin[0], dn2 = pmin[2] - pmax[0], ap2 = fabs(dp2), an2 = fabs(dn2);
1451 if(ap1 > bias*an1 && ap2 > bias*an2)
1453 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1454 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1455 if(an1 > bias*ap1 && an2 > bias*ap2)
1457 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1458 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1463 #define R_Shadow_CalcEntitySideMask(ent, worldtolight, radiustolight, bias) R_Shadow_CalcBBoxSideMask((ent)->mins, (ent)->maxs, worldtolight, radiustolight, bias)
1465 int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
1467 // p is in the cubemap's local coordinate system
1468 // bias = border/(size - border)
1469 float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn);
1470 float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn);
1471 float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn);
1473 if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
1474 if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
1475 if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
1476 if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
1477 if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
1478 if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
1482 int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
1486 int sides = 0x3F, masks[6] = { 3<<4, 3<<4, 3<<0, 3<<0, 3<<2, 3<<2 };
1487 float scale = (size - 2*border)/size, len;
1488 float bias = border / (float)(size - border), dp, dn, ap, an;
1489 // check if cone enclosing side would cross frustum plane
1490 scale = 2 / (scale*scale + 2);
1491 for (i = 0;i < 5;i++)
1493 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) > -0.03125)
1495 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[i].normal, n);
1496 len = scale*VectorLength2(n);
1497 if(n[0]*n[0] > len) sides &= n[0] < 0 ? ~(1<<0) : ~(2 << 0);
1498 if(n[1]*n[1] > len) sides &= n[1] < 0 ? ~(1<<2) : ~(2 << 2);
1499 if(n[2]*n[2] > len) sides &= n[2] < 0 ? ~(1<<4) : ~(2 << 4);
1501 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[4]) >= r_refdef.farclip - r_refdef.nearclip + 0.03125)
1503 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[4].normal, n);
1504 len = scale*VectorLength(n);
1505 if(n[0]*n[0] > len) sides &= n[0] >= 0 ? ~(1<<0) : ~(2 << 0);
1506 if(n[1]*n[1] > len) sides &= n[1] >= 0 ? ~(1<<2) : ~(2 << 2);
1507 if(n[2]*n[2] > len) sides &= n[2] >= 0 ? ~(1<<4) : ~(2 << 4);
1509 // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results
1510 // check if frustum corners/origin cross plane sides
1511 for (i = 0;i < 5;i++)
1513 Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p);
1514 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn),
1515 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1516 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1517 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn),
1518 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1519 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1520 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn),
1521 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1522 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1524 return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5];
1527 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)
1535 int mask, surfacemask = 0;
1536 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1538 bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
1539 tend = firsttriangle + numtris;
1540 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1542 // surface box entirely inside light box, no box cull
1543 if (projectdirection)
1545 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1547 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1548 TriangleNormal(v[0], v[1], v[2], normal);
1549 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1551 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1552 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1553 surfacemask |= mask;
1556 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;
1557 shadowsides[numshadowsides] = mask;
1558 shadowsideslist[numshadowsides++] = t;
1565 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1567 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1568 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]))
1570 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1571 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1572 surfacemask |= mask;
1575 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;
1576 shadowsides[numshadowsides] = mask;
1577 shadowsideslist[numshadowsides++] = t;
1585 // surface box not entirely inside light box, cull each triangle
1586 if (projectdirection)
1588 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1590 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1591 TriangleNormal(v[0], v[1], v[2], normal);
1592 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1593 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1595 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1596 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1597 surfacemask |= mask;
1600 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;
1601 shadowsides[numshadowsides] = mask;
1602 shadowsideslist[numshadowsides++] = t;
1609 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1611 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1612 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1613 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1615 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1616 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1617 surfacemask |= mask;
1620 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;
1621 shadowsides[numshadowsides] = mask;
1622 shadowsideslist[numshadowsides++] = t;
1631 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)
1633 int i, j, outtriangles = 0;
1634 int *outelement3i[6];
1635 if (!numverts || !numsidetris || !r_shadow_compilingrtlight)
1637 outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5];
1638 // make sure shadowelements is big enough for this mesh
1639 if (maxshadowtriangles < outtriangles)
1640 R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1);
1642 // compute the offset and size of the separate index lists for each cubemap side
1644 for (i = 0;i < 6;i++)
1646 outelement3i[i] = shadowelements + outtriangles * 3;
1647 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles;
1648 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i];
1649 outtriangles += sidetotals[i];
1652 // gather up the (sparse) triangles into separate index lists for each cubemap side
1653 for (i = 0;i < numsidetris;i++)
1655 const int *element = elements + sidetris[i] * 3;
1656 for (j = 0;j < 6;j++)
1658 if (sides[i] & (1 << j))
1660 outelement3i[j][0] = element[0];
1661 outelement3i[j][1] = element[1];
1662 outelement3i[j][2] = element[2];
1663 outelement3i[j] += 3;
1668 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, outtriangles, shadowelements);
1671 static void R_Shadow_MakeTextures_MakeCorona(void)
1675 unsigned char pixels[32][32][4];
1676 for (y = 0;y < 32;y++)
1678 dy = (y - 15.5f) * (1.0f / 16.0f);
1679 for (x = 0;x < 32;x++)
1681 dx = (x - 15.5f) * (1.0f / 16.0f);
1682 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1683 a = bound(0, a, 255);
1684 pixels[y][x][0] = a;
1685 pixels[y][x][1] = a;
1686 pixels[y][x][2] = a;
1687 pixels[y][x][3] = 255;
1690 r_shadow_lightcorona = R_SkinFrame_LoadInternalBGRA("lightcorona", TEXF_FORCELINEAR, &pixels[0][0][0], 32, 32);
1693 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1695 float dist = sqrt(x*x+y*y+z*z);
1696 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1697 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1698 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1701 static void R_Shadow_MakeTextures(void)
1704 float intensity, dist;
1706 R_Shadow_FreeShadowMaps();
1707 R_FreeTexturePool(&r_shadow_texturepool);
1708 r_shadow_texturepool = R_AllocTexturePool();
1709 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1710 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1711 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1712 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1713 for (x = 0;x <= ATTENTABLESIZE;x++)
1715 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1716 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1717 r_shadow_attentable[x] = bound(0, intensity, 1);
1719 // 1D gradient texture
1720 for (x = 0;x < ATTEN1DSIZE;x++)
1721 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1722 r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, NULL);
1723 // 2D circle texture
1724 for (y = 0;y < ATTEN2DSIZE;y++)
1725 for (x = 0;x < ATTEN2DSIZE;x++)
1726 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);
1727 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, NULL);
1728 // 3D sphere texture
1729 if (r_shadow_texture3d.integer && vid.support.ext_texture_3d)
1731 for (z = 0;z < ATTEN3DSIZE;z++)
1732 for (y = 0;y < ATTEN3DSIZE;y++)
1733 for (x = 0;x < ATTEN3DSIZE;x++)
1734 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));
1735 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, NULL);
1738 r_shadow_attenuation3dtexture = NULL;
1741 R_Shadow_MakeTextures_MakeCorona();
1743 // Editor light sprites
1744 r_editlights_sprcursor = R_SkinFrame_LoadInternal8bit("gfx/editlights/cursor", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1761 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1762 r_editlights_sprlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/light", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1779 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1780 r_editlights_sprnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/noshadow", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1797 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1798 r_editlights_sprcubemaplight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemaplight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1815 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1816 r_editlights_sprcubemapnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemapnoshadowlight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1833 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1834 r_editlights_sprselection = R_SkinFrame_LoadInternal8bit("gfx/editlights/selection", TEXF_ALPHA | TEXF_CLAMP, (unsigned char *)
1851 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1854 void R_Shadow_ValidateCvars(void)
1856 if (r_shadow_texture3d.integer && !vid.support.ext_texture_3d)
1857 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1858 if (gl_ext_separatestencil.integer && !vid.support.ati_separate_stencil)
1859 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
1860 if (gl_ext_stenciltwoside.integer && !vid.support.ext_stencil_two_side)
1861 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1864 void R_Shadow_RenderMode_Begin(void)
1870 R_Shadow_ValidateCvars();
1872 if (!r_shadow_attenuation2dtexture
1873 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1874 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1875 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1876 R_Shadow_MakeTextures();
1879 R_Mesh_ColorPointer(NULL, 0, 0);
1880 R_Mesh_ResetTextureState();
1881 GL_BlendFunc(GL_ONE, GL_ZERO);
1882 GL_DepthRange(0, 1);
1883 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1885 GL_DepthMask(false);
1886 GL_Color(0, 0, 0, 1);
1887 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1889 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1891 if (gl_ext_separatestencil.integer && vid.support.ati_separate_stencil)
1893 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
1894 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
1896 else if (gl_ext_stenciltwoside.integer && vid.support.ext_stencil_two_side)
1898 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
1899 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
1903 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
1904 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
1907 switch(vid.renderpath)
1909 case RENDERPATH_GL20:
1910 case RENDERPATH_CGGL:
1911 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1913 case RENDERPATH_GL13:
1914 case RENDERPATH_GL11:
1915 if (r_textureunits.integer >= 2 && vid.texunits >= 2 && r_shadow_texture3d.integer && r_shadow_attenuation3dtexture)
1916 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN;
1917 else if (r_textureunits.integer >= 3 && vid.texunits >= 3)
1918 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN;
1919 else if (r_textureunits.integer >= 2 && vid.texunits >= 2)
1920 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN;
1922 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1928 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
1929 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
1930 r_shadow_drawbuffer = drawbuffer;
1931 r_shadow_readbuffer = readbuffer;
1933 r_shadow_cullface_front = r_refdef.view.cullface_front;
1934 r_shadow_cullface_back = r_refdef.view.cullface_back;
1937 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
1939 rsurface.rtlight = rtlight;
1942 void R_Shadow_RenderMode_Reset(void)
1945 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE)
1947 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1949 if (vid.support.ext_framebuffer_object)
1951 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);CHECKGLERROR
1954 qglDrawBuffer(r_shadow_drawbuffer);CHECKGLERROR
1955 qglReadBuffer(r_shadow_readbuffer);CHECKGLERROR
1957 R_SetViewport(&r_refdef.view.viewport);
1958 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
1959 R_Mesh_ColorPointer(NULL, 0, 0);
1960 R_Mesh_ResetTextureState();
1961 GL_DepthRange(0, 1);
1963 GL_DepthMask(false);
1964 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1965 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1966 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
1967 qglStencilMask(~0);CHECKGLERROR
1968 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
1969 qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
1970 r_refdef.view.cullface_front = r_shadow_cullface_front;
1971 r_refdef.view.cullface_back = r_shadow_cullface_back;
1972 GL_CullFace(r_refdef.view.cullface_back);
1973 GL_Color(1, 1, 1, 1);
1974 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
1975 GL_BlendFunc(GL_ONE, GL_ZERO);
1976 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
1977 r_shadow_usingshadowmaprect = false;
1978 r_shadow_usingshadowmapcube = false;
1979 r_shadow_usingshadowmap2d = false;
1983 void R_Shadow_ClearStencil(void)
1986 GL_Clear(GL_STENCIL_BUFFER_BIT);
1987 r_refdef.stats.lights_clears++;
1990 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
1992 r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
1993 if (r_shadow_rendermode == mode)
1996 R_Shadow_RenderMode_Reset();
1997 GL_ColorMask(0, 0, 0, 0);
1998 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1999 R_SetupShader_DepthOrShadow();
2000 qglDepthFunc(GL_LESS);CHECKGLERROR
2001 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2002 r_shadow_rendermode = mode;
2007 case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
2008 GL_CullFace(GL_NONE);
2009 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
2010 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
2012 case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
2013 GL_CullFace(GL_NONE);
2014 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
2015 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
2017 case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
2018 GL_CullFace(GL_NONE);
2019 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
2020 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
2021 qglStencilMask(~0);CHECKGLERROR
2022 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
2023 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
2024 qglStencilMask(~0);CHECKGLERROR
2025 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
2027 case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
2028 GL_CullFace(GL_NONE);
2029 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
2030 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
2031 qglStencilMask(~0);CHECKGLERROR
2032 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
2033 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
2034 qglStencilMask(~0);CHECKGLERROR
2035 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
2040 static void R_Shadow_MakeVSDCT(void)
2042 // maps to a 2x3 texture rectangle with normalized coordinates
2047 // stores abs(dir.xy), offset.xy/2.5
2048 unsigned char data[4*6] =
2050 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
2051 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
2052 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
2053 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
2054 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
2055 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
2057 r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, NULL);
2060 void R_Shadow_RenderMode_ShadowMap(int side, qboolean clear, int size)
2064 float nearclip, farclip, bias;
2065 r_viewport_t viewport;
2068 maxsize = r_shadow_shadowmapmaxsize;
2069 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
2071 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
2072 r_shadow_shadowmap_parameters[2] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
2073 r_shadow_shadowmap_parameters[3] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
2074 r_shadow_shadowmapside = side;
2075 r_shadow_shadowmapsize = size;
2076 if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
2078 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2079 r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2080 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
2081 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D) goto init_done;
2083 // complex unrolled cube approach (more flexible)
2084 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2085 R_Shadow_MakeVSDCT();
2086 if (!r_shadow_shadowmap2dtexture)
2089 int w = maxsize*2, h = vid.support.arb_texture_non_power_of_two ? maxsize*3 : maxsize*4;
2090 r_shadow_shadowmap2dtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "shadowmap", w, h, r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
2091 qglGenFramebuffersEXT(1, &r_shadow_fbo2d);CHECKGLERROR
2092 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbo2d);CHECKGLERROR
2093 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_shadowmap2dtexture), 0);CHECKGLERROR
2094 // render depth into the fbo, do not render color at all
2095 qglDrawBuffer(GL_NONE);CHECKGLERROR
2096 qglReadBuffer(GL_NONE);CHECKGLERROR
2097 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2098 if (status != GL_FRAMEBUFFER_COMPLETE_EXT && (r_shadow_shadowmapping.integer || r_shadow_deferred.integer))
2100 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2101 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2102 Cvar_SetValueQuick(&r_shadow_deferred, 0);
2107 if (r_shadow_shadowmap2dtexture) fbo = r_shadow_fbo2d;
2108 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
2109 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
2110 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
2112 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE)
2114 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2115 r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2116 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
2117 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE) goto init_done;
2119 // complex unrolled cube approach (more flexible)
2120 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2121 R_Shadow_MakeVSDCT();
2122 if (!r_shadow_shadowmaprectangletexture)
2125 r_shadow_shadowmaprectangletexture = R_LoadTextureShadowMapRectangle(r_shadow_texturepool, "shadowmap", maxsize*2, maxsize*3, r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
2126 qglGenFramebuffersEXT(1, &r_shadow_fborectangle);CHECKGLERROR
2127 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fborectangle);CHECKGLERROR
2128 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, R_GetTexture(r_shadow_shadowmaprectangletexture), 0);CHECKGLERROR
2129 // render depth into the fbo, do not render color at all
2130 qglDrawBuffer(GL_NONE);CHECKGLERROR
2131 qglReadBuffer(GL_NONE);CHECKGLERROR
2132 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2133 if (status != GL_FRAMEBUFFER_COMPLETE_EXT && (r_shadow_shadowmapping.integer || r_shadow_deferred.integer))
2135 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2136 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2137 Cvar_SetValueQuick(&r_shadow_deferred, 0);
2142 if(r_shadow_shadowmaprectangletexture) fbo = r_shadow_fborectangle;
2143 r_shadow_shadowmap_texturescale[0] = 1.0f;
2144 r_shadow_shadowmap_texturescale[1] = 1.0f;
2145 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE;
2147 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
2149 r_shadow_shadowmap_parameters[0] = 1.0f;
2150 r_shadow_shadowmap_parameters[1] = 1.0f;
2151 R_Viewport_InitCubeSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, nearclip, farclip, NULL);
2152 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE) goto init_done;
2154 // simple cube approach
2155 if (!r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod])
2158 r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod] = R_LoadTextureShadowMapCube(r_shadow_texturepool, "shadowmapcube", size, r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
2159 qglGenFramebuffersEXT(1, &r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR
2160 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR
2161 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
2162 // render depth into the fbo, do not render color at all
2163 qglDrawBuffer(GL_NONE);CHECKGLERROR
2164 qglReadBuffer(GL_NONE);CHECKGLERROR
2165 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2166 if (status != GL_FRAMEBUFFER_COMPLETE_EXT && (r_shadow_shadowmapping.integer || r_shadow_deferred.integer))
2168 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2169 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2170 Cvar_SetValueQuick(&r_shadow_deferred, 0);
2175 if (r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]) fbo = r_shadow_fbocubeside[r_shadow_shadowmaplod];
2176 r_shadow_shadowmap_texturescale[0] = 0.0f;
2177 r_shadow_shadowmap_texturescale[1] = 0.0f;
2178 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE;
2181 R_Shadow_RenderMode_Reset();
2184 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);CHECKGLERROR
2185 R_SetupShader_DepthOrShadow();
2189 R_SetupShader_ShowDepth();
2190 qglClearColor(1,1,1,1);CHECKGLERROR
2193 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
2200 R_SetViewport(&viewport);
2201 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2202 if(r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE)
2204 int flipped = (side&1)^(side>>2);
2205 r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
2206 r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
2207 GL_CullFace(r_refdef.view.cullface_back);
2209 else if(r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE)
2211 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + side, R_GetTexture(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]), 0);CHECKGLERROR
2214 qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
2218 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
2222 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2223 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2224 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2225 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2228 R_Shadow_RenderMode_Reset();
2229 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2232 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2236 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2237 // only draw light where this geometry was already rendered AND the
2238 // stencil is 128 (values other than this mean shadow)
2239 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
2241 r_shadow_rendermode = r_shadow_lightingrendermode;
2242 // do global setup needed for the chosen lighting mode
2243 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2245 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2250 if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
2251 r_shadow_usingshadowmap2d = true;
2252 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE)
2253 r_shadow_usingshadowmaprect = true;
2254 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
2255 r_shadow_usingshadowmapcube = true;
2257 R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
2261 static const unsigned short bboxelements[36] =
2271 static const float bboxpoints[8][3] =
2283 void R_Shadow_RenderMode_DrawDeferredLight(qboolean stenciltest, qboolean shadowmapping)
2286 float vertex3f[8*3];
2287 const matrix4x4_t *matrix = &rsurface.rtlight->matrix_lighttoworld;
2289 R_Shadow_RenderMode_Reset();
2290 r_shadow_rendermode = r_shadow_lightingrendermode;
2291 // do global setup needed for the chosen lighting mode
2293 R_EntityMatrix(&identitymatrix);
2294 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2297 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2298 // only draw light where this geometry was already rendered AND the
2299 // stencil is 128 (values other than this mean shadow)
2300 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
2302 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepasslightingfbo);CHECKGLERROR
2305 if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
2306 r_shadow_usingshadowmap2d = true;
2307 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE)
2308 r_shadow_usingshadowmaprect = true;
2309 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
2310 r_shadow_usingshadowmapcube = true;
2313 // render the lighting
2314 R_SetupShader_DeferredLight(rsurface.rtlight);
2315 for (i = 0;i < 8;i++)
2316 Matrix4x4_Transform(matrix, bboxpoints[i], vertex3f + i*3);
2318 R_Mesh_VertexPointer(vertex3f, 0, 0);
2319 R_Mesh_ColorPointer(NULL, 0, 0);
2320 GL_ColorMask(1,1,1,1);
2321 GL_DepthMask(false);
2322 GL_DepthRange(0, 1);
2323 GL_PolygonOffset(0, 0);
2325 qglDepthFunc(GL_GREATER);CHECKGLERROR
2326 GL_CullFace(r_refdef.view.cullface_back);
2327 R_Mesh_Draw(0, 8, 0, 12, NULL, bboxelements, 0, 0);
2331 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
2334 R_Shadow_RenderMode_Reset();
2335 GL_BlendFunc(GL_ONE, GL_ONE);
2336 GL_DepthRange(0, 1);
2337 GL_DepthTest(r_showshadowvolumes.integer < 2);
2338 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
2339 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2340 GL_CullFace(GL_NONE);
2341 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
2344 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
2347 R_Shadow_RenderMode_Reset();
2348 GL_BlendFunc(GL_ONE, GL_ONE);
2349 GL_DepthRange(0, 1);
2350 GL_DepthTest(r_showlighting.integer < 2);
2351 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2354 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2358 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2359 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
2361 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2364 void R_Shadow_RenderMode_End(void)
2367 R_Shadow_RenderMode_Reset();
2368 R_Shadow_RenderMode_ActiveLight(NULL);
2370 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2371 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2374 int bboxedges[12][2] =
2393 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2395 int i, ix1, iy1, ix2, iy2;
2396 float x1, y1, x2, y2;
2398 float vertex[20][3];
2407 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2408 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2409 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2410 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2412 if (!r_shadow_scissor.integer)
2415 // if view is inside the light box, just say yes it's visible
2416 if (BoxesOverlap(r_refdef.view.origin, r_refdef.view.origin, mins, maxs))
2419 x1 = y1 = x2 = y2 = 0;
2421 // transform all corners that are infront of the nearclip plane
2422 VectorNegate(r_refdef.view.frustum[4].normal, plane4f);
2423 plane4f[3] = r_refdef.view.frustum[4].dist;
2425 for (i = 0;i < 8;i++)
2427 Vector4Set(corner[i], (i & 1) ? maxs[0] : mins[0], (i & 2) ? maxs[1] : mins[1], (i & 4) ? maxs[2] : mins[2], 1);
2428 dist[i] = DotProduct4(corner[i], plane4f);
2429 sign[i] = dist[i] > 0;
2432 VectorCopy(corner[i], vertex[numvertices]);
2436 // if some points are behind the nearclip, add clipped edge points to make
2437 // sure that the scissor boundary is complete
2438 if (numvertices > 0 && numvertices < 8)
2440 // add clipped edge points
2441 for (i = 0;i < 12;i++)
2443 j = bboxedges[i][0];
2444 k = bboxedges[i][1];
2445 if (sign[j] != sign[k])
2447 f = dist[j] / (dist[j] - dist[k]);
2448 VectorLerp(corner[j], f, corner[k], vertex[numvertices]);
2454 // if we have no points to check, the light is behind the view plane
2458 // if we have some points to transform, check what screen area is covered
2459 x1 = y1 = x2 = y2 = 0;
2461 //Con_Printf("%i vertices to transform...\n", numvertices);
2462 for (i = 0;i < numvertices;i++)
2464 VectorCopy(vertex[i], v);
2465 R_Viewport_TransformToScreen(&r_refdef.view.viewport, v, v2);
2466 //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]);
2469 if (x1 > v2[0]) x1 = v2[0];
2470 if (x2 < v2[0]) x2 = v2[0];
2471 if (y1 > v2[1]) y1 = v2[1];
2472 if (y2 < v2[1]) y2 = v2[1];
2481 // now convert the scissor rectangle to integer screen coordinates
2482 ix1 = (int)(x1 - 1.0f);
2483 iy1 = vid.height - (int)(y2 - 1.0f);
2484 ix2 = (int)(x2 + 1.0f);
2485 iy2 = vid.height - (int)(y1 + 1.0f);
2486 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
2488 // clamp it to the screen
2489 if (ix1 < r_refdef.view.viewport.x) ix1 = r_refdef.view.viewport.x;
2490 if (iy1 < r_refdef.view.viewport.y) iy1 = r_refdef.view.viewport.y;
2491 if (ix2 > r_refdef.view.viewport.x + r_refdef.view.viewport.width) ix2 = r_refdef.view.viewport.x + r_refdef.view.viewport.width;
2492 if (iy2 > r_refdef.view.viewport.y + r_refdef.view.viewport.height) iy2 = r_refdef.view.viewport.y + r_refdef.view.viewport.height;
2494 // if it is inside out, it's not visible
2495 if (ix2 <= ix1 || iy2 <= iy1)
2498 // the light area is visible, set up the scissor rectangle
2499 r_shadow_lightscissor[0] = ix1;
2500 r_shadow_lightscissor[1] = iy1;
2501 r_shadow_lightscissor[2] = ix2 - ix1;
2502 r_shadow_lightscissor[3] = iy2 - iy1;
2504 r_refdef.stats.lights_scissored++;
2508 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, int numtriangles, const int *element3i, const float *diffusecolor, const float *ambientcolor)
2510 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
2511 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
2512 float *color4f = rsurface.array_color4f + 4 * firstvertex;
2513 float dist, dot, distintensity, shadeintensity, v[3], n[3];
2514 switch (r_shadow_rendermode)
2516 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2517 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2518 if (VectorLength2(diffusecolor) > 0)
2520 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2522 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2523 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2524 if ((dot = DotProduct(n, v)) < 0)
2526 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2527 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
2530 VectorCopy(ambientcolor, color4f);
2531 if (r_refdef.fogenabled)
2534 f = RSurf_FogVertex(vertex3f);
2535 VectorScale(color4f, f, color4f);
2542 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2544 VectorCopy(ambientcolor, color4f);
2545 if (r_refdef.fogenabled)
2548 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2549 f = RSurf_FogVertex(vertex3f);
2550 VectorScale(color4f, f, color4f);
2556 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2557 if (VectorLength2(diffusecolor) > 0)
2559 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2561 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2562 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2564 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2565 if ((dot = DotProduct(n, v)) < 0)
2567 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2568 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2569 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2570 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2574 color4f[0] = ambientcolor[0] * distintensity;
2575 color4f[1] = ambientcolor[1] * distintensity;
2576 color4f[2] = ambientcolor[2] * distintensity;
2578 if (r_refdef.fogenabled)
2581 f = RSurf_FogVertex(vertex3f);
2582 VectorScale(color4f, f, color4f);
2586 VectorClear(color4f);
2592 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2594 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2595 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2597 color4f[0] = ambientcolor[0] * distintensity;
2598 color4f[1] = ambientcolor[1] * distintensity;
2599 color4f[2] = ambientcolor[2] * distintensity;
2600 if (r_refdef.fogenabled)
2603 f = RSurf_FogVertex(vertex3f);
2604 VectorScale(color4f, f, color4f);
2608 VectorClear(color4f);
2613 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2614 if (VectorLength2(diffusecolor) > 0)
2616 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2618 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2619 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2621 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2622 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2623 if ((dot = DotProduct(n, v)) < 0)
2625 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2626 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2627 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2628 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2632 color4f[0] = ambientcolor[0] * distintensity;
2633 color4f[1] = ambientcolor[1] * distintensity;
2634 color4f[2] = ambientcolor[2] * distintensity;
2636 if (r_refdef.fogenabled)
2639 f = RSurf_FogVertex(vertex3f);
2640 VectorScale(color4f, f, color4f);
2644 VectorClear(color4f);
2650 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2652 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2653 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2655 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2656 color4f[0] = ambientcolor[0] * distintensity;
2657 color4f[1] = ambientcolor[1] * distintensity;
2658 color4f[2] = ambientcolor[2] * distintensity;
2659 if (r_refdef.fogenabled)
2662 f = RSurf_FogVertex(vertex3f);
2663 VectorScale(color4f, f, color4f);
2667 VectorClear(color4f);
2677 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)
2679 // used to display how many times a surface is lit for level design purposes
2680 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2683 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)
2685 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2686 R_SetupShader_Surface(lightcolor, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT);
2687 if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND))
2688 R_Mesh_ColorPointer(rsurface.modellightmapcolor4f, rsurface.modellightmapcolor4f_bufferobject, rsurface.modellightmapcolor4f_bufferoffset);
2690 R_Mesh_ColorPointer(NULL, 0, 0);
2691 R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
2692 R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset);
2693 R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset);
2694 R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset);
2695 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2697 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2699 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2700 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2702 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
2706 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
2713 int newnumtriangles;
2717 int maxtriangles = 4096;
2718 static int newelements[4096*3];
2719 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, numtriangles, element3i, diffusecolor2, ambientcolor2);
2720 for (renders = 0;renders < 64;renders++)
2725 newnumtriangles = 0;
2727 // due to low fillrate on the cards this vertex lighting path is
2728 // designed for, we manually cull all triangles that do not
2729 // contain a lit vertex
2730 // this builds batches of triangles from multiple surfaces and
2731 // renders them at once
2732 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
2734 if (VectorLength2(rsurface.array_color4f + e[0] * 4) + VectorLength2(rsurface.array_color4f + e[1] * 4) + VectorLength2(rsurface.array_color4f + e[2] * 4) >= 0.01)
2736 if (newnumtriangles)
2738 newfirstvertex = min(newfirstvertex, e[0]);
2739 newlastvertex = max(newlastvertex, e[0]);
2743 newfirstvertex = e[0];
2744 newlastvertex = e[0];
2746 newfirstvertex = min(newfirstvertex, e[1]);
2747 newlastvertex = max(newlastvertex, e[1]);
2748 newfirstvertex = min(newfirstvertex, e[2]);
2749 newlastvertex = max(newlastvertex, e[2]);
2755 if (newnumtriangles >= maxtriangles)
2757 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
2758 newnumtriangles = 0;
2764 if (newnumtriangles >= 1)
2766 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
2769 // if we couldn't find any lit triangles, exit early
2772 // now reduce the intensity for the next overbright pass
2773 // we have to clamp to 0 here incase the drivers have improper
2774 // handling of negative colors
2775 // (some old drivers even have improper handling of >1 color)
2777 for (i = 0, c = rsurface.array_color4f + 4 * firstvertex;i < numvertices;i++, c += 4)
2779 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
2781 c[0] = max(0, c[0] - 1);
2782 c[1] = max(0, c[1] - 1);
2783 c[2] = max(0, c[2] - 1);
2795 static void R_Shadow_RenderLighting_Light_Vertex(int firstvertex, int numvertices, int numtriangles, const int *element3i, const vec3_t lightcolor, float ambientscale, float diffusescale)
2797 // OpenGL 1.1 path (anything)
2798 float ambientcolorbase[3], diffusecolorbase[3];
2799 float ambientcolorpants[3], diffusecolorpants[3];
2800 float ambientcolorshirt[3], diffusecolorshirt[3];
2801 const float *surfacecolor = rsurface.texture->dlightcolor;
2802 const float *surfacepants = rsurface.colormap_pantscolor;
2803 const float *surfaceshirt = rsurface.colormap_shirtcolor;
2804 rtexture_t *basetexture = rsurface.texture->basetexture;
2805 rtexture_t *pantstexture = rsurface.texture->pantstexture;
2806 rtexture_t *shirttexture = rsurface.texture->shirttexture;
2807 qboolean dopants = pantstexture && VectorLength2(surfacepants) >= (1.0f / 1048576.0f);
2808 qboolean doshirt = shirttexture && VectorLength2(surfaceshirt) >= (1.0f / 1048576.0f);
2809 ambientscale *= 2 * r_refdef.view.colorscale;
2810 diffusescale *= 2 * r_refdef.view.colorscale;
2811 ambientcolorbase[0] = lightcolor[0] * ambientscale * surfacecolor[0];ambientcolorbase[1] = lightcolor[1] * ambientscale * surfacecolor[1];ambientcolorbase[2] = lightcolor[2] * ambientscale * surfacecolor[2];
2812 diffusecolorbase[0] = lightcolor[0] * diffusescale * surfacecolor[0];diffusecolorbase[1] = lightcolor[1] * diffusescale * surfacecolor[1];diffusecolorbase[2] = lightcolor[2] * diffusescale * surfacecolor[2];
2813 ambientcolorpants[0] = ambientcolorbase[0] * surfacepants[0];ambientcolorpants[1] = ambientcolorbase[1] * surfacepants[1];ambientcolorpants[2] = ambientcolorbase[2] * surfacepants[2];
2814 diffusecolorpants[0] = diffusecolorbase[0] * surfacepants[0];diffusecolorpants[1] = diffusecolorbase[1] * surfacepants[1];diffusecolorpants[2] = diffusecolorbase[2] * surfacepants[2];
2815 ambientcolorshirt[0] = ambientcolorbase[0] * surfaceshirt[0];ambientcolorshirt[1] = ambientcolorbase[1] * surfaceshirt[1];ambientcolorshirt[2] = ambientcolorbase[2] * surfaceshirt[2];
2816 diffusecolorshirt[0] = diffusecolorbase[0] * surfaceshirt[0];diffusecolorshirt[1] = diffusecolorbase[1] * surfaceshirt[1];diffusecolorshirt[2] = diffusecolorbase[2] * surfaceshirt[2];
2817 R_Mesh_TexBind(0, R_GetTexture(basetexture));
2818 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
2819 R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
2820 R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
2821 switch(r_shadow_rendermode)
2823 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2824 R_Mesh_TexBindAll(1, 0, R_GetTexture(r_shadow_attenuation3dtexture), 0, 0);
2825 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
2826 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
2827 R_Mesh_TexCoordPointer(1, 3, rsurface.vertex3f, rsurface.vertex3f_bufferobject, rsurface.vertex3f_bufferoffset);
2829 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2830 R_Mesh_TexBind(2, R_GetTexture(r_shadow_attenuation2dtexture));
2831 R_Mesh_TexMatrix(2, &rsurface.entitytoattenuationz);
2832 R_Mesh_TexCombine(2, GL_MODULATE, GL_MODULATE, 1, 1);
2833 R_Mesh_TexCoordPointer(2, 3, rsurface.vertex3f, rsurface.vertex3f_bufferobject, rsurface.vertex3f_bufferoffset);
2835 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2836 R_Mesh_TexBind(1, R_GetTexture(r_shadow_attenuation2dtexture));
2837 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
2838 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
2839 R_Mesh_TexCoordPointer(1, 3, rsurface.vertex3f, rsurface.vertex3f_bufferobject, rsurface.vertex3f_bufferoffset);
2841 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2846 //R_Mesh_TexBind(0, R_GetTexture(basetexture));
2847 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorbase, ambientcolorbase);
2850 R_Mesh_TexBind(0, R_GetTexture(pantstexture));
2851 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorpants, ambientcolorpants);
2855 R_Mesh_TexBind(0, R_GetTexture(shirttexture));
2856 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorshirt, ambientcolorshirt);
2860 extern cvar_t gl_lightmaps;
2861 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)
2863 float ambientscale, diffusescale, specularscale;
2865 float lightcolor[3];
2866 VectorCopy(rsurface.rtlight->currentcolor, lightcolor);
2867 ambientscale = rsurface.rtlight->ambientscale;
2868 diffusescale = rsurface.rtlight->diffusescale;
2869 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
2870 if (!r_shadow_usenormalmap.integer)
2872 ambientscale += 1.0f * diffusescale;
2876 if ((ambientscale + diffusescale) * VectorLength2(lightcolor) + specularscale * VectorLength2(lightcolor) < (1.0f / 1048576.0f))
2878 negated = (lightcolor[0] + lightcolor[1] + lightcolor[2] < 0) && vid.support.ext_blend_subtract;
2881 VectorNegate(lightcolor, lightcolor);
2882 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
2884 RSurf_SetupDepthAndCulling();
2885 switch (r_shadow_rendermode)
2887 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2888 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2889 R_Shadow_RenderLighting_VisibleLighting(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2891 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2892 R_Shadow_RenderLighting_Light_GLSL(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolor, ambientscale, diffusescale, specularscale);
2894 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2895 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2896 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2897 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2898 R_Shadow_RenderLighting_Light_Vertex(firstvertex, numvertices, numtriangles, element3i + firsttriangle * 3, lightcolor, ambientscale, diffusescale);
2901 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2905 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
2908 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)
2910 matrix4x4_t tempmatrix = *matrix;
2911 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
2913 // if this light has been compiled before, free the associated data
2914 R_RTLight_Uncompile(rtlight);
2916 // clear it completely to avoid any lingering data
2917 memset(rtlight, 0, sizeof(*rtlight));
2919 // copy the properties
2920 rtlight->matrix_lighttoworld = tempmatrix;
2921 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
2922 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
2923 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
2924 VectorCopy(color, rtlight->color);
2925 rtlight->cubemapname[0] = 0;
2926 if (cubemapname && cubemapname[0])
2927 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
2928 rtlight->shadow = shadow;
2929 rtlight->corona = corona;
2930 rtlight->style = style;
2931 rtlight->isstatic = isstatic;
2932 rtlight->coronasizescale = coronasizescale;
2933 rtlight->ambientscale = ambientscale;
2934 rtlight->diffusescale = diffusescale;
2935 rtlight->specularscale = specularscale;
2936 rtlight->flags = flags;
2938 // compute derived data
2939 //rtlight->cullradius = rtlight->radius;
2940 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2941 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2942 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2943 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2944 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2945 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2946 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2949 // compiles rtlight geometry
2950 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2951 void R_RTLight_Compile(rtlight_t *rtlight)
2954 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
2955 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
2956 entity_render_t *ent = r_refdef.scene.worldentity;
2957 dp_model_t *model = r_refdef.scene.worldmodel;
2958 unsigned char *data;
2961 // compile the light
2962 rtlight->compiled = true;
2963 rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
2964 rtlight->static_numleafs = 0;
2965 rtlight->static_numleafpvsbytes = 0;
2966 rtlight->static_leaflist = NULL;
2967 rtlight->static_leafpvs = NULL;
2968 rtlight->static_numsurfaces = 0;
2969 rtlight->static_surfacelist = NULL;
2970 rtlight->static_shadowmap_receivers = 0x3F;
2971 rtlight->static_shadowmap_casters = 0x3F;
2972 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2973 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2974 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2975 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2976 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2977 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2979 if (model && model->GetLightInfo)
2981 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
2982 r_shadow_compilingrtlight = rtlight;
2983 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);
2984 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2985 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
2986 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
2987 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
2988 rtlight->static_numsurfaces = numsurfaces;
2989 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
2990 rtlight->static_numleafs = numleafs;
2991 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
2992 rtlight->static_numleafpvsbytes = numleafpvsbytes;
2993 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
2994 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
2995 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
2996 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
2997 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
2998 if (rtlight->static_numsurfaces)
2999 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3000 if (rtlight->static_numleafs)
3001 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3002 if (rtlight->static_numleafpvsbytes)
3003 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3004 if (rtlight->static_numshadowtrispvsbytes)
3005 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3006 if (rtlight->static_numlighttrispvsbytes)
3007 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3008 switch (rtlight->shadowmode)
3010 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
3011 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
3012 case R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE:
3013 if (model->CompileShadowMap && rtlight->shadow)
3014 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3017 if (model->CompileShadowVolume && rtlight->shadow)
3018 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3021 // now we're done compiling the rtlight
3022 r_shadow_compilingrtlight = NULL;
3026 // use smallest available cullradius - box radius or light radius
3027 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3028 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3030 shadowzpasstris = 0;
3031 if (rtlight->static_meshchain_shadow_zpass)
3032 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
3033 shadowzpasstris += mesh->numtriangles;
3035 shadowzfailtris = 0;
3036 if (rtlight->static_meshchain_shadow_zfail)
3037 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
3038 shadowzfailtris += mesh->numtriangles;
3041 if (rtlight->static_numlighttrispvsbytes)
3042 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3043 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3047 if (rtlight->static_numlighttrispvsbytes)
3048 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3049 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3052 if (developer.integer >= 10)
3053 Con_Printf("static light built: %f %f %f : %f %f %f box, %i light triangles, %i shadow triangles, %i zpass/%i zfail compiled shadow volume triangles\n", rtlight->cullmins[0], rtlight->cullmins[1], rtlight->cullmins[2], rtlight->cullmaxs[0], rtlight->cullmaxs[1], rtlight->cullmaxs[2], lighttris, shadowtris, shadowzpasstris, shadowzfailtris);
3056 void R_RTLight_Uncompile(rtlight_t *rtlight)
3058 if (rtlight->compiled)
3060 if (rtlight->static_meshchain_shadow_zpass)
3061 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
3062 rtlight->static_meshchain_shadow_zpass = NULL;
3063 if (rtlight->static_meshchain_shadow_zfail)
3064 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
3065 rtlight->static_meshchain_shadow_zfail = NULL;
3066 if (rtlight->static_meshchain_shadow_shadowmap)
3067 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
3068 rtlight->static_meshchain_shadow_shadowmap = NULL;
3069 // these allocations are grouped
3070 if (rtlight->static_surfacelist)
3071 Mem_Free(rtlight->static_surfacelist);
3072 rtlight->static_numleafs = 0;
3073 rtlight->static_numleafpvsbytes = 0;
3074 rtlight->static_leaflist = NULL;
3075 rtlight->static_leafpvs = NULL;
3076 rtlight->static_numsurfaces = 0;
3077 rtlight->static_surfacelist = NULL;
3078 rtlight->static_numshadowtrispvsbytes = 0;
3079 rtlight->static_shadowtrispvs = NULL;
3080 rtlight->static_numlighttrispvsbytes = 0;
3081 rtlight->static_lighttrispvs = NULL;
3082 rtlight->compiled = false;
3086 void R_Shadow_UncompileWorldLights(void)
3090 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3091 for (lightindex = 0;lightindex < range;lightindex++)
3093 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3096 R_RTLight_Uncompile(&light->rtlight);
3100 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3104 // reset the count of frustum planes
3105 // see rtlight->cached_frustumplanes definition for how much this array
3107 rtlight->cached_numfrustumplanes = 0;
3109 // haven't implemented a culling path for ortho rendering
3110 if (!r_refdef.view.useperspective)
3112 // check if the light is on screen and copy the 4 planes if it is
3113 for (i = 0;i < 4;i++)
3114 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3117 for (i = 0;i < 4;i++)
3118 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3123 // generate a deformed frustum that includes the light origin, this is
3124 // used to cull shadow casting surfaces that can not possibly cast a
3125 // shadow onto the visible light-receiving surfaces, which can be a
3128 // if the light origin is onscreen the result will be 4 planes exactly
3129 // if the light origin is offscreen on only one axis the result will
3130 // be exactly 5 planes (split-side case)
3131 // if the light origin is offscreen on two axes the result will be
3132 // exactly 4 planes (stretched corner case)
3133 for (i = 0;i < 4;i++)
3135 // quickly reject standard frustum planes that put the light
3136 // origin outside the frustum
3137 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3140 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3142 // if all the standard frustum planes were accepted, the light is onscreen
3143 // otherwise we need to generate some more planes below...
3144 if (rtlight->cached_numfrustumplanes < 4)
3146 // at least one of the stock frustum planes failed, so we need to
3147 // create one or two custom planes to enclose the light origin
3148 for (i = 0;i < 4;i++)
3150 // create a plane using the view origin and light origin, and a
3151 // single point from the frustum corner set
3152 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3153 VectorNormalize(plane.normal);
3154 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3155 // see if this plane is backwards and flip it if so
3156 for (j = 0;j < 4;j++)
3157 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3161 VectorNegate(plane.normal, plane.normal);
3163 // flipped plane, test again to see if it is now valid
3164 for (j = 0;j < 4;j++)
3165 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3167 // if the plane is still not valid, then it is dividing the
3168 // frustum and has to be rejected
3172 // we have created a valid plane, compute extra info
3173 PlaneClassify(&plane);
3175 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3177 // if we've found 5 frustum planes then we have constructed a
3178 // proper split-side case and do not need to keep searching for
3179 // planes to enclose the light origin
3180 if (rtlight->cached_numfrustumplanes == 5)
3188 for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
3190 plane = rtlight->cached_frustumplanes[i];
3191 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));
3196 // now add the light-space box planes if the light box is rotated, as any
3197 // caster outside the oriented light box is irrelevant (even if it passed
3198 // the worldspace light box, which is axial)
3199 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3201 for (i = 0;i < 6;i++)
3205 v[i >> 1] = (i & 1) ? -1 : 1;
3206 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3207 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3208 plane.dist = VectorNormalizeLength(plane.normal);
3209 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3210 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3216 // add the world-space reduced box planes
3217 for (i = 0;i < 6;i++)
3219 VectorClear(plane.normal);
3220 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3221 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
3222 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3231 // reduce all plane distances to tightly fit the rtlight cull box, which
3233 VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3234 VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3235 VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3236 VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3237 VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3238 VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3239 VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3240 VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3241 oldnum = rtlight->cached_numfrustumplanes;
3242 rtlight->cached_numfrustumplanes = 0;
3243 for (j = 0;j < oldnum;j++)
3245 // find the nearest point on the box to this plane
3246 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
3247 for (i = 1;i < 8;i++)
3249 dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
3250 if (bestdist > dist)
3253 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);
3254 // if the nearest point is near or behind the plane, we want this
3255 // plane, otherwise the plane is useless as it won't cull anything
3256 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
3258 PlaneClassify(&rtlight->cached_frustumplanes[j]);
3259 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
3266 void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
3270 RSurf_ActiveWorldEntity();
3272 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3275 GL_CullFace(GL_NONE);
3276 mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3277 for (;mesh;mesh = mesh->next)
3279 if (!mesh->sidetotals[r_shadow_shadowmapside])
3281 r_refdef.stats.lights_shadowtriangles += mesh->sidetotals[r_shadow_shadowmapside];
3282 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
3283 R_Mesh_Draw(0, mesh->numverts, mesh->sideoffsets[r_shadow_shadowmapside], mesh->sidetotals[r_shadow_shadowmapside], mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3287 else if (r_refdef.scene.worldentity->model)
3288 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);
3290 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3293 void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3295 qboolean zpass = false;
3298 int surfacelistindex;
3299 msurface_t *surface;
3301 RSurf_ActiveWorldEntity();
3303 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3306 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
3308 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
3309 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
3311 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
3312 for (;mesh;mesh = mesh->next)
3314 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
3315 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
3316 GL_LockArrays(0, mesh->numverts);
3317 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
3319 // increment stencil if frontface is infront of depthbuffer
3320 GL_CullFace(r_refdef.view.cullface_back);
3321 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
3322 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3323 // decrement stencil if backface is infront of depthbuffer
3324 GL_CullFace(r_refdef.view.cullface_front);
3325 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
3327 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
3329 // decrement stencil if backface is behind depthbuffer
3330 GL_CullFace(r_refdef.view.cullface_front);
3331 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
3332 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3333 // increment stencil if frontface is behind depthbuffer
3334 GL_CullFace(r_refdef.view.cullface_back);
3335 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
3337 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3338 GL_LockArrays(0, 0);
3342 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh)
3344 // use the shadow trispvs calculated earlier by GetLightInfo to cull world triangles on this dynamic light
3345 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
3346 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
3348 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
3349 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
3350 if (CHECKPVSBIT(trispvs, t))
3351 shadowmarklist[numshadowmark++] = t;
3353 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);
3355 else if (numsurfaces)
3356 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);
3358 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3361 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3363 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3364 vec_t relativeshadowradius;
3365 RSurf_ActiveModelEntity(ent, false, false, false);
3366 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3367 // we need to re-init the shader for each entity because the matrix changed
3368 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3369 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3370 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3371 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3372 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3373 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3374 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3375 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D)
3377 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
3380 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3381 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3384 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3386 // set up properties for rendering light onto this entity
3387 RSurf_ActiveModelEntity(ent, true, true, false);
3388 GL_AlphaTest(false);
3389 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3390 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3391 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3392 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3395 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3397 if (!r_refdef.scene.worldmodel->DrawLight)
3400 // set up properties for rendering light onto this entity
3401 RSurf_ActiveWorldEntity();
3402 GL_AlphaTest(false);
3403 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3404 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3405 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3406 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3408 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, trispvs);
3410 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3413 void R_Shadow_DrawEntityLight(entity_render_t *ent)
3415 dp_model_t *model = ent->model;
3416 if (!model->DrawLight)
3419 R_Shadow_SetupEntityLight(ent);
3421 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3423 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3426 void R_Shadow_PrepareLight(rtlight_t *rtlight)
3430 int numleafs, numsurfaces;
3431 int *leaflist, *surfacelist;
3432 unsigned char *leafpvs, *shadowtrispvs, *lighttrispvs, *surfacesides;
3433 int numlightentities;
3434 int numlightentities_noselfshadow;
3435 int numshadowentities;
3436 int numshadowentities_noselfshadow;
3437 static entity_render_t *lightentities[MAX_EDICTS];
3438 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3439 static entity_render_t *shadowentities[MAX_EDICTS];
3440 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3442 rtlight->draw = false;
3444 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3445 // skip lights that are basically invisible (color 0 0 0)
3446 if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
3449 // loading is done before visibility checks because loading should happen
3450 // all at once at the start of a level, not when it stalls gameplay.
3451 // (especially important to benchmarks)
3453 if (rtlight->isstatic && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
3455 if (rtlight->compiled)
3456 R_RTLight_Uncompile(rtlight);
3457 R_RTLight_Compile(rtlight);
3461 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
3463 // look up the light style value at this time
3464 f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3465 VectorScale(rtlight->color, f, rtlight->currentcolor);
3467 if (rtlight->selected)
3469 f = 2 + sin(realtime * M_PI * 4.0);
3470 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3474 // if lightstyle is currently off, don't draw the light
3475 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3478 // if the light box is offscreen, skip it
3479 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3482 VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
3483 VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
3485 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3487 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3489 // compiled light, world available and can receive realtime lighting
3490 // retrieve leaf information
3491 numleafs = rtlight->static_numleafs;
3492 leaflist = rtlight->static_leaflist;
3493 leafpvs = rtlight->static_leafpvs;
3494 numsurfaces = rtlight->static_numsurfaces;
3495 surfacelist = rtlight->static_surfacelist;
3496 surfacesides = NULL;
3497 shadowtrispvs = rtlight->static_shadowtrispvs;
3498 lighttrispvs = rtlight->static_lighttrispvs;
3500 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3502 // dynamic light, world available and can receive realtime lighting
3503 // calculate lit surfaces and leafs
3504 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);
3505 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3506 leaflist = r_shadow_buffer_leaflist;
3507 leafpvs = r_shadow_buffer_leafpvs;
3508 surfacelist = r_shadow_buffer_surfacelist;
3509 surfacesides = r_shadow_buffer_surfacesides;
3510 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3511 lighttrispvs = r_shadow_buffer_lighttrispvs;
3512 // if the reduced leaf bounds are offscreen, skip it
3513 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3524 surfacesides = NULL;
3525 shadowtrispvs = NULL;
3526 lighttrispvs = NULL;
3528 // check if light is illuminating any visible leafs
3531 for (i = 0;i < numleafs;i++)
3532 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3538 // make a list of lit entities and shadow casting entities
3539 numlightentities = 0;
3540 numlightentities_noselfshadow = 0;
3541 numshadowentities = 0;
3542 numshadowentities_noselfshadow = 0;
3544 // add dynamic entities that are lit by the light
3545 for (i = 0;i < r_refdef.scene.numentities;i++)
3548 entity_render_t *ent = r_refdef.scene.entities[i];
3550 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3552 // skip the object entirely if it is not within the valid
3553 // shadow-casting region (which includes the lit region)
3554 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
3556 if (!(model = ent->model))
3558 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
3560 // this entity wants to receive light, is visible, and is
3561 // inside the light box
3562 // TODO: check if the surfaces in the model can receive light
3563 // so now check if it's in a leaf seen by the light
3564 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))
3566 if (ent->flags & RENDER_NOSELFSHADOW)
3567 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
3569 lightentities[numlightentities++] = ent;
3570 // since it is lit, it probably also casts a shadow...
3571 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3572 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3573 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3575 // note: exterior models without the RENDER_NOSELFSHADOW
3576 // flag still create a RENDER_NOSELFSHADOW shadow but
3577 // are lit normally, this means that they are
3578 // self-shadowing but do not shadow other
3579 // RENDER_NOSELFSHADOW entities such as the gun
3580 // (very weird, but keeps the player shadow off the gun)
3581 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3582 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3584 shadowentities[numshadowentities++] = ent;
3587 else if (ent->flags & RENDER_SHADOW)
3589 // this entity is not receiving light, but may still need to
3591 // TODO: check if the surfaces in the model can cast shadow
3592 // now check if it is in a leaf seen by the light
3593 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))
3595 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3596 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3597 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3599 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3600 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3602 shadowentities[numshadowentities++] = ent;
3607 // return if there's nothing at all to light
3608 if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
3611 // count this light in the r_speeds
3612 r_refdef.stats.lights++;
3614 // flag it as worth drawing later
3615 rtlight->draw = true;
3617 // cache all the animated entities that cast a shadow but are not visible
3618 for (i = 0;i < numshadowentities;i++)
3619 if (!shadowentities[i]->animcache_vertex3f)
3620 R_AnimCache_GetEntity(shadowentities[i], false, false);
3621 for (i = 0;i < numshadowentities_noselfshadow;i++)
3622 if (!shadowentities_noselfshadow[i]->animcache_vertex3f)
3623 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
3625 // allocate some temporary memory for rendering this light later in the frame
3626 // reusable buffers need to be copied, static data can be used as-is
3627 rtlight->cached_numlightentities = numlightentities;
3628 rtlight->cached_numlightentities_noselfshadow = numlightentities_noselfshadow;
3629 rtlight->cached_numshadowentities = numshadowentities;
3630 rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
3631 rtlight->cached_numsurfaces = numsurfaces;
3632 rtlight->cached_lightentities = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
3633 rtlight->cached_lightentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
3634 rtlight->cached_shadowentities = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
3635 rtlight->cached_shadowentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
3636 if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
3638 int numshadowtrispvsbytes = (((r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles) + 7) >> 3);
3639 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
3640 rtlight->cached_shadowtrispvs = (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
3641 rtlight->cached_lighttrispvs = (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
3642 rtlight->cached_surfacelist = (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
3646 // compiled light data
3647 rtlight->cached_shadowtrispvs = shadowtrispvs;
3648 rtlight->cached_lighttrispvs = lighttrispvs;
3649 rtlight->cached_surfacelist = surfacelist;
3653 void R_Shadow_DrawLight(rtlight_t *rtlight)
3657 unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
3658 int numlightentities;
3659 int numlightentities_noselfshadow;
3660 int numshadowentities;
3661 int numshadowentities_noselfshadow;
3662 entity_render_t **lightentities;
3663 entity_render_t **lightentities_noselfshadow;
3664 entity_render_t **shadowentities;
3665 entity_render_t **shadowentities_noselfshadow;
3667 static unsigned char entitysides[MAX_EDICTS];
3668 static unsigned char entitysides_noselfshadow[MAX_EDICTS];
3669 vec3_t nearestpoint;
3671 qboolean castshadows;
3674 // check if we cached this light this frame (meaning it is worth drawing)
3678 // if R_FrameData_Store ran out of space we skip anything dependent on it
3679 if (r_framedata_failed)
3682 numlightentities = rtlight->cached_numlightentities;
3683 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
3684 numshadowentities = rtlight->cached_numshadowentities;
3685 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
3686 numsurfaces = rtlight->cached_numsurfaces;
3687 lightentities = rtlight->cached_lightentities;
3688 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
3689 shadowentities = rtlight->cached_shadowentities;
3690 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
3691 shadowtrispvs = rtlight->cached_shadowtrispvs;
3692 lighttrispvs = rtlight->cached_lighttrispvs;
3693 surfacelist = rtlight->cached_surfacelist;
3695 // set up a scissor rectangle for this light
3696 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3699 // don't let sound skip if going slow
3700 if (r_refdef.scene.extraupdate)
3703 // make this the active rtlight for rendering purposes
3704 R_Shadow_RenderMode_ActiveLight(rtlight);
3706 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
3708 // optionally draw visible shape of the shadow volumes
3709 // for performance analysis by level designers
3710 R_Shadow_RenderMode_VisibleShadowVolumes();
3712 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
3713 for (i = 0;i < numshadowentities;i++)
3714 R_Shadow_DrawEntityShadow(shadowentities[i]);
3715 for (i = 0;i < numshadowentities_noselfshadow;i++)
3716 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3717 R_Shadow_RenderMode_VisibleLighting(false, false);
3720 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
3722 // optionally draw the illuminated areas
3723 // for performance analysis by level designers
3724 R_Shadow_RenderMode_VisibleLighting(false, false);
3726 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3727 for (i = 0;i < numlightentities;i++)
3728 R_Shadow_DrawEntityLight(lightentities[i]);
3729 for (i = 0;i < numlightentities_noselfshadow;i++)
3730 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3733 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
3735 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
3736 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
3737 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
3738 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
3740 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance/rtlight->radius));
3741 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
3742 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
3744 if (castshadows && (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE))
3750 int receivermask = 0;
3751 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
3752 Matrix4x4_Abs(&radiustolight);
3754 r_shadow_shadowmaplod = 0;
3755 for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
3756 if ((r_shadow_shadowmapmaxsize >> i) > lodlinear)
3757 r_shadow_shadowmaplod = i;
3759 if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
3760 size = max(1, r_shadow_shadowmapmaxsize >> r_shadow_shadowmaplod);
3762 size = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
3764 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
3766 surfacesides = NULL;
3769 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3771 castermask = rtlight->static_shadowmap_casters;
3772 receivermask = rtlight->static_shadowmap_receivers;
3776 surfacesides = r_shadow_buffer_surfacesides;
3777 for(i = 0;i < numsurfaces;i++)
3779 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
3780 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3781 castermask |= surfacesides[i];
3782 receivermask |= surfacesides[i];
3786 if (receivermask < 0x3F)
3788 for (i = 0;i < numlightentities;i++)
3789 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3790 if (receivermask < 0x3F)
3791 for(i = 0; i < numlightentities_noselfshadow;i++)
3792 receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3795 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
3799 for (i = 0;i < numshadowentities;i++)
3800 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3801 for (i = 0;i < numshadowentities_noselfshadow;i++)
3802 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3805 //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
3807 // render shadow casters into 6 sided depth texture
3808 for (side = 0;side < 6;side++) if (receivermask & (1 << side))
3810 R_Shadow_RenderMode_ShadowMap(side, true, size);
3811 if (! (castermask & (1 << side))) continue;
3813 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
3814 for (i = 0;i < numshadowentities;i++) if (entitysides[i] & (1 << side))
3815 R_Shadow_DrawEntityShadow(shadowentities[i]);
3818 if (numlightentities_noselfshadow)
3820 // render lighting using the depth texture as shadowmap
3821 // draw lighting in the unmasked areas
3822 R_Shadow_RenderMode_Lighting(false, false, true);
3823 for (i = 0;i < numlightentities_noselfshadow;i++)
3824 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3827 // render shadow casters into 6 sided depth texture
3828 if (numshadowentities_noselfshadow)
3830 for (side = 0;side < 6;side++) if ((receivermask & castermask) & (1 << side))
3832 R_Shadow_RenderMode_ShadowMap(side, false, size);
3833 for (i = 0;i < numshadowentities_noselfshadow;i++) if (entitysides_noselfshadow[i] & (1 << side))
3834 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3838 // render lighting using the depth texture as shadowmap
3839 // draw lighting in the unmasked areas
3840 R_Shadow_RenderMode_Lighting(false, false, true);
3841 // draw lighting in the unmasked areas
3843 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3844 for (i = 0;i < numlightentities;i++)
3845 R_Shadow_DrawEntityLight(lightentities[i]);
3847 else if (castshadows && vid.stencil)
3849 // draw stencil shadow volumes to mask off pixels that are in shadow
3850 // so that they won't receive lighting
3851 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
3852 R_Shadow_ClearStencil();
3855 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
3856 for (i = 0;i < numshadowentities;i++)
3857 R_Shadow_DrawEntityShadow(shadowentities[i]);
3859 // draw lighting in the unmasked areas
3860 R_Shadow_RenderMode_Lighting(true, false, false);
3861 for (i = 0;i < numlightentities_noselfshadow;i++)
3862 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3864 for (i = 0;i < numshadowentities_noselfshadow;i++)
3865 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3867 // draw lighting in the unmasked areas
3868 R_Shadow_RenderMode_Lighting(true, false, false);
3870 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3871 for (i = 0;i < numlightentities;i++)
3872 R_Shadow_DrawEntityLight(lightentities[i]);
3876 // draw lighting in the unmasked areas
3877 R_Shadow_RenderMode_Lighting(false, false, false);
3879 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3880 for (i = 0;i < numlightentities;i++)
3881 R_Shadow_DrawEntityLight(lightentities[i]);
3882 for (i = 0;i < numlightentities_noselfshadow;i++)
3883 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3886 if (r_shadow_usingdeferredprepass)
3888 // when rendering deferred lighting, we simply rasterize the box
3889 if (castshadows && (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE))
3890 R_Shadow_RenderMode_DrawDeferredLight(false, true);
3891 else if (castshadows && vid.stencil)
3892 R_Shadow_RenderMode_DrawDeferredLight(true, false);
3894 R_Shadow_RenderMode_DrawDeferredLight(false, false);
3898 static void R_Shadow_FreeDeferred(void)
3900 if (r_shadow_prepassgeometryfbo)
3901 qglDeleteFramebuffersEXT(1, &r_shadow_prepassgeometryfbo);CHECKGLERROR
3902 r_shadow_prepassgeometryfbo = 0;
3904 if (r_shadow_prepasslightingfbo)
3905 qglDeleteFramebuffersEXT(1, &r_shadow_prepasslightingfbo);CHECKGLERROR
3906 r_shadow_prepasslightingfbo = 0;
3908 if (r_shadow_prepassgeometrydepthtexture)
3909 R_FreeTexture(r_shadow_prepassgeometrydepthtexture);
3910 r_shadow_prepassgeometrydepthtexture = NULL;
3912 if (r_shadow_prepassgeometrynormalmaptexture)
3913 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
3914 r_shadow_prepassgeometrynormalmaptexture = NULL;
3916 if (r_shadow_prepasslightingdiffusetexture)
3917 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
3918 r_shadow_prepasslightingdiffusetexture = NULL;
3920 if (r_shadow_prepasslightingspeculartexture)
3921 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
3922 r_shadow_prepasslightingspeculartexture = NULL;
3925 void R_Shadow_DrawPrepass(void)
3933 entity_render_t *ent;
3935 GL_AlphaTest(false);
3936 R_Mesh_ColorPointer(NULL, 0, 0);
3937 R_Mesh_ResetTextureState();
3939 GL_ColorMask(1,1,1,1);
3940 GL_BlendFunc(GL_ONE, GL_ZERO);
3943 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepassgeometryfbo);CHECKGLERROR
3944 qglClearColor(0.5f,0.5f,0.5f,1.0f);CHECKGLERROR
3945 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);CHECKGLERROR
3947 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
3948 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
3949 if (r_timereport_active)
3950 R_TimeReport("prepassworld");
3952 for (i = 0;i < r_refdef.scene.numentities;i++)
3954 if (!r_refdef.viewcache.entityvisible[i])
3956 ent = r_refdef.scene.entities[i];
3957 if (ent->model && ent->model->DrawPrepass != NULL)
3958 ent->model->DrawPrepass(ent);
3961 if (r_timereport_active)
3962 R_TimeReport("prepassmodels");
3964 GL_DepthMask(false);
3965 GL_ColorMask(1,1,1,1);
3968 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepasslightingfbo);CHECKGLERROR
3969 qglClearColor(0.0f,0.0f,0.0f,0.0f);CHECKGLERROR
3970 GL_Clear(GL_COLOR_BUFFER_BIT);CHECKGLERROR
3971 if (r_refdef.fogenabled)
3972 qglClearColor(r_refdef.fogcolor[0],r_refdef.fogcolor[1],r_refdef.fogcolor[2],0);CHECKGLERROR
3974 R_Shadow_RenderMode_Begin();
3976 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3977 if (r_shadow_debuglight.integer >= 0)
3979 lightindex = r_shadow_debuglight.integer;
3980 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3981 if (light && (light->flags & flag))
3982 R_Shadow_DrawLight(&light->rtlight);
3986 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3987 for (lightindex = 0;lightindex < range;lightindex++)
3989 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3990 if (light && (light->flags & flag))
3991 R_Shadow_DrawLight(&light->rtlight);
3994 if (r_refdef.scene.rtdlight)
3995 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
3996 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
3998 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);CHECKGLERROR
3999 if (r_refdef.fogenabled)
4000 qglClearColor(r_refdef.fogcolor[0],r_refdef.fogcolor[1],r_refdef.fogcolor[2],0);CHECKGLERROR
4002 R_Shadow_RenderMode_End();
4004 if (r_timereport_active)
4005 R_TimeReport("prepasslights");
4008 void R_Shadow_DrawLightSprites(void);
4009 void R_Shadow_PrepareLights(void)
4019 if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4) ||
4020 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
4021 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0) ||
4022 r_shadow_shadowmaptexturetype != r_shadow_shadowmapping_texturetype.integer ||
4023 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
4024 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
4025 r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
4026 R_Shadow_FreeShadowMaps();
4028 switch (vid.renderpath)
4030 case RENDERPATH_GL20:
4031 case RENDERPATH_CGGL:
4032 if (!r_shadow_deferred.integer || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_STENCIL || !vid.support.ext_framebuffer_object || !vid.support.arb_texture_rectangle || vid.maxdrawbuffers < 2)
4034 r_shadow_usingdeferredprepass = false;
4035 if (r_shadow_prepass_width)
4036 R_Shadow_FreeDeferred();
4037 r_shadow_prepass_width = r_shadow_prepass_height = 0;
4041 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
4043 R_Shadow_FreeDeferred();
4045 r_shadow_usingdeferredprepass = true;
4046 r_shadow_prepass_width = vid.width;
4047 r_shadow_prepass_height = vid.height;
4048 r_shadow_prepassgeometrydepthtexture = R_LoadTextureShadowMapRectangle(r_shadow_texturepool, "prepassgeometrydepthmap", vid.width, vid.height, 24, false);
4049 r_shadow_prepassgeometrynormalmaptexture = R_LoadTextureRectangle(r_shadow_texturepool, "prepassgeometrynormalmap", vid.width, vid.height, NULL, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, NULL);
4050 r_shadow_prepasslightingdiffusetexture = R_LoadTextureRectangle(r_shadow_texturepool, "prepasslightingdiffuse", vid.width, vid.height, NULL, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, NULL);
4051 r_shadow_prepasslightingspeculartexture = R_LoadTextureRectangle(r_shadow_texturepool, "prepasslightingspecular", vid.width, vid.height, NULL, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, NULL);
4053 // set up the geometry pass fbo (depth + normalmap)
4054 qglGenFramebuffersEXT(1, &r_shadow_prepassgeometryfbo);CHECKGLERROR
4055 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepassgeometryfbo);CHECKGLERROR
4056 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, R_GetTexture(r_shadow_prepassgeometrydepthtexture), 0);CHECKGLERROR
4057 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, R_GetTexture(r_shadow_prepassgeometrynormalmaptexture), 0);CHECKGLERROR
4058 // render depth into one texture and normalmap into the other
4059 qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);CHECKGLERROR
4060 qglReadBuffer(GL_NONE);CHECKGLERROR
4061 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4062 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4064 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4065 Cvar_SetValueQuick(&r_shadow_deferred, 0);
4066 r_shadow_usingdeferredprepass = false;
4069 // set up the lighting pass fbo (diffuse + specular)
4070 qglGenFramebuffersEXT(1, &r_shadow_prepasslightingfbo);CHECKGLERROR
4071 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_prepasslightingfbo);CHECKGLERROR
4072 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, R_GetTexture(r_shadow_prepassgeometrydepthtexture), 0);CHECKGLERROR
4073 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, R_GetTexture(r_shadow_prepasslightingdiffusetexture), 0);CHECKGLERROR
4074 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_RECTANGLE_ARB, R_GetTexture(r_shadow_prepasslightingspeculartexture), 0);CHECKGLERROR
4075 // render diffuse into one texture and specular into another,
4076 // with depth and normalmap bound as textures,
4077 // with depth bound as attachment as well
4078 qglDrawBuffersARB(2, r_shadow_prepasslightingdrawbuffers);CHECKGLERROR
4079 qglReadBuffer(GL_NONE);CHECKGLERROR
4080 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4081 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4083 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4084 Cvar_SetValueQuick(&r_shadow_deferred, 0);
4085 r_shadow_usingdeferredprepass = false;
4089 case RENDERPATH_GL13:
4090 case RENDERPATH_GL11:
4091 r_shadow_usingdeferredprepass = false;
4095 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);
4097 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4098 if (r_shadow_debuglight.integer >= 0)
4100 lightindex = r_shadow_debuglight.integer;
4101 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4102 if (light && (light->flags & flag))
4103 R_Shadow_PrepareLight(&light->rtlight);
4107 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4108 for (lightindex = 0;lightindex < range;lightindex++)
4110 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4111 if (light && (light->flags & flag))
4112 R_Shadow_PrepareLight(&light->rtlight);
4115 if (r_refdef.scene.rtdlight)
4117 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4118 R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
4120 else if(gl_flashblend.integer)
4122 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4124 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
4125 f = (rtlight->style >= 0 ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4126 VectorScale(rtlight->color, f, rtlight->currentcolor);
4130 if (r_editlights.integer)
4131 R_Shadow_DrawLightSprites();
4134 void R_Shadow_DrawLights(void)
4142 R_Shadow_RenderMode_Begin();
4144 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4145 if (r_shadow_debuglight.integer >= 0)
4147 lightindex = r_shadow_debuglight.integer;
4148 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4149 if (light && (light->flags & flag))
4150 R_Shadow_DrawLight(&light->rtlight);
4154 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4155 for (lightindex = 0;lightindex < range;lightindex++)
4157 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4158 if (light && (light->flags & flag))
4159 R_Shadow_DrawLight(&light->rtlight);
4162 if (r_refdef.scene.rtdlight)
4163 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4164 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4166 R_Shadow_RenderMode_End();
4169 extern const float r_screenvertex3f[12];
4170 extern void R_SetupView(qboolean allowwaterclippingplane);
4171 extern void R_ResetViewRendering3D(void);
4172 extern void R_ResetViewRendering2D(void);
4173 extern cvar_t r_shadows;
4174 extern cvar_t r_shadows_darken;
4175 extern cvar_t r_shadows_drawafterrtlighting;
4176 extern cvar_t r_shadows_castfrombmodels;
4177 extern cvar_t r_shadows_throwdistance;
4178 extern cvar_t r_shadows_throwdirection;
4179 void R_DrawModelShadows(void)
4182 float relativethrowdistance;
4183 entity_render_t *ent;
4184 vec3_t relativelightorigin;
4185 vec3_t relativelightdirection;
4186 vec3_t relativeshadowmins, relativeshadowmaxs;
4187 vec3_t tmp, shadowdir;
4189 if (!r_refdef.scene.numentities || !vid.stencil)
4193 R_ResetViewRendering3D();
4194 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4195 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4196 R_Shadow_RenderMode_Begin();
4197 R_Shadow_RenderMode_ActiveLight(NULL);
4198 r_shadow_lightscissor[0] = r_refdef.view.x;
4199 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
4200 r_shadow_lightscissor[2] = r_refdef.view.width;
4201 r_shadow_lightscissor[3] = r_refdef.view.height;
4202 R_Shadow_RenderMode_StencilShadowVolumes(false);
4205 if (r_shadows.integer == 2)
4207 Math_atov(r_shadows_throwdirection.string, shadowdir);
4208 VectorNormalize(shadowdir);
4211 R_Shadow_ClearStencil();
4213 for (i = 0;i < r_refdef.scene.numentities;i++)
4215 ent = r_refdef.scene.entities[i];
4217 // cast shadows from anything of the map (submodels are optional)
4218 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4220 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4221 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
4222 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
4223 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
4224 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4227 if(ent->entitynumber != 0)
4229 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
4230 int entnum, entnum2, recursion;
4231 entnum = entnum2 = ent->entitynumber;
4232 for(recursion = 32; recursion > 0; --recursion)
4234 entnum2 = cl.entities[entnum].state_current.tagentity;
4235 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
4240 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
4242 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
4243 // transform into modelspace of OUR entity
4244 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
4245 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
4248 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4251 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4254 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
4255 RSurf_ActiveModelEntity(ent, false, false, false);
4256 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4257 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4261 // not really the right mode, but this will disable any silly stencil features
4262 R_Shadow_RenderMode_End();
4264 // set up ortho view for rendering this pass
4265 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4266 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4267 //GL_ScissorTest(true);
4268 //R_EntityMatrix(&identitymatrix);
4269 //R_Mesh_ResetTextureState();
4270 R_ResetViewRendering2D();
4271 R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
4272 R_Mesh_ColorPointer(NULL, 0, 0);
4273 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
4275 // set up a darkening blend on shadowed areas
4276 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4277 //GL_DepthRange(0, 1);
4278 //GL_DepthTest(false);
4279 //GL_DepthMask(false);
4280 //GL_PolygonOffset(0, 0);CHECKGLERROR
4281 GL_Color(0, 0, 0, r_shadows_darken.value);
4282 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4283 //qglDepthFunc(GL_ALWAYS);CHECKGLERROR
4284 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
4285 qglStencilMask(~0);CHECKGLERROR
4286 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
4287 qglStencilFunc(GL_NOTEQUAL, 128, ~0);CHECKGLERROR
4289 // apply the blend to the shadowed areas
4290 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
4292 // restore the viewport
4293 R_SetViewport(&r_refdef.view.viewport);
4295 // restore other state to normal
4296 //R_Shadow_RenderMode_End();
4299 void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4302 vec3_t centerorigin;
4304 // if it's too close, skip it
4305 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
4307 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4310 if (usequery && r_numqueries + 2 <= r_maxqueries)
4312 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4313 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4314 // 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
4315 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4318 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use qglDepthFunc instead
4319 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
4320 qglDepthFunc(GL_ALWAYS);
4321 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4322 R_Mesh_VertexPointer(vertex3f, 0, 0);
4323 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
4324 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4325 qglDepthFunc(GL_LEQUAL);
4326 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
4327 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4328 R_Mesh_VertexPointer(vertex3f, 0, 0);
4329 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
4330 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4333 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4336 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
4338 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4341 GLint allpixels = 0, visiblepixels = 0;
4342 // now we have to check the query result
4343 if (rtlight->corona_queryindex_visiblepixels)
4346 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
4347 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
4349 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
4350 if (visiblepixels < 1 || allpixels < 1)
4352 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
4353 cscale *= rtlight->corona_visibility;
4357 // FIXME: these traces should scan all render entities instead of cl.world
4358 if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
4361 VectorScale(rtlight->currentcolor, cscale, color);
4362 if (VectorLength(color) > (1.0f / 256.0f))
4365 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
4368 VectorNegate(color, color);
4369 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
4371 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4372 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);
4373 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4375 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
4379 void R_Shadow_DrawCoronas(void)
4387 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4389 if (r_waterstate.renderingscene)
4391 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4392 R_EntityMatrix(&identitymatrix);
4394 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4396 // check occlusion of coronas
4397 // use GL_ARB_occlusion_query if available
4398 // otherwise use raytraces
4400 usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
4403 GL_ColorMask(0,0,0,0);
4404 if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
4405 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
4408 r_maxqueries = (range + r_refdef.scene.numlights) * 4;
4409 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
4411 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
4414 RSurf_ActiveWorldEntity();
4415 GL_BlendFunc(GL_ONE, GL_ZERO);
4416 GL_CullFace(GL_NONE);
4417 GL_DepthMask(false);
4418 GL_DepthRange(0, 1);
4419 GL_PolygonOffset(0, 0);
4421 R_Mesh_ColorPointer(NULL, 0, 0);
4422 R_Mesh_ResetTextureState();
4423 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
4425 for (lightindex = 0;lightindex < range;lightindex++)
4427 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4430 rtlight = &light->rtlight;
4431 rtlight->corona_visibility = 0;
4432 rtlight->corona_queryindex_visiblepixels = 0;
4433 rtlight->corona_queryindex_allpixels = 0;
4434 if (!(rtlight->flags & flag))
4436 if (rtlight->corona <= 0)
4438 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4440 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4442 for (i = 0;i < r_refdef.scene.numlights;i++)
4444 rtlight = r_refdef.scene.lights[i];
4445 rtlight->corona_visibility = 0;
4446 rtlight->corona_queryindex_visiblepixels = 0;
4447 rtlight->corona_queryindex_allpixels = 0;
4448 if (!(rtlight->flags & flag))
4450 if (rtlight->corona <= 0)
4452 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4455 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4457 // now draw the coronas using the query data for intensity info
4458 for (lightindex = 0;lightindex < range;lightindex++)
4460 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4463 rtlight = &light->rtlight;
4464 if (rtlight->corona_visibility <= 0)
4466 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4468 for (i = 0;i < r_refdef.scene.numlights;i++)
4470 rtlight = r_refdef.scene.lights[i];
4471 if (rtlight->corona_visibility <= 0)
4473 if (gl_flashblend.integer)
4474 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4476 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4482 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
4483 typedef struct suffixinfo_s
4486 qboolean flipx, flipy, flipdiagonal;
4489 static suffixinfo_t suffix[3][6] =
4492 {"px", false, false, false},
4493 {"nx", false, false, false},
4494 {"py", false, false, false},
4495 {"ny", false, false, false},
4496 {"pz", false, false, false},
4497 {"nz", false, false, false}
4500 {"posx", false, false, false},
4501 {"negx", false, false, false},
4502 {"posy", false, false, false},
4503 {"negy", false, false, false},
4504 {"posz", false, false, false},
4505 {"negz", false, false, false}
4508 {"rt", true, false, true},
4509 {"lf", false, true, true},
4510 {"ft", true, true, false},
4511 {"bk", false, false, false},
4512 {"up", true, false, true},
4513 {"dn", true, false, true}
4517 static int componentorder[4] = {0, 1, 2, 3};
4519 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
4521 int i, j, cubemapsize;
4522 unsigned char *cubemappixels, *image_buffer;
4523 rtexture_t *cubemaptexture;
4525 // must start 0 so the first loadimagepixels has no requested width/height
4527 cubemappixels = NULL;
4528 cubemaptexture = NULL;
4529 // keep trying different suffix groups (posx, px, rt) until one loads
4530 for (j = 0;j < 3 && !cubemappixels;j++)
4532 // load the 6 images in the suffix group
4533 for (i = 0;i < 6;i++)
4535 // generate an image name based on the base and and suffix
4536 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
4538 if ((image_buffer = loadimagepixelsbgra(name, false, false)))
4540 // an image loaded, make sure width and height are equal
4541 if (image_width == image_height && (!cubemappixels || image_width == cubemapsize))
4543 // if this is the first image to load successfully, allocate the cubemap memory
4544 if (!cubemappixels && image_width >= 1)
4546 cubemapsize = image_width;
4547 // note this clears to black, so unavailable sides are black
4548 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
4550 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
4552 Image_CopyMux(cubemappixels+i*cubemapsize*cubemapsize*4, image_buffer, cubemapsize, cubemapsize, suffix[j][i].flipx, suffix[j][i].flipy, suffix[j][i].flipdiagonal, 4, 4, componentorder);
4555 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
4557 Mem_Free(image_buffer);
4561 // if a cubemap loaded, upload it
4564 if (developer_loading.integer)
4565 Con_Printf("loading cubemap \"%s\"\n", basename);
4567 if (!r_shadow_filters_texturepool)
4568 r_shadow_filters_texturepool = R_AllocTexturePool();
4569 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_BGRA, (gl_texturecompression_lightcubemaps.integer ? TEXF_COMPRESS : 0) | TEXF_FORCELINEAR, NULL);
4570 Mem_Free(cubemappixels);
4574 Con_DPrintf("failed to load cubemap \"%s\"\n", basename);
4575 if (developer_loading.integer)
4577 Con_Printf("(tried tried images ");
4578 for (j = 0;j < 3;j++)
4579 for (i = 0;i < 6;i++)
4580 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
4581 Con_Print(" and was unable to find any of them).\n");
4584 return cubemaptexture;
4587 rtexture_t *R_Shadow_Cubemap(const char *basename)
4590 for (i = 0;i < numcubemaps;i++)
4591 if (!strcasecmp(cubemaps[i].basename, basename))
4592 return cubemaps[i].texture ? cubemaps[i].texture : r_texture_whitecube;
4593 if (i >= MAX_CUBEMAPS)
4594 return r_texture_whitecube;
4596 strlcpy(cubemaps[i].basename, basename, sizeof(cubemaps[i].basename));
4597 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
4598 return cubemaps[i].texture;
4601 void R_Shadow_FreeCubemaps(void)
4604 for (i = 0;i < numcubemaps;i++)
4606 if (developer_loading.integer)
4607 Con_Printf("unloading cubemap \"%s\"\n", cubemaps[i].basename);
4608 if (cubemaps[i].texture)
4609 R_FreeTexture(cubemaps[i].texture);
4613 R_FreeTexturePool(&r_shadow_filters_texturepool);
4616 dlight_t *R_Shadow_NewWorldLight(void)
4618 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4621 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)
4624 // validate parameters
4625 if (style < 0 || style >= MAX_LIGHTSTYLES)
4627 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
4633 // copy to light properties
4634 VectorCopy(origin, light->origin);
4635 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4636 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4637 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4639 light->color[0] = max(color[0], 0);
4640 light->color[1] = max(color[1], 0);
4641 light->color[2] = max(color[2], 0);
4643 light->color[0] = color[0];
4644 light->color[1] = color[1];
4645 light->color[2] = color[2];
4646 light->radius = max(radius, 0);
4647 light->style = style;
4648 light->shadow = shadowenable;
4649 light->corona = corona;
4650 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4651 light->coronasizescale = coronasizescale;
4652 light->ambientscale = ambientscale;
4653 light->diffusescale = diffusescale;
4654 light->specularscale = specularscale;
4655 light->flags = flags;
4657 // update renderable light data
4658 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4659 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);
4662 void R_Shadow_FreeWorldLight(dlight_t *light)
4664 if (r_shadow_selectedlight == light)
4665 r_shadow_selectedlight = NULL;
4666 R_RTLight_Uncompile(&light->rtlight);
4667 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4670 void R_Shadow_ClearWorldLights(void)
4674 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4675 for (lightindex = 0;lightindex < range;lightindex++)
4677 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4679 R_Shadow_FreeWorldLight(light);
4681 r_shadow_selectedlight = NULL;
4682 R_Shadow_FreeCubemaps();
4685 void R_Shadow_SelectLight(dlight_t *light)
4687 if (r_shadow_selectedlight)
4688 r_shadow_selectedlight->selected = false;
4689 r_shadow_selectedlight = light;
4690 if (r_shadow_selectedlight)
4691 r_shadow_selectedlight->selected = true;
4694 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4696 // this is never batched (there can be only one)
4698 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
4699 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4700 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4703 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4708 skinframe_t *skinframe;
4711 // this is never batched (due to the ent parameter changing every time)
4712 // so numsurfaces == 1 and surfacelist[0] == lightnumber
4713 const dlight_t *light = (dlight_t *)ent;
4716 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
4719 VectorScale(light->color, intensity, spritecolor);
4720 if (VectorLength(spritecolor) < 0.1732f)
4721 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
4722 if (VectorLength(spritecolor) > 1.0f)
4723 VectorNormalize(spritecolor);
4725 // draw light sprite
4726 if (light->cubemapname[0] && !light->shadow)
4727 skinframe = r_editlights_sprcubemapnoshadowlight;
4728 else if (light->cubemapname[0])
4729 skinframe = r_editlights_sprcubemaplight;
4730 else if (!light->shadow)
4731 skinframe = r_editlights_sprnoshadowlight;
4733 skinframe = r_editlights_sprlight;
4735 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);
4736 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4738 // draw selection sprite if light is selected
4739 if (light->selected)
4741 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4742 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4743 // VorteX todo: add normalmode/realtime mode light overlay sprites?
4747 void R_Shadow_DrawLightSprites(void)
4751 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4752 for (lightindex = 0;lightindex < range;lightindex++)
4754 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4756 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
4758 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
4761 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
4766 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
4767 if (lightindex >= range)
4769 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4772 rtlight = &light->rtlight;
4773 //if (!(rtlight->flags & flag))
4775 VectorCopy(rtlight->shadoworigin, origin);
4776 *radius = rtlight->radius;
4777 VectorCopy(rtlight->color, color);
4781 void R_Shadow_SelectLightInView(void)
4783 float bestrating, rating, temp[3];
4787 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4790 for (lightindex = 0;lightindex < range;lightindex++)
4792 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4795 VectorSubtract(light->origin, r_refdef.view.origin, temp);
4796 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
4799 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
4800 if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1.0f)
4802 bestrating = rating;
4807 R_Shadow_SelectLight(best);
4810 void R_Shadow_LoadWorldLights(void)
4812 int n, a, style, shadow, flags;
4813 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
4814 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
4815 if (cl.worldmodel == NULL)
4817 Con_Print("No map loaded.\n");
4820 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4821 strlcat (name, ".rtlights", sizeof (name));
4822 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4832 for (;COM_Parse(t, true) && strcmp(
4833 if (COM_Parse(t, true))
4835 if (com_token[0] == '!')
4838 origin[0] = atof(com_token+1);
4841 origin[0] = atof(com_token);
4846 while (*s && *s != '\n' && *s != '\r')
4852 // check for modifier flags
4859 #if _MSC_VER >= 1400
4860 #define sscanf sscanf_s
4862 cubemapname[sizeof(cubemapname)-1] = 0;
4863 #if MAX_QPATH != 128
4864 #error update this code if MAX_QPATH changes
4866 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
4867 #if _MSC_VER >= 1400
4868 , sizeof(cubemapname)
4870 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
4873 flags = LIGHTFLAG_REALTIMEMODE;
4881 coronasizescale = 0.25f;
4883 VectorClear(angles);
4886 if (a < 9 || !strcmp(cubemapname, "\"\""))
4888 // remove quotes on cubemapname
4889 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
4892 namelen = strlen(cubemapname) - 2;
4893 memmove(cubemapname, cubemapname + 1, namelen);
4894 cubemapname[namelen] = '\0';
4898 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);
4901 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4909 Con_Printf("invalid rtlights file \"%s\"\n", name);
4910 Mem_Free(lightsstring);
4914 void R_Shadow_SaveWorldLights(void)
4918 size_t bufchars, bufmaxchars;
4920 char name[MAX_QPATH];
4921 char line[MAX_INPUTLINE];
4922 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
4923 // I hate lines which are 3 times my screen size :( --blub
4926 if (cl.worldmodel == NULL)
4928 Con_Print("No map loaded.\n");
4931 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4932 strlcat (name, ".rtlights", sizeof (name));
4933 bufchars = bufmaxchars = 0;
4935 for (lightindex = 0;lightindex < range;lightindex++)
4937 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4940 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
4941 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);
4942 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
4943 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]);
4945 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);
4946 if (bufchars + strlen(line) > bufmaxchars)
4948 bufmaxchars = bufchars + strlen(line) + 2048;
4950 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
4954 memcpy(buf, oldbuf, bufchars);
4960 memcpy(buf + bufchars, line, strlen(line));
4961 bufchars += strlen(line);
4965 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
4970 void R_Shadow_LoadLightsFile(void)
4973 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
4974 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
4975 if (cl.worldmodel == NULL)
4977 Con_Print("No map loaded.\n");
4980 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4981 strlcat (name, ".lights", sizeof (name));
4982 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4990 while (*s && *s != '\n' && *s != '\r')
4996 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);
5000 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);
5003 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
5004 radius = bound(15, radius, 4096);
5005 VectorScale(color, (2.0f / (8388608.0f)), color);
5006 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5014 Con_Printf("invalid lights file \"%s\"\n", name);
5015 Mem_Free(lightsstring);
5019 // tyrlite/hmap2 light types in the delay field
5020 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
5022 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
5024 int entnum, style, islight, skin, pflags, effects, type, n;
5027 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
5028 char key[256], value[MAX_INPUTLINE];
5030 if (cl.worldmodel == NULL)
5032 Con_Print("No map loaded.\n");
5035 // try to load a .ent file first
5036 FS_StripExtension (cl.worldmodel->name, key, sizeof (key));
5037 strlcat (key, ".ent", sizeof (key));
5038 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
5039 // and if that is not found, fall back to the bsp file entity string
5041 data = cl.worldmodel->brush.entities;
5044 for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
5046 type = LIGHTTYPE_MINUSX;
5047 origin[0] = origin[1] = origin[2] = 0;
5048 originhack[0] = originhack[1] = originhack[2] = 0;
5049 angles[0] = angles[1] = angles[2] = 0;
5050 color[0] = color[1] = color[2] = 1;
5051 light[0] = light[1] = light[2] = 1;light[3] = 300;
5052 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
5062 if (!COM_ParseToken_Simple(&data, false, false))
5064 if (com_token[0] == '}')
5065 break; // end of entity
5066 if (com_token[0] == '_')
5067 strlcpy(key, com_token + 1, sizeof(key));
5069 strlcpy(key, com_token, sizeof(key));
5070 while (key[strlen(key)-1] == ' ') // remove trailing spaces
5071 key[strlen(key)-1] = 0;
5072 if (!COM_ParseToken_Simple(&data, false, false))
5074 strlcpy(value, com_token, sizeof(value));
5076 // now that we have the key pair worked out...
5077 if (!strcmp("light", key))
5079 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5083 light[0] = vec[0] * (1.0f / 256.0f);
5084 light[1] = vec[0] * (1.0f / 256.0f);
5085 light[2] = vec[0] * (1.0f / 256.0f);
5091 light[0] = vec[0] * (1.0f / 255.0f);
5092 light[1] = vec[1] * (1.0f / 255.0f);
5093 light[2] = vec[2] * (1.0f / 255.0f);
5097 else if (!strcmp("delay", key))
5099 else if (!strcmp("origin", key))
5100 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5101 else if (!strcmp("angle", key))
5102 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5103 else if (!strcmp("angles", key))
5104 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5105 else if (!strcmp("color", key))
5106 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5107 else if (!strcmp("wait", key))
5108 fadescale = atof(value);
5109 else if (!strcmp("classname", key))
5111 if (!strncmp(value, "light", 5))
5114 if (!strcmp(value, "light_fluoro"))
5119 overridecolor[0] = 1;
5120 overridecolor[1] = 1;
5121 overridecolor[2] = 1;
5123 if (!strcmp(value, "light_fluorospark"))
5128 overridecolor[0] = 1;
5129 overridecolor[1] = 1;
5130 overridecolor[2] = 1;
5132 if (!strcmp(value, "light_globe"))
5137 overridecolor[0] = 1;
5138 overridecolor[1] = 0.8;
5139 overridecolor[2] = 0.4;
5141 if (!strcmp(value, "light_flame_large_yellow"))
5146 overridecolor[0] = 1;
5147 overridecolor[1] = 0.5;
5148 overridecolor[2] = 0.1;
5150 if (!strcmp(value, "light_flame_small_yellow"))
5155 overridecolor[0] = 1;
5156 overridecolor[1] = 0.5;
5157 overridecolor[2] = 0.1;
5159 if (!strcmp(value, "light_torch_small_white"))
5164 overridecolor[0] = 1;
5165 overridecolor[1] = 0.5;
5166 overridecolor[2] = 0.1;
5168 if (!strcmp(value, "light_torch_small_walltorch"))
5173 overridecolor[0] = 1;
5174 overridecolor[1] = 0.5;
5175 overridecolor[2] = 0.1;
5179 else if (!strcmp("style", key))
5180 style = atoi(value);
5181 else if (!strcmp("skin", key))
5182 skin = (int)atof(value);
5183 else if (!strcmp("pflags", key))
5184 pflags = (int)atof(value);
5185 else if (!strcmp("effects", key))
5186 effects = (int)atof(value);
5187 else if (cl.worldmodel->type == mod_brushq3)
5189 if (!strcmp("scale", key))
5190 lightscale = atof(value);
5191 if (!strcmp("fade", key))
5192 fadescale = atof(value);
5197 if (lightscale <= 0)
5201 if (color[0] == color[1] && color[0] == color[2])
5203 color[0] *= overridecolor[0];
5204 color[1] *= overridecolor[1];
5205 color[2] *= overridecolor[2];
5207 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5208 color[0] = color[0] * light[0];
5209 color[1] = color[1] * light[1];
5210 color[2] = color[2] * light[2];
5213 case LIGHTTYPE_MINUSX:
5215 case LIGHTTYPE_RECIPX:
5217 VectorScale(color, (1.0f / 16.0f), color);
5219 case LIGHTTYPE_RECIPXX:
5221 VectorScale(color, (1.0f / 16.0f), color);
5224 case LIGHTTYPE_NONE:
5228 case LIGHTTYPE_MINUSXX:
5231 VectorAdd(origin, originhack, origin);
5233 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);
5236 Mem_Free(entfiledata);
5240 void R_Shadow_SetCursorLocationForView(void)
5243 vec3_t dest, endpos;
5245 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5246 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
5247 if (trace.fraction < 1)
5249 dist = trace.fraction * r_editlights_cursordistance.value;
5250 push = r_editlights_cursorpushback.value;
5254 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5255 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5259 VectorClear( endpos );
5261 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5262 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5263 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5266 void R_Shadow_UpdateWorldLightSelection(void)
5268 if (r_editlights.integer)
5270 R_Shadow_SetCursorLocationForView();
5271 R_Shadow_SelectLightInView();
5274 R_Shadow_SelectLight(NULL);
5277 void R_Shadow_EditLights_Clear_f(void)
5279 R_Shadow_ClearWorldLights();
5282 void R_Shadow_EditLights_Reload_f(void)
5286 strlcpy(r_shadow_mapname, cl.worldmodel->name, sizeof(r_shadow_mapname));
5287 R_Shadow_ClearWorldLights();
5288 R_Shadow_LoadWorldLights();
5289 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5291 R_Shadow_LoadLightsFile();
5292 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5293 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5297 void R_Shadow_EditLights_Save_f(void)
5301 R_Shadow_SaveWorldLights();
5304 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
5306 R_Shadow_ClearWorldLights();
5307 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5310 void R_Shadow_EditLights_ImportLightsFile_f(void)
5312 R_Shadow_ClearWorldLights();
5313 R_Shadow_LoadLightsFile();
5316 void R_Shadow_EditLights_Spawn_f(void)
5319 if (!r_editlights.integer)
5321 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5324 if (Cmd_Argc() != 1)
5326 Con_Print("r_editlights_spawn does not take parameters\n");
5329 color[0] = color[1] = color[2] = 1;
5330 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5333 void R_Shadow_EditLights_Edit_f(void)
5335 vec3_t origin, angles, color;
5336 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5337 int style, shadows, flags, normalmode, realtimemode;
5338 char cubemapname[MAX_INPUTLINE];
5339 if (!r_editlights.integer)
5341 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5344 if (!r_shadow_selectedlight)
5346 Con_Print("No selected light.\n");
5349 VectorCopy(r_shadow_selectedlight->origin, origin);
5350 VectorCopy(r_shadow_selectedlight->angles, angles);
5351 VectorCopy(r_shadow_selectedlight->color, color);
5352 radius = r_shadow_selectedlight->radius;
5353 style = r_shadow_selectedlight->style;
5354 if (r_shadow_selectedlight->cubemapname)
5355 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5358 shadows = r_shadow_selectedlight->shadow;
5359 corona = r_shadow_selectedlight->corona;
5360 coronasizescale = r_shadow_selectedlight->coronasizescale;
5361 ambientscale = r_shadow_selectedlight->ambientscale;
5362 diffusescale = r_shadow_selectedlight->diffusescale;
5363 specularscale = r_shadow_selectedlight->specularscale;
5364 flags = r_shadow_selectedlight->flags;
5365 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5366 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5367 if (!strcmp(Cmd_Argv(1), "origin"))
5369 if (Cmd_Argc() != 5)
5371 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5374 origin[0] = atof(Cmd_Argv(2));
5375 origin[1] = atof(Cmd_Argv(3));
5376 origin[2] = atof(Cmd_Argv(4));
5378 else if (!strcmp(Cmd_Argv(1), "originx"))
5380 if (Cmd_Argc() != 3)
5382 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5385 origin[0] = atof(Cmd_Argv(2));
5387 else if (!strcmp(Cmd_Argv(1), "originy"))
5389 if (Cmd_Argc() != 3)
5391 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5394 origin[1] = atof(Cmd_Argv(2));
5396 else if (!strcmp(Cmd_Argv(1), "originz"))
5398 if (Cmd_Argc() != 3)
5400 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5403 origin[2] = atof(Cmd_Argv(2));
5405 else if (!strcmp(Cmd_Argv(1), "move"))
5407 if (Cmd_Argc() != 5)
5409 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5412 origin[0] += atof(Cmd_Argv(2));
5413 origin[1] += atof(Cmd_Argv(3));
5414 origin[2] += atof(Cmd_Argv(4));
5416 else if (!strcmp(Cmd_Argv(1), "movex"))
5418 if (Cmd_Argc() != 3)
5420 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5423 origin[0] += atof(Cmd_Argv(2));
5425 else if (!strcmp(Cmd_Argv(1), "movey"))
5427 if (Cmd_Argc() != 3)
5429 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5432 origin[1] += atof(Cmd_Argv(2));
5434 else if (!strcmp(Cmd_Argv(1), "movez"))
5436 if (Cmd_Argc() != 3)
5438 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5441 origin[2] += atof(Cmd_Argv(2));
5443 else if (!strcmp(Cmd_Argv(1), "angles"))
5445 if (Cmd_Argc() != 5)
5447 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5450 angles[0] = atof(Cmd_Argv(2));
5451 angles[1] = atof(Cmd_Argv(3));
5452 angles[2] = atof(Cmd_Argv(4));
5454 else if (!strcmp(Cmd_Argv(1), "anglesx"))
5456 if (Cmd_Argc() != 3)
5458 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5461 angles[0] = atof(Cmd_Argv(2));
5463 else if (!strcmp(Cmd_Argv(1), "anglesy"))
5465 if (Cmd_Argc() != 3)
5467 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5470 angles[1] = atof(Cmd_Argv(2));
5472 else if (!strcmp(Cmd_Argv(1), "anglesz"))
5474 if (Cmd_Argc() != 3)
5476 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5479 angles[2] = atof(Cmd_Argv(2));
5481 else if (!strcmp(Cmd_Argv(1), "color"))
5483 if (Cmd_Argc() != 5)
5485 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
5488 color[0] = atof(Cmd_Argv(2));
5489 color[1] = atof(Cmd_Argv(3));
5490 color[2] = atof(Cmd_Argv(4));
5492 else if (!strcmp(Cmd_Argv(1), "radius"))
5494 if (Cmd_Argc() != 3)
5496 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5499 radius = atof(Cmd_Argv(2));
5501 else if (!strcmp(Cmd_Argv(1), "colorscale"))
5503 if (Cmd_Argc() == 3)
5505 double scale = atof(Cmd_Argv(2));
5512 if (Cmd_Argc() != 5)
5514 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
5517 color[0] *= atof(Cmd_Argv(2));
5518 color[1] *= atof(Cmd_Argv(3));
5519 color[2] *= atof(Cmd_Argv(4));
5522 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
5524 if (Cmd_Argc() != 3)
5526 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5529 radius *= atof(Cmd_Argv(2));
5531 else if (!strcmp(Cmd_Argv(1), "style"))
5533 if (Cmd_Argc() != 3)
5535 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5538 style = atoi(Cmd_Argv(2));
5540 else if (!strcmp(Cmd_Argv(1), "cubemap"))
5544 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5547 if (Cmd_Argc() == 3)
5548 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
5552 else if (!strcmp(Cmd_Argv(1), "shadows"))
5554 if (Cmd_Argc() != 3)
5556 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5559 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5561 else if (!strcmp(Cmd_Argv(1), "corona"))
5563 if (Cmd_Argc() != 3)
5565 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5568 corona = atof(Cmd_Argv(2));
5570 else if (!strcmp(Cmd_Argv(1), "coronasize"))
5572 if (Cmd_Argc() != 3)
5574 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5577 coronasizescale = atof(Cmd_Argv(2));
5579 else if (!strcmp(Cmd_Argv(1), "ambient"))
5581 if (Cmd_Argc() != 3)
5583 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5586 ambientscale = atof(Cmd_Argv(2));
5588 else if (!strcmp(Cmd_Argv(1), "diffuse"))
5590 if (Cmd_Argc() != 3)
5592 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5595 diffusescale = atof(Cmd_Argv(2));
5597 else if (!strcmp(Cmd_Argv(1), "specular"))
5599 if (Cmd_Argc() != 3)
5601 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5604 specularscale = atof(Cmd_Argv(2));
5606 else if (!strcmp(Cmd_Argv(1), "normalmode"))
5608 if (Cmd_Argc() != 3)
5610 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5613 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5615 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
5617 if (Cmd_Argc() != 3)
5619 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5622 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5626 Con_Print("usage: r_editlights_edit [property] [value]\n");
5627 Con_Print("Selected light's properties:\n");
5628 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5629 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5630 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5631 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
5632 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
5633 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
5634 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5635 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
5636 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
5637 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
5638 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
5639 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
5640 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5641 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5644 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5645 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5648 void R_Shadow_EditLights_EditAll_f(void)
5654 if (!r_editlights.integer)
5656 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5660 // EditLights doesn't seem to have a "remove" command or something so:
5661 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5662 for (lightindex = 0;lightindex < range;lightindex++)
5664 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5667 R_Shadow_SelectLight(light);
5668 R_Shadow_EditLights_Edit_f();
5672 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
5674 int lightnumber, lightcount;
5675 size_t lightindex, range;
5679 if (!r_editlights.integer)
5681 x = vid_conwidth.value - 240;
5683 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
5686 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5687 for (lightindex = 0;lightindex < range;lightindex++)
5689 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5692 if (light == r_shadow_selectedlight)
5693 lightnumber = lightindex;
5696 dpsnprintf(temp, sizeof(temp), "Cursor origin: %.0f %.0f %.0f", r_editlights_cursorlocation[0], r_editlights_cursorlocation[1], r_editlights_cursorlocation[2]); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, false);y += 8;
5697 dpsnprintf(temp, sizeof(temp), "Total lights : %i active (%i total)", lightcount, (int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray)); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, false);y += 8;
5699 if (r_shadow_selectedlight == NULL)
5701 dpsnprintf(temp, sizeof(temp), "Light #%i properties:", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
5702 dpsnprintf(temp, sizeof(temp), "Origin : %.0f %.0f %.0f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
5703 dpsnprintf(temp, sizeof(temp), "Angles : %.0f %.0f %.0f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
5704 dpsnprintf(temp, sizeof(temp), "Color : %.2f %.2f %.2f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
5705 dpsnprintf(temp, sizeof(temp), "Radius : %.0f\n", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
5706 dpsnprintf(temp, sizeof(temp), "Corona : %.0f\n", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
5707 dpsnprintf(temp, sizeof(temp), "Style : %i\n", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
5708 dpsnprintf(temp, sizeof(temp), "Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
5709 dpsnprintf(temp, sizeof(temp), "Cubemap : %s\n", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
5710 dpsnprintf(temp, sizeof(temp), "CoronaSize : %.2f\n", r_shadow_selectedlight->coronasizescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
5711 dpsnprintf(temp, sizeof(temp), "Ambient : %.2f\n", r_shadow_selectedlight->ambientscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
5712 dpsnprintf(temp, sizeof(temp), "Diffuse : %.2f\n", r_shadow_selectedlight->diffusescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
5713 dpsnprintf(temp, sizeof(temp), "Specular : %.2f\n", r_shadow_selectedlight->specularscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
5714 dpsnprintf(temp, sizeof(temp), "NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
5715 dpsnprintf(temp, sizeof(temp), "RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
5718 void R_Shadow_EditLights_ToggleShadow_f(void)
5720 if (!r_editlights.integer)
5722 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5725 if (!r_shadow_selectedlight)
5727 Con_Print("No selected light.\n");
5730 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);
5733 void R_Shadow_EditLights_ToggleCorona_f(void)
5735 if (!r_editlights.integer)
5737 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5740 if (!r_shadow_selectedlight)
5742 Con_Print("No selected light.\n");
5745 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);
5748 void R_Shadow_EditLights_Remove_f(void)
5750 if (!r_editlights.integer)
5752 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
5755 if (!r_shadow_selectedlight)
5757 Con_Print("No selected light.\n");
5760 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
5761 r_shadow_selectedlight = NULL;
5764 void R_Shadow_EditLights_Help_f(void)
5767 "Documentation on r_editlights system:\n"
5769 "r_editlights : enable/disable editing mode\n"
5770 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
5771 "r_editlights_cursorpushback : push back cursor this far from surface\n"
5772 "r_editlights_cursorpushoff : push cursor off surface this far\n"
5773 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
5774 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
5776 "r_editlights_help : this help\n"
5777 "r_editlights_clear : remove all lights\n"
5778 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
5779 "r_editlights_save : save to .rtlights file\n"
5780 "r_editlights_spawn : create a light with default settings\n"
5781 "r_editlights_edit command : edit selected light - more documentation below\n"
5782 "r_editlights_remove : remove selected light\n"
5783 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
5784 "r_editlights_importlightentitiesfrommap : reload light entities\n"
5785 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
5787 "origin x y z : set light location\n"
5788 "originx x: set x component of light location\n"
5789 "originy y: set y component of light location\n"
5790 "originz z: set z component of light location\n"
5791 "move x y z : adjust light location\n"
5792 "movex x: adjust x component of light location\n"
5793 "movey y: adjust y component of light location\n"
5794 "movez z: adjust z component of light location\n"
5795 "angles x y z : set light angles\n"
5796 "anglesx x: set x component of light angles\n"
5797 "anglesy y: set y component of light angles\n"
5798 "anglesz z: set z component of light angles\n"
5799 "color r g b : set color of light (can be brighter than 1 1 1)\n"
5800 "radius radius : set radius (size) of light\n"
5801 "colorscale grey : multiply color of light (1 does nothing)\n"
5802 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
5803 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
5804 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
5805 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
5806 "cubemap basename : set filter cubemap of light (not yet supported)\n"
5807 "shadows 1/0 : turn on/off shadows\n"
5808 "corona n : set corona intensity\n"
5809 "coronasize n : set corona size (0-1)\n"
5810 "ambient n : set ambient intensity (0-1)\n"
5811 "diffuse n : set diffuse intensity (0-1)\n"
5812 "specular n : set specular intensity (0-1)\n"
5813 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
5814 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
5815 "<nothing> : print light properties to console\n"
5819 void R_Shadow_EditLights_CopyInfo_f(void)
5821 if (!r_editlights.integer)
5823 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
5826 if (!r_shadow_selectedlight)
5828 Con_Print("No selected light.\n");
5831 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
5832 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
5833 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
5834 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
5835 if (r_shadow_selectedlight->cubemapname)
5836 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
5838 r_shadow_bufferlight.cubemapname[0] = 0;
5839 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
5840 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
5841 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
5842 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
5843 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
5844 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
5845 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
5848 void R_Shadow_EditLights_PasteInfo_f(void)
5850 if (!r_editlights.integer)
5852 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
5855 if (!r_shadow_selectedlight)
5857 Con_Print("No selected light.\n");
5860 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);
5863 void R_Shadow_EditLights_Init(void)
5865 Cvar_RegisterVariable(&r_editlights);
5866 Cvar_RegisterVariable(&r_editlights_cursordistance);
5867 Cvar_RegisterVariable(&r_editlights_cursorpushback);
5868 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
5869 Cvar_RegisterVariable(&r_editlights_cursorgrid);
5870 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
5871 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
5872 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
5873 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)");
5874 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
5875 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
5876 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
5877 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)");
5878 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
5879 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
5880 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
5881 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
5882 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
5883 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
5884 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)");
5890 =============================================================================
5894 =============================================================================
5897 void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, int dynamic)
5899 VectorClear(diffusecolor);
5900 VectorClear(diffusenormal);
5902 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
5904 ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_refdef.scene.ambient;
5905 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
5908 VectorSet(ambientcolor, 1, 1, 1);
5915 for (i = 0;i < r_refdef.scene.numlights;i++)
5917 light = r_refdef.scene.lights[i];
5918 Matrix4x4_Transform(&light->matrix_worldtolight, p, v);
5919 f = 1 - VectorLength2(v);
5920 if (f > 0 && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
5921 VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);