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"
142 #include "dpsoftrast.h"
146 extern LPDIRECT3DDEVICE9 vid_d3d9dev;
149 extern void R_Shadow_EditLights_Init(void);
151 typedef enum r_shadow_rendermode_e
153 R_SHADOW_RENDERMODE_NONE,
154 R_SHADOW_RENDERMODE_ZPASS_STENCIL,
155 R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL,
156 R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE,
157 R_SHADOW_RENDERMODE_ZFAIL_STENCIL,
158 R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL,
159 R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE,
160 R_SHADOW_RENDERMODE_LIGHT_VERTEX,
161 R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN,
162 R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN,
163 R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN,
164 R_SHADOW_RENDERMODE_LIGHT_GLSL,
165 R_SHADOW_RENDERMODE_VISIBLEVOLUMES,
166 R_SHADOW_RENDERMODE_VISIBLELIGHTING,
167 R_SHADOW_RENDERMODE_SHADOWMAP2D
169 r_shadow_rendermode_t;
171 typedef enum r_shadow_shadowmode_e
173 R_SHADOW_SHADOWMODE_STENCIL,
174 R_SHADOW_SHADOWMODE_SHADOWMAP2D
176 r_shadow_shadowmode_t;
178 r_shadow_rendermode_t r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
179 r_shadow_rendermode_t r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_NONE;
180 r_shadow_rendermode_t r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_NONE;
181 r_shadow_rendermode_t r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_NONE;
182 qboolean r_shadow_usingshadowmap2d;
183 qboolean r_shadow_usingshadowmaportho;
184 int r_shadow_shadowmapside;
185 float r_shadow_shadowmap_texturescale[2];
186 float r_shadow_shadowmap_parameters[4];
188 int r_shadow_drawbuffer;
189 int r_shadow_readbuffer;
191 int r_shadow_cullface_front, r_shadow_cullface_back;
192 GLuint r_shadow_fbo2d;
193 r_shadow_shadowmode_t r_shadow_shadowmode;
194 int r_shadow_shadowmapfilterquality;
195 int r_shadow_shadowmapdepthbits;
196 int r_shadow_shadowmapmaxsize;
197 qboolean r_shadow_shadowmapvsdct;
198 qboolean r_shadow_shadowmapsampler;
199 int r_shadow_shadowmappcf;
200 int r_shadow_shadowmapborder;
201 matrix4x4_t r_shadow_shadowmapmatrix;
202 int r_shadow_lightscissor[4];
203 qboolean r_shadow_usingdeferredprepass;
205 int maxshadowtriangles;
208 int maxshadowvertices;
209 float *shadowvertex3f;
219 unsigned char *shadowsides;
220 int *shadowsideslist;
227 int r_shadow_buffer_numleafpvsbytes;
228 unsigned char *r_shadow_buffer_visitingleafpvs;
229 unsigned char *r_shadow_buffer_leafpvs;
230 int *r_shadow_buffer_leaflist;
232 int r_shadow_buffer_numsurfacepvsbytes;
233 unsigned char *r_shadow_buffer_surfacepvs;
234 int *r_shadow_buffer_surfacelist;
235 unsigned char *r_shadow_buffer_surfacesides;
237 int r_shadow_buffer_numshadowtrispvsbytes;
238 unsigned char *r_shadow_buffer_shadowtrispvs;
239 int r_shadow_buffer_numlighttrispvsbytes;
240 unsigned char *r_shadow_buffer_lighttrispvs;
242 rtexturepool_t *r_shadow_texturepool;
243 rtexture_t *r_shadow_attenuationgradienttexture;
244 rtexture_t *r_shadow_attenuation2dtexture;
245 rtexture_t *r_shadow_attenuation3dtexture;
246 skinframe_t *r_shadow_lightcorona;
247 rtexture_t *r_shadow_shadowmap2dtexture;
248 rtexture_t *r_shadow_shadowmap2dcolortexture;
249 rtexture_t *r_shadow_shadowmapvsdcttexture;
250 int r_shadow_shadowmapsize; // changes for each light based on distance
251 int r_shadow_shadowmaplod; // changes for each light based on distance
253 GLuint r_shadow_prepassgeometryfbo;
254 GLuint r_shadow_prepasslightingfbo;
255 int r_shadow_prepass_width;
256 int r_shadow_prepass_height;
257 rtexture_t *r_shadow_prepassgeometrydepthtexture;
258 rtexture_t *r_shadow_prepassgeometrydepthcolortexture;
259 rtexture_t *r_shadow_prepassgeometrynormalmaptexture;
260 rtexture_t *r_shadow_prepasslightingdiffusetexture;
261 rtexture_t *r_shadow_prepasslightingspeculartexture;
263 // lights are reloaded when this changes
264 char r_shadow_mapname[MAX_QPATH];
266 // used only for light filters (cubemaps)
267 rtexturepool_t *r_shadow_filters_texturepool;
269 static const GLenum r_shadow_prepasslightingdrawbuffers[2] = {GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT};
271 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"};
272 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"};
273 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
274 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"};
275 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)"};
276 //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"};
277 cvar_t r_shadow_usebihculling = {0, "r_shadow_usebihculling", "1", "use BIH (Bounding Interval Hierarchy) for culling lit surfaces instead of BSP (Binary Space Partitioning)"};
278 cvar_t r_shadow_usenormalmap = {CVAR_SAVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"};
279 cvar_t r_shadow_gloss = {CVAR_SAVE, "r_shadow_gloss", "1", "0 disables gloss (specularity) rendering, 1 uses gloss if textures are found, 2 forces a flat metallic specular effect on everything without textures (similar to tenebrae)"};
280 cvar_t r_shadow_gloss2intensity = {0, "r_shadow_gloss2intensity", "0.125", "how bright the forced flat gloss should look if r_shadow_gloss is 2"};
281 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
282 cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
283 cvar_t r_shadow_gloss2exponent = {0, "r_shadow_gloss2exponent", "32", "same as r_shadow_glossexponent but for forced gloss (gloss 2) surfaces"};
284 cvar_t r_shadow_glossexact = {0, "r_shadow_glossexact", "0", "use exact reflection math for gloss (slightly slower, but should look a tad better)"};
285 cvar_t r_shadow_lightattenuationdividebias = {0, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"};
286 cvar_t r_shadow_lightattenuationlinearscale = {0, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"};
287 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
288 cvar_t r_shadow_lightradiusscale = {0, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
289 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "0", "how far to cast shadows"};
290 cvar_t r_shadow_frontsidecasting = {0, "r_shadow_frontsidecasting", "1", "whether to cast shadows from illuminated triangles (front side of model) or unlit triangles (back side of model)"};
291 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
292 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
293 cvar_t r_shadow_realtime_dlight_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
294 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
295 cvar_t r_shadow_realtime_world = {CVAR_SAVE, "r_shadow_realtime_world", "0", "enables rendering of full world lighting (whether loaded from the map, or a .rtlights file, or a .ent file, or a .lights file produced by hlight)"};
296 cvar_t r_shadow_realtime_world_lightmaps = {CVAR_SAVE, "r_shadow_realtime_world_lightmaps", "0", "brightness to render lightmaps when using full world lighting, try 0.5 for a tenebrae-like appearance"};
297 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
298 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
299 cvar_t r_shadow_realtime_world_compileshadow = {0, "r_shadow_realtime_world_compileshadow", "1", "enables compilation of shadows from world lights for higher performance rendering"};
300 cvar_t r_shadow_realtime_world_compilesvbsp = {0, "r_shadow_realtime_world_compilesvbsp", "1", "enables svbsp optimization during compilation (slower than compileportalculling but more exact)"};
301 cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "1", "enables portal-based culling optimization during compilation (overrides compilesvbsp)"};
302 cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1", "use scissor optimization of light rendering (restricts rendering to the portion of the screen affected by the light)"};
303 cvar_t r_shadow_shadowmapping = {CVAR_SAVE, "r_shadow_shadowmapping", "0", "enables use of shadowmapping (depth texture sampling) instead of stencil shadow volumes, requires gl_fbo 1"};
304 cvar_t r_shadow_shadowmapping_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)"};
305 cvar_t r_shadow_shadowmapping_depthbits = {CVAR_SAVE, "r_shadow_shadowmapping_depthbits", "24", "requested minimum shadowmap texture depth bits"};
306 cvar_t r_shadow_shadowmapping_vsdct = {CVAR_SAVE, "r_shadow_shadowmapping_vsdct", "1", "enables use of virtual shadow depth cube texture"};
307 cvar_t r_shadow_shadowmapping_minsize = {CVAR_SAVE, "r_shadow_shadowmapping_minsize", "32", "shadowmap size limit"};
308 cvar_t r_shadow_shadowmapping_maxsize = {CVAR_SAVE, "r_shadow_shadowmapping_maxsize", "512", "shadowmap size limit"};
309 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"};
310 //cvar_t r_shadow_shadowmapping_lod_bias = {CVAR_SAVE, "r_shadow_shadowmapping_lod_bias", "16", "shadowmap size bias"};
311 //cvar_t r_shadow_shadowmapping_lod_scale = {CVAR_SAVE, "r_shadow_shadowmapping_lod_scale", "128", "shadowmap size scaling parameter"};
312 cvar_t r_shadow_shadowmapping_bordersize = {CVAR_SAVE, "r_shadow_shadowmapping_bordersize", "4", "shadowmap size bias for filtering"};
313 cvar_t r_shadow_shadowmapping_nearclip = {CVAR_SAVE, "r_shadow_shadowmapping_nearclip", "1", "shadowmap nearclip in world units"};
314 cvar_t r_shadow_shadowmapping_bias = {CVAR_SAVE, "r_shadow_shadowmapping_bias", "0.03", "shadowmap bias parameter (this is multiplied by nearclip * 1024 / lodsize)"};
315 cvar_t r_shadow_shadowmapping_polygonfactor = {CVAR_SAVE, "r_shadow_shadowmapping_polygonfactor", "2", "slope-dependent shadowmapping bias"};
316 cvar_t r_shadow_shadowmapping_polygonoffset = {CVAR_SAVE, "r_shadow_shadowmapping_polygonoffset", "0", "constant shadowmapping bias"};
317 cvar_t r_shadow_sortsurfaces = {0, "r_shadow_sortsurfaces", "1", "improve performance by sorting illuminated surfaces by texture"};
318 cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
319 cvar_t r_shadow_polygonoffset = {0, "r_shadow_polygonoffset", "1", "how much to push shadow volumes into the distance when rendering, to reduce chances of zfighting artifacts (should not be less than 0)"};
320 cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "1", "use 3D voxel textures for spherical attenuation rather than cylindrical (does not affect OpenGL 2.0 render path)"};
321 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "1", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
322 cvar_t r_coronas_occlusionsizescale = {CVAR_SAVE, "r_coronas_occlusionsizescale", "0.1", "size of light source for corona occlusion checksum the proportion of hidden pixels controls corona intensity"};
323 cvar_t r_coronas_occlusionquery = {CVAR_SAVE, "r_coronas_occlusionquery", "1", "use GL_ARB_occlusion_query extension if supported (fades coronas according to visibility)"};
324 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
325 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
326 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
327 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
328 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
329 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
330 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
331 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
332 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
334 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
335 #define ATTENTABLESIZE 256
336 // 1D gradient, 2D circle and 3D sphere attenuation textures
337 #define ATTEN1DSIZE 32
338 #define ATTEN2DSIZE 64
339 #define ATTEN3DSIZE 32
341 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
342 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
343 static float r_shadow_attentable[ATTENTABLESIZE+1];
345 rtlight_t *r_shadow_compilingrtlight;
346 static memexpandablearray_t r_shadow_worldlightsarray;
347 dlight_t *r_shadow_selectedlight;
348 dlight_t r_shadow_bufferlight;
349 vec3_t r_editlights_cursorlocation;
350 qboolean r_editlights_lockcursor;
352 extern int con_vislines;
354 void R_Shadow_UncompileWorldLights(void);
355 void R_Shadow_ClearWorldLights(void);
356 void R_Shadow_SaveWorldLights(void);
357 void R_Shadow_LoadWorldLights(void);
358 void R_Shadow_LoadLightsFile(void);
359 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
360 void R_Shadow_EditLights_Reload_f(void);
361 void R_Shadow_ValidateCvars(void);
362 static void R_Shadow_MakeTextures(void);
364 #define EDLIGHTSPRSIZE 8
365 skinframe_t *r_editlights_sprcursor;
366 skinframe_t *r_editlights_sprlight;
367 skinframe_t *r_editlights_sprnoshadowlight;
368 skinframe_t *r_editlights_sprcubemaplight;
369 skinframe_t *r_editlights_sprcubemapnoshadowlight;
370 skinframe_t *r_editlights_sprselection;
372 void R_Shadow_SetShadowMode(void)
374 r_shadow_shadowmapmaxsize = bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4);
375 r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20;
376 r_shadow_shadowmapfilterquality = r_shadow_shadowmapping_filterquality.integer;
377 r_shadow_shadowmapdepthbits = r_shadow_shadowmapping_depthbits.integer;
378 r_shadow_shadowmapborder = bound(0, r_shadow_shadowmapping_bordersize.integer, 16);
379 r_shadow_shadowmaplod = -1;
380 r_shadow_shadowmapsize = 0;
381 r_shadow_shadowmapsampler = false;
382 r_shadow_shadowmappcf = 0;
383 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
384 if ((r_shadow_shadowmapping.integer || r_shadow_deferred.integer) && vid.support.ext_framebuffer_object)
386 switch(vid.renderpath)
388 case RENDERPATH_GL20:
389 if(r_shadow_shadowmapfilterquality < 0)
391 if(vid.support.amd_texture_texture4 || vid.support.arb_texture_gather)
392 r_shadow_shadowmappcf = 1;
393 else if(strstr(gl_vendor, "NVIDIA") || strstr(gl_renderer, "Radeon HD"))
395 r_shadow_shadowmapsampler = vid.support.arb_shadow;
396 r_shadow_shadowmappcf = 1;
398 else if(strstr(gl_vendor, "ATI"))
399 r_shadow_shadowmappcf = 1;
401 r_shadow_shadowmapsampler = vid.support.arb_shadow;
405 switch (r_shadow_shadowmapfilterquality)
408 r_shadow_shadowmapsampler = vid.support.arb_shadow;
411 r_shadow_shadowmapsampler = vid.support.arb_shadow;
412 r_shadow_shadowmappcf = 1;
415 r_shadow_shadowmappcf = 1;
418 r_shadow_shadowmappcf = 2;
422 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
424 case RENDERPATH_D3D9:
425 case RENDERPATH_D3D10:
426 case RENDERPATH_D3D11:
427 case RENDERPATH_SOFT:
428 r_shadow_shadowmapsampler = false;
429 r_shadow_shadowmappcf = 1;
430 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
432 case RENDERPATH_GL13:
434 case RENDERPATH_GL11:
436 case RENDERPATH_GLES2:
442 qboolean R_Shadow_ShadowMappingEnabled(void)
444 switch (r_shadow_shadowmode)
446 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
453 void R_Shadow_FreeShadowMaps(void)
455 R_Shadow_SetShadowMode();
457 R_Mesh_DestroyFramebufferObject(r_shadow_fbo2d);
461 if (r_shadow_shadowmap2dtexture)
462 R_FreeTexture(r_shadow_shadowmap2dtexture);
463 r_shadow_shadowmap2dtexture = NULL;
465 if (r_shadow_shadowmap2dcolortexture)
466 R_FreeTexture(r_shadow_shadowmap2dcolortexture);
467 r_shadow_shadowmap2dcolortexture = NULL;
469 if (r_shadow_shadowmapvsdcttexture)
470 R_FreeTexture(r_shadow_shadowmapvsdcttexture);
471 r_shadow_shadowmapvsdcttexture = NULL;
474 void r_shadow_start(void)
476 // allocate vertex processing arrays
477 r_shadow_attenuationgradienttexture = NULL;
478 r_shadow_attenuation2dtexture = NULL;
479 r_shadow_attenuation3dtexture = NULL;
480 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
481 r_shadow_shadowmap2dtexture = NULL;
482 r_shadow_shadowmap2dcolortexture = NULL;
483 r_shadow_shadowmapvsdcttexture = NULL;
484 r_shadow_shadowmapmaxsize = 0;
485 r_shadow_shadowmapsize = 0;
486 r_shadow_shadowmaplod = 0;
487 r_shadow_shadowmapfilterquality = -1;
488 r_shadow_shadowmapdepthbits = 0;
489 r_shadow_shadowmapvsdct = false;
490 r_shadow_shadowmapsampler = false;
491 r_shadow_shadowmappcf = 0;
494 R_Shadow_FreeShadowMaps();
496 r_shadow_texturepool = NULL;
497 r_shadow_filters_texturepool = NULL;
498 R_Shadow_ValidateCvars();
499 R_Shadow_MakeTextures();
500 maxshadowtriangles = 0;
501 shadowelements = NULL;
502 maxshadowvertices = 0;
503 shadowvertex3f = NULL;
511 shadowmarklist = NULL;
516 shadowsideslist = NULL;
517 r_shadow_buffer_numleafpvsbytes = 0;
518 r_shadow_buffer_visitingleafpvs = NULL;
519 r_shadow_buffer_leafpvs = NULL;
520 r_shadow_buffer_leaflist = NULL;
521 r_shadow_buffer_numsurfacepvsbytes = 0;
522 r_shadow_buffer_surfacepvs = NULL;
523 r_shadow_buffer_surfacelist = NULL;
524 r_shadow_buffer_surfacesides = NULL;
525 r_shadow_buffer_numshadowtrispvsbytes = 0;
526 r_shadow_buffer_shadowtrispvs = NULL;
527 r_shadow_buffer_numlighttrispvsbytes = 0;
528 r_shadow_buffer_lighttrispvs = NULL;
530 r_shadow_usingdeferredprepass = false;
531 r_shadow_prepass_width = r_shadow_prepass_height = 0;
534 static void R_Shadow_FreeDeferred(void);
535 void r_shadow_shutdown(void)
538 R_Shadow_UncompileWorldLights();
540 R_Shadow_FreeShadowMaps();
542 r_shadow_usingdeferredprepass = false;
543 if (r_shadow_prepass_width)
544 R_Shadow_FreeDeferred();
545 r_shadow_prepass_width = r_shadow_prepass_height = 0;
548 r_shadow_attenuationgradienttexture = NULL;
549 r_shadow_attenuation2dtexture = NULL;
550 r_shadow_attenuation3dtexture = NULL;
551 R_FreeTexturePool(&r_shadow_texturepool);
552 R_FreeTexturePool(&r_shadow_filters_texturepool);
553 maxshadowtriangles = 0;
555 Mem_Free(shadowelements);
556 shadowelements = NULL;
558 Mem_Free(shadowvertex3f);
559 shadowvertex3f = NULL;
562 Mem_Free(vertexupdate);
565 Mem_Free(vertexremap);
571 Mem_Free(shadowmark);
574 Mem_Free(shadowmarklist);
575 shadowmarklist = NULL;
580 Mem_Free(shadowsides);
583 Mem_Free(shadowsideslist);
584 shadowsideslist = NULL;
585 r_shadow_buffer_numleafpvsbytes = 0;
586 if (r_shadow_buffer_visitingleafpvs)
587 Mem_Free(r_shadow_buffer_visitingleafpvs);
588 r_shadow_buffer_visitingleafpvs = NULL;
589 if (r_shadow_buffer_leafpvs)
590 Mem_Free(r_shadow_buffer_leafpvs);
591 r_shadow_buffer_leafpvs = NULL;
592 if (r_shadow_buffer_leaflist)
593 Mem_Free(r_shadow_buffer_leaflist);
594 r_shadow_buffer_leaflist = NULL;
595 r_shadow_buffer_numsurfacepvsbytes = 0;
596 if (r_shadow_buffer_surfacepvs)
597 Mem_Free(r_shadow_buffer_surfacepvs);
598 r_shadow_buffer_surfacepvs = NULL;
599 if (r_shadow_buffer_surfacelist)
600 Mem_Free(r_shadow_buffer_surfacelist);
601 r_shadow_buffer_surfacelist = NULL;
602 if (r_shadow_buffer_surfacesides)
603 Mem_Free(r_shadow_buffer_surfacesides);
604 r_shadow_buffer_surfacesides = NULL;
605 r_shadow_buffer_numshadowtrispvsbytes = 0;
606 if (r_shadow_buffer_shadowtrispvs)
607 Mem_Free(r_shadow_buffer_shadowtrispvs);
608 r_shadow_buffer_numlighttrispvsbytes = 0;
609 if (r_shadow_buffer_lighttrispvs)
610 Mem_Free(r_shadow_buffer_lighttrispvs);
613 void r_shadow_newmap(void)
615 if (r_shadow_lightcorona) R_SkinFrame_MarkUsed(r_shadow_lightcorona);
616 if (r_editlights_sprcursor) R_SkinFrame_MarkUsed(r_editlights_sprcursor);
617 if (r_editlights_sprlight) R_SkinFrame_MarkUsed(r_editlights_sprlight);
618 if (r_editlights_sprnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprnoshadowlight);
619 if (r_editlights_sprcubemaplight) R_SkinFrame_MarkUsed(r_editlights_sprcubemaplight);
620 if (r_editlights_sprcubemapnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprcubemapnoshadowlight);
621 if (r_editlights_sprselection) R_SkinFrame_MarkUsed(r_editlights_sprselection);
622 if (strncmp(cl.worldname, r_shadow_mapname, sizeof(r_shadow_mapname)))
623 R_Shadow_EditLights_Reload_f();
626 void R_Shadow_Init(void)
628 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
629 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
630 Cvar_RegisterVariable(&r_shadow_usebihculling);
631 Cvar_RegisterVariable(&r_shadow_usenormalmap);
632 Cvar_RegisterVariable(&r_shadow_debuglight);
633 Cvar_RegisterVariable(&r_shadow_deferred);
634 Cvar_RegisterVariable(&r_shadow_deferred_8bitrange);
635 // Cvar_RegisterVariable(&r_shadow_deferred_fp);
636 Cvar_RegisterVariable(&r_shadow_gloss);
637 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
638 Cvar_RegisterVariable(&r_shadow_glossintensity);
639 Cvar_RegisterVariable(&r_shadow_glossexponent);
640 Cvar_RegisterVariable(&r_shadow_gloss2exponent);
641 Cvar_RegisterVariable(&r_shadow_glossexact);
642 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
643 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
644 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
645 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
646 Cvar_RegisterVariable(&r_shadow_projectdistance);
647 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
648 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
649 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
650 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
651 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
652 Cvar_RegisterVariable(&r_shadow_realtime_world);
653 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
654 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
655 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
656 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
657 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
658 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
659 Cvar_RegisterVariable(&r_shadow_scissor);
660 Cvar_RegisterVariable(&r_shadow_shadowmapping);
661 Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
662 Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
663 Cvar_RegisterVariable(&r_shadow_shadowmapping_depthbits);
664 Cvar_RegisterVariable(&r_shadow_shadowmapping_precision);
665 Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
666 Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
667 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
668 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
669 Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
670 Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
671 Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
672 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonfactor);
673 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonoffset);
674 Cvar_RegisterVariable(&r_shadow_sortsurfaces);
675 Cvar_RegisterVariable(&r_shadow_polygonfactor);
676 Cvar_RegisterVariable(&r_shadow_polygonoffset);
677 Cvar_RegisterVariable(&r_shadow_texture3d);
678 Cvar_RegisterVariable(&r_coronas);
679 Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
680 Cvar_RegisterVariable(&r_coronas_occlusionquery);
681 Cvar_RegisterVariable(&gl_flashblend);
682 Cvar_RegisterVariable(&gl_ext_separatestencil);
683 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
684 if (gamemode == GAME_TENEBRAE)
686 Cvar_SetValue("r_shadow_gloss", 2);
687 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
689 R_Shadow_EditLights_Init();
690 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
691 maxshadowtriangles = 0;
692 shadowelements = NULL;
693 maxshadowvertices = 0;
694 shadowvertex3f = NULL;
702 shadowmarklist = NULL;
707 shadowsideslist = NULL;
708 r_shadow_buffer_numleafpvsbytes = 0;
709 r_shadow_buffer_visitingleafpvs = NULL;
710 r_shadow_buffer_leafpvs = NULL;
711 r_shadow_buffer_leaflist = NULL;
712 r_shadow_buffer_numsurfacepvsbytes = 0;
713 r_shadow_buffer_surfacepvs = NULL;
714 r_shadow_buffer_surfacelist = NULL;
715 r_shadow_buffer_surfacesides = NULL;
716 r_shadow_buffer_shadowtrispvs = NULL;
717 r_shadow_buffer_lighttrispvs = NULL;
718 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap, NULL, NULL);
721 matrix4x4_t matrix_attenuationxyz =
724 {0.5, 0.0, 0.0, 0.5},
725 {0.0, 0.5, 0.0, 0.5},
726 {0.0, 0.0, 0.5, 0.5},
731 matrix4x4_t matrix_attenuationz =
734 {0.0, 0.0, 0.5, 0.5},
735 {0.0, 0.0, 0.0, 0.5},
736 {0.0, 0.0, 0.0, 0.5},
741 void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles, int vertscale, int triscale)
743 numvertices = ((numvertices + 255) & ~255) * vertscale;
744 numtriangles = ((numtriangles + 255) & ~255) * triscale;
745 // make sure shadowelements is big enough for this volume
746 if (maxshadowtriangles < numtriangles)
748 maxshadowtriangles = numtriangles;
750 Mem_Free(shadowelements);
751 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[3]));
753 // make sure shadowvertex3f is big enough for this volume
754 if (maxshadowvertices < numvertices)
756 maxshadowvertices = numvertices;
758 Mem_Free(shadowvertex3f);
759 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[3]));
763 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
765 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
766 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
767 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
768 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
769 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
771 if (r_shadow_buffer_visitingleafpvs)
772 Mem_Free(r_shadow_buffer_visitingleafpvs);
773 if (r_shadow_buffer_leafpvs)
774 Mem_Free(r_shadow_buffer_leafpvs);
775 if (r_shadow_buffer_leaflist)
776 Mem_Free(r_shadow_buffer_leaflist);
777 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
778 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
779 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
780 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
782 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
784 if (r_shadow_buffer_surfacepvs)
785 Mem_Free(r_shadow_buffer_surfacepvs);
786 if (r_shadow_buffer_surfacelist)
787 Mem_Free(r_shadow_buffer_surfacelist);
788 if (r_shadow_buffer_surfacesides)
789 Mem_Free(r_shadow_buffer_surfacesides);
790 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
791 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
792 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
793 r_shadow_buffer_surfacesides = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
795 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
797 if (r_shadow_buffer_shadowtrispvs)
798 Mem_Free(r_shadow_buffer_shadowtrispvs);
799 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
800 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
802 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
804 if (r_shadow_buffer_lighttrispvs)
805 Mem_Free(r_shadow_buffer_lighttrispvs);
806 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
807 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
811 void R_Shadow_PrepareShadowMark(int numtris)
813 // make sure shadowmark is big enough for this volume
814 if (maxshadowmark < numtris)
816 maxshadowmark = numtris;
818 Mem_Free(shadowmark);
820 Mem_Free(shadowmarklist);
821 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
822 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
826 // if shadowmarkcount wrapped we clear the array and adjust accordingly
827 if (shadowmarkcount == 0)
830 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
835 void R_Shadow_PrepareShadowSides(int numtris)
837 if (maxshadowsides < numtris)
839 maxshadowsides = numtris;
841 Mem_Free(shadowsides);
843 Mem_Free(shadowsideslist);
844 shadowsides = (unsigned char *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsides));
845 shadowsideslist = (int *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsideslist));
850 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)
853 int outtriangles = 0, outvertices = 0;
856 float ratio, direction[3], projectvector[3];
858 if (projectdirection)
859 VectorScale(projectdirection, projectdistance, projectvector);
861 VectorClear(projectvector);
863 // create the vertices
864 if (projectdirection)
866 for (i = 0;i < numshadowmarktris;i++)
868 element = inelement3i + shadowmarktris[i] * 3;
869 for (j = 0;j < 3;j++)
871 if (vertexupdate[element[j]] != vertexupdatenum)
873 vertexupdate[element[j]] = vertexupdatenum;
874 vertexremap[element[j]] = outvertices;
875 vertex = invertex3f + element[j] * 3;
876 // project one copy of the vertex according to projectvector
877 VectorCopy(vertex, outvertex3f);
878 VectorAdd(vertex, projectvector, (outvertex3f + 3));
887 for (i = 0;i < numshadowmarktris;i++)
889 element = inelement3i + shadowmarktris[i] * 3;
890 for (j = 0;j < 3;j++)
892 if (vertexupdate[element[j]] != vertexupdatenum)
894 vertexupdate[element[j]] = vertexupdatenum;
895 vertexremap[element[j]] = outvertices;
896 vertex = invertex3f + element[j] * 3;
897 // project one copy of the vertex to the sphere radius of the light
898 // (FIXME: would projecting it to the light box be better?)
899 VectorSubtract(vertex, projectorigin, direction);
900 ratio = projectdistance / VectorLength(direction);
901 VectorCopy(vertex, outvertex3f);
902 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
910 if (r_shadow_frontsidecasting.integer)
912 for (i = 0;i < numshadowmarktris;i++)
914 int remappedelement[3];
916 const int *neighbortriangle;
918 markindex = shadowmarktris[i] * 3;
919 element = inelement3i + markindex;
920 neighbortriangle = inneighbor3i + markindex;
921 // output the front and back triangles
922 outelement3i[0] = vertexremap[element[0]];
923 outelement3i[1] = vertexremap[element[1]];
924 outelement3i[2] = vertexremap[element[2]];
925 outelement3i[3] = vertexremap[element[2]] + 1;
926 outelement3i[4] = vertexremap[element[1]] + 1;
927 outelement3i[5] = vertexremap[element[0]] + 1;
931 // output the sides (facing outward from this triangle)
932 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
934 remappedelement[0] = vertexremap[element[0]];
935 remappedelement[1] = vertexremap[element[1]];
936 outelement3i[0] = remappedelement[1];
937 outelement3i[1] = remappedelement[0];
938 outelement3i[2] = remappedelement[0] + 1;
939 outelement3i[3] = remappedelement[1];
940 outelement3i[4] = remappedelement[0] + 1;
941 outelement3i[5] = remappedelement[1] + 1;
946 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
948 remappedelement[1] = vertexremap[element[1]];
949 remappedelement[2] = vertexremap[element[2]];
950 outelement3i[0] = remappedelement[2];
951 outelement3i[1] = remappedelement[1];
952 outelement3i[2] = remappedelement[1] + 1;
953 outelement3i[3] = remappedelement[2];
954 outelement3i[4] = remappedelement[1] + 1;
955 outelement3i[5] = remappedelement[2] + 1;
960 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
962 remappedelement[0] = vertexremap[element[0]];
963 remappedelement[2] = vertexremap[element[2]];
964 outelement3i[0] = remappedelement[0];
965 outelement3i[1] = remappedelement[2];
966 outelement3i[2] = remappedelement[2] + 1;
967 outelement3i[3] = remappedelement[0];
968 outelement3i[4] = remappedelement[2] + 1;
969 outelement3i[5] = remappedelement[0] + 1;
978 for (i = 0;i < numshadowmarktris;i++)
980 int remappedelement[3];
982 const int *neighbortriangle;
984 markindex = shadowmarktris[i] * 3;
985 element = inelement3i + markindex;
986 neighbortriangle = inneighbor3i + markindex;
987 // output the front and back triangles
988 outelement3i[0] = vertexremap[element[2]];
989 outelement3i[1] = vertexremap[element[1]];
990 outelement3i[2] = vertexremap[element[0]];
991 outelement3i[3] = vertexremap[element[0]] + 1;
992 outelement3i[4] = vertexremap[element[1]] + 1;
993 outelement3i[5] = vertexremap[element[2]] + 1;
997 // output the sides (facing outward from this triangle)
998 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
1000 remappedelement[0] = vertexremap[element[0]];
1001 remappedelement[1] = vertexremap[element[1]];
1002 outelement3i[0] = remappedelement[0];
1003 outelement3i[1] = remappedelement[1];
1004 outelement3i[2] = remappedelement[1] + 1;
1005 outelement3i[3] = remappedelement[0];
1006 outelement3i[4] = remappedelement[1] + 1;
1007 outelement3i[5] = remappedelement[0] + 1;
1012 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1014 remappedelement[1] = vertexremap[element[1]];
1015 remappedelement[2] = vertexremap[element[2]];
1016 outelement3i[0] = remappedelement[1];
1017 outelement3i[1] = remappedelement[2];
1018 outelement3i[2] = remappedelement[2] + 1;
1019 outelement3i[3] = remappedelement[1];
1020 outelement3i[4] = remappedelement[2] + 1;
1021 outelement3i[5] = remappedelement[1] + 1;
1026 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1028 remappedelement[0] = vertexremap[element[0]];
1029 remappedelement[2] = vertexremap[element[2]];
1030 outelement3i[0] = remappedelement[2];
1031 outelement3i[1] = remappedelement[0];
1032 outelement3i[2] = remappedelement[0] + 1;
1033 outelement3i[3] = remappedelement[2];
1034 outelement3i[4] = remappedelement[0] + 1;
1035 outelement3i[5] = remappedelement[2] + 1;
1043 *outnumvertices = outvertices;
1044 return outtriangles;
1047 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)
1050 int outtriangles = 0, outvertices = 0;
1052 const float *vertex;
1053 float ratio, direction[3], projectvector[3];
1056 if (projectdirection)
1057 VectorScale(projectdirection, projectdistance, projectvector);
1059 VectorClear(projectvector);
1061 for (i = 0;i < numshadowmarktris;i++)
1063 int remappedelement[3];
1065 const int *neighbortriangle;
1067 markindex = shadowmarktris[i] * 3;
1068 neighbortriangle = inneighbor3i + markindex;
1069 side[0] = shadowmark[neighbortriangle[0]] == shadowmarkcount;
1070 side[1] = shadowmark[neighbortriangle[1]] == shadowmarkcount;
1071 side[2] = shadowmark[neighbortriangle[2]] == shadowmarkcount;
1072 if (side[0] + side[1] + side[2] == 0)
1076 element = inelement3i + markindex;
1078 // create the vertices
1079 for (j = 0;j < 3;j++)
1081 if (side[j] + side[j+1] == 0)
1084 if (vertexupdate[k] != vertexupdatenum)
1086 vertexupdate[k] = vertexupdatenum;
1087 vertexremap[k] = outvertices;
1088 vertex = invertex3f + k * 3;
1089 VectorCopy(vertex, outvertex3f);
1090 if (projectdirection)
1092 // project one copy of the vertex according to projectvector
1093 VectorAdd(vertex, projectvector, (outvertex3f + 3));
1097 // project one copy of the vertex to the sphere radius of the light
1098 // (FIXME: would projecting it to the light box be better?)
1099 VectorSubtract(vertex, projectorigin, direction);
1100 ratio = projectdistance / VectorLength(direction);
1101 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1108 // output the sides (facing outward from this triangle)
1111 remappedelement[0] = vertexremap[element[0]];
1112 remappedelement[1] = vertexremap[element[1]];
1113 outelement3i[0] = remappedelement[1];
1114 outelement3i[1] = remappedelement[0];
1115 outelement3i[2] = remappedelement[0] + 1;
1116 outelement3i[3] = remappedelement[1];
1117 outelement3i[4] = remappedelement[0] + 1;
1118 outelement3i[5] = remappedelement[1] + 1;
1125 remappedelement[1] = vertexremap[element[1]];
1126 remappedelement[2] = vertexremap[element[2]];
1127 outelement3i[0] = remappedelement[2];
1128 outelement3i[1] = remappedelement[1];
1129 outelement3i[2] = remappedelement[1] + 1;
1130 outelement3i[3] = remappedelement[2];
1131 outelement3i[4] = remappedelement[1] + 1;
1132 outelement3i[5] = remappedelement[2] + 1;
1139 remappedelement[0] = vertexremap[element[0]];
1140 remappedelement[2] = vertexremap[element[2]];
1141 outelement3i[0] = remappedelement[0];
1142 outelement3i[1] = remappedelement[2];
1143 outelement3i[2] = remappedelement[2] + 1;
1144 outelement3i[3] = remappedelement[0];
1145 outelement3i[4] = remappedelement[2] + 1;
1146 outelement3i[5] = remappedelement[0] + 1;
1153 *outnumvertices = outvertices;
1154 return outtriangles;
1157 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)
1163 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1165 tend = firsttriangle + numtris;
1166 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1168 // surface box entirely inside light box, no box cull
1169 if (projectdirection)
1171 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1173 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
1174 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1175 shadowmarklist[numshadowmark++] = t;
1180 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1181 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
1182 shadowmarklist[numshadowmark++] = t;
1187 // surface box not entirely inside light box, cull each triangle
1188 if (projectdirection)
1190 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1192 v[0] = invertex3f + e[0] * 3;
1193 v[1] = invertex3f + e[1] * 3;
1194 v[2] = invertex3f + e[2] * 3;
1195 TriangleNormal(v[0], v[1], v[2], normal);
1196 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1197 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1198 shadowmarklist[numshadowmark++] = t;
1203 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1205 v[0] = invertex3f + e[0] * 3;
1206 v[1] = invertex3f + e[1] * 3;
1207 v[2] = invertex3f + e[2] * 3;
1208 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1209 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1210 shadowmarklist[numshadowmark++] = t;
1216 qboolean R_Shadow_UseZPass(vec3_t mins, vec3_t maxs)
1221 if (r_shadow_compilingrtlight || !r_shadow_frontsidecasting.integer || !r_shadow_usezpassifpossible.integer)
1223 // check if the shadow volume intersects the near plane
1225 // a ray between the eye and light origin may intersect the caster,
1226 // indicating that the shadow may touch the eye location, however we must
1227 // test the near plane (a polygon), not merely the eye location, so it is
1228 // easiest to enlarge the caster bounding shape slightly for this.
1234 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)
1236 int i, tris, outverts;
1237 if (projectdistance < 0.1)
1239 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
1242 if (!numverts || !nummarktris)
1244 // make sure shadowelements is big enough for this volume
1245 if (maxshadowtriangles < nummarktris*8 || maxshadowvertices < numverts*2)
1246 R_Shadow_ResizeShadowArrays(numverts, nummarktris, 2, 8);
1248 if (maxvertexupdate < numverts)
1250 maxvertexupdate = numverts;
1252 Mem_Free(vertexupdate);
1254 Mem_Free(vertexremap);
1255 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1256 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1257 vertexupdatenum = 0;
1260 if (vertexupdatenum == 0)
1262 vertexupdatenum = 1;
1263 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
1264 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
1267 for (i = 0;i < nummarktris;i++)
1268 shadowmark[marktris[i]] = shadowmarkcount;
1270 if (r_shadow_compilingrtlight)
1272 // if we're compiling an rtlight, capture the mesh
1273 //tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1274 //Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zpass, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1275 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1276 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zfail, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1278 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
1280 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1281 R_Mesh_PrepareVertices_Vertex3f(outverts, shadowvertex3f, NULL);
1282 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1286 // decide which type of shadow to generate and set stencil mode
1287 R_Shadow_RenderMode_StencilShadowVolumes(R_Shadow_UseZPass(trismins, trismaxs));
1288 // generate the sides or a solid volume, depending on type
1289 if (r_shadow_rendermode >= R_SHADOW_RENDERMODE_ZPASS_STENCIL && r_shadow_rendermode <= R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE)
1290 tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1292 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1293 r_refdef.stats.lights_dynamicshadowtriangles += tris;
1294 r_refdef.stats.lights_shadowtriangles += tris;
1295 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
1297 // increment stencil if frontface is infront of depthbuffer
1298 GL_CullFace(r_refdef.view.cullface_front);
1299 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
1300 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1301 // decrement stencil if backface is infront of depthbuffer
1302 GL_CullFace(r_refdef.view.cullface_back);
1303 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
1305 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
1307 // decrement stencil if backface is behind depthbuffer
1308 GL_CullFace(r_refdef.view.cullface_front);
1309 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
1310 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1311 // increment stencil if frontface is behind depthbuffer
1312 GL_CullFace(r_refdef.view.cullface_back);
1313 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
1315 R_Mesh_PrepareVertices_Vertex3f(outverts, shadowvertex3f, NULL);
1316 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1320 int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias)
1322 // p1, p2, p3 are in the cubemap's local coordinate system
1323 // bias = border/(size - border)
1326 float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1327 dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2),
1328 dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3);
1329 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1331 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1332 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1333 | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1334 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1336 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1337 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1338 | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1340 dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1341 dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2),
1342 dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3);
1343 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1345 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1346 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1347 | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1348 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1350 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1351 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1352 | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1354 dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1355 dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2),
1356 dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3);
1357 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1359 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1360 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1361 | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1362 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1364 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1365 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1366 | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1371 int R_Shadow_CalcBBoxSideMask(const vec3_t mins, const vec3_t maxs, const matrix4x4_t *worldtolight, const matrix4x4_t *radiustolight, float bias)
1373 vec3_t center, radius, lightcenter, lightradius, pmin, pmax;
1374 float dp1, dn1, ap1, an1, dp2, dn2, ap2, an2;
1377 VectorSubtract(maxs, mins, radius);
1378 VectorScale(radius, 0.5f, radius);
1379 VectorAdd(mins, radius, center);
1380 Matrix4x4_Transform(worldtolight, center, lightcenter);
1381 Matrix4x4_Transform3x3(radiustolight, radius, lightradius);
1382 VectorSubtract(lightcenter, lightradius, pmin);
1383 VectorAdd(lightcenter, lightradius, pmax);
1385 dp1 = pmax[0] + pmax[1], dn1 = pmax[0] - pmin[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1386 dp2 = pmin[0] + pmin[1], dn2 = pmin[0] - pmax[1], ap2 = fabs(dp2), an2 = fabs(dn2);
1387 if(ap1 > bias*an1 && ap2 > bias*an2)
1389 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1390 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1391 if(an1 > bias*ap1 && an2 > bias*ap2)
1393 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1394 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1396 dp1 = pmax[1] + pmax[2], dn1 = pmax[1] - pmin[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1397 dp2 = pmin[1] + pmin[2], dn2 = pmin[1] - pmax[2], ap2 = fabs(dp2), an2 = fabs(dn2);
1398 if(ap1 > bias*an1 && ap2 > bias*an2)
1400 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1401 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1402 if(an1 > bias*ap1 && an2 > bias*ap2)
1404 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1405 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1407 dp1 = pmax[2] + pmax[0], dn1 = pmax[2] - pmin[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1408 dp2 = pmin[2] + pmin[0], dn2 = pmin[2] - pmax[0], ap2 = fabs(dp2), an2 = fabs(dn2);
1409 if(ap1 > bias*an1 && ap2 > bias*an2)
1411 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1412 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1413 if(an1 > bias*ap1 && an2 > bias*ap2)
1415 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1416 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1421 #define R_Shadow_CalcEntitySideMask(ent, worldtolight, radiustolight, bias) R_Shadow_CalcBBoxSideMask((ent)->mins, (ent)->maxs, worldtolight, radiustolight, bias)
1423 int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
1425 // p is in the cubemap's local coordinate system
1426 // bias = border/(size - border)
1427 float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn);
1428 float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn);
1429 float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn);
1431 if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
1432 if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
1433 if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
1434 if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
1435 if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
1436 if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
1440 int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
1444 int sides = 0x3F, masks[6] = { 3<<4, 3<<4, 3<<0, 3<<0, 3<<2, 3<<2 };
1445 float scale = (size - 2*border)/size, len;
1446 float bias = border / (float)(size - border), dp, dn, ap, an;
1447 // check if cone enclosing side would cross frustum plane
1448 scale = 2 / (scale*scale + 2);
1449 for (i = 0;i < 5;i++)
1451 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) > -0.03125)
1453 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[i].normal, n);
1454 len = scale*VectorLength2(n);
1455 if(n[0]*n[0] > len) sides &= n[0] < 0 ? ~(1<<0) : ~(2 << 0);
1456 if(n[1]*n[1] > len) sides &= n[1] < 0 ? ~(1<<2) : ~(2 << 2);
1457 if(n[2]*n[2] > len) sides &= n[2] < 0 ? ~(1<<4) : ~(2 << 4);
1459 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[4]) >= r_refdef.farclip - r_refdef.nearclip + 0.03125)
1461 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[4].normal, n);
1462 len = scale*VectorLength(n);
1463 if(n[0]*n[0] > len) sides &= n[0] >= 0 ? ~(1<<0) : ~(2 << 0);
1464 if(n[1]*n[1] > len) sides &= n[1] >= 0 ? ~(1<<2) : ~(2 << 2);
1465 if(n[2]*n[2] > len) sides &= n[2] >= 0 ? ~(1<<4) : ~(2 << 4);
1467 // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results
1468 // check if frustum corners/origin cross plane sides
1470 // infinite version, assumes frustum corners merely give direction and extend to infinite distance
1471 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.origin, p);
1472 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1473 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1474 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1475 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1476 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1477 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1478 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1479 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1480 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1481 for (i = 0;i < 4;i++)
1483 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.frustumcorner[i], n);
1484 VectorSubtract(n, p, n);
1485 dp = n[0] + n[1], dn = n[0] - n[1], ap = fabs(dp), an = fabs(dn);
1486 if(ap > 0) masks[0] |= dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2);
1487 if(an > 0) masks[1] |= dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2);
1488 dp = n[1] + n[2], dn = n[1] - n[2], ap = fabs(dp), an = fabs(dn);
1489 if(ap > 0) masks[2] |= dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4);
1490 if(an > 0) masks[3] |= dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4);
1491 dp = n[2] + n[0], dn = n[2] - n[0], ap = fabs(dp), an = fabs(dn);
1492 if(ap > 0) masks[4] |= dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0);
1493 if(an > 0) masks[5] |= dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0);
1496 // finite version, assumes corners are a finite distance from origin dependent on far plane
1497 for (i = 0;i < 5;i++)
1499 Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p);
1500 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1501 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1502 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1503 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1504 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1505 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1506 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1507 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1508 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1511 return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5];
1514 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)
1522 int mask, surfacemask = 0;
1523 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1525 bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
1526 tend = firsttriangle + numtris;
1527 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1529 // surface box entirely inside light box, no box cull
1530 if (projectdirection)
1532 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1534 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1535 TriangleNormal(v[0], v[1], v[2], normal);
1536 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1538 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1539 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1540 surfacemask |= mask;
1543 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;
1544 shadowsides[numshadowsides] = mask;
1545 shadowsideslist[numshadowsides++] = t;
1552 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1554 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1555 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]))
1557 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1558 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1559 surfacemask |= mask;
1562 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;
1563 shadowsides[numshadowsides] = mask;
1564 shadowsideslist[numshadowsides++] = t;
1572 // surface box not entirely inside light box, cull each triangle
1573 if (projectdirection)
1575 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1577 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1578 TriangleNormal(v[0], v[1], v[2], normal);
1579 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1580 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1582 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1583 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1584 surfacemask |= mask;
1587 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;
1588 shadowsides[numshadowsides] = mask;
1589 shadowsideslist[numshadowsides++] = t;
1596 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1598 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1599 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1600 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1602 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1603 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1604 surfacemask |= mask;
1607 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;
1608 shadowsides[numshadowsides] = mask;
1609 shadowsideslist[numshadowsides++] = t;
1618 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)
1620 int i, j, outtriangles = 0;
1621 int *outelement3i[6];
1622 if (!numverts || !numsidetris || !r_shadow_compilingrtlight)
1624 outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5];
1625 // make sure shadowelements is big enough for this mesh
1626 if (maxshadowtriangles < outtriangles)
1627 R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1);
1629 // compute the offset and size of the separate index lists for each cubemap side
1631 for (i = 0;i < 6;i++)
1633 outelement3i[i] = shadowelements + outtriangles * 3;
1634 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles;
1635 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i];
1636 outtriangles += sidetotals[i];
1639 // gather up the (sparse) triangles into separate index lists for each cubemap side
1640 for (i = 0;i < numsidetris;i++)
1642 const int *element = elements + sidetris[i] * 3;
1643 for (j = 0;j < 6;j++)
1645 if (sides[i] & (1 << j))
1647 outelement3i[j][0] = element[0];
1648 outelement3i[j][1] = element[1];
1649 outelement3i[j][2] = element[2];
1650 outelement3i[j] += 3;
1655 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, outtriangles, shadowelements);
1658 static void R_Shadow_MakeTextures_MakeCorona(void)
1662 unsigned char pixels[32][32][4];
1663 for (y = 0;y < 32;y++)
1665 dy = (y - 15.5f) * (1.0f / 16.0f);
1666 for (x = 0;x < 32;x++)
1668 dx = (x - 15.5f) * (1.0f / 16.0f);
1669 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1670 a = bound(0, a, 255);
1671 pixels[y][x][0] = a;
1672 pixels[y][x][1] = a;
1673 pixels[y][x][2] = a;
1674 pixels[y][x][3] = 255;
1677 r_shadow_lightcorona = R_SkinFrame_LoadInternalBGRA("lightcorona", TEXF_FORCELINEAR, &pixels[0][0][0], 32, 32);
1680 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1682 float dist = sqrt(x*x+y*y+z*z);
1683 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1684 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1685 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1688 static void R_Shadow_MakeTextures(void)
1691 float intensity, dist;
1693 R_Shadow_FreeShadowMaps();
1694 R_FreeTexturePool(&r_shadow_texturepool);
1695 r_shadow_texturepool = R_AllocTexturePool();
1696 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1697 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1698 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1699 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1700 for (x = 0;x <= ATTENTABLESIZE;x++)
1702 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1703 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1704 r_shadow_attentable[x] = bound(0, intensity, 1);
1706 // 1D gradient texture
1707 for (x = 0;x < ATTEN1DSIZE;x++)
1708 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1709 r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1710 // 2D circle texture
1711 for (y = 0;y < ATTEN2DSIZE;y++)
1712 for (x = 0;x < ATTEN2DSIZE;x++)
1713 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);
1714 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1715 // 3D sphere texture
1716 if (r_shadow_texture3d.integer && vid.support.ext_texture_3d)
1718 for (z = 0;z < ATTEN3DSIZE;z++)
1719 for (y = 0;y < ATTEN3DSIZE;y++)
1720 for (x = 0;x < ATTEN3DSIZE;x++)
1721 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));
1722 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1725 r_shadow_attenuation3dtexture = NULL;
1728 R_Shadow_MakeTextures_MakeCorona();
1730 // Editor light sprites
1731 r_editlights_sprcursor = R_SkinFrame_LoadInternal8bit("gfx/editlights/cursor", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1748 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1749 r_editlights_sprlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/light", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1766 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1767 r_editlights_sprnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/noshadow", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1784 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1785 r_editlights_sprcubemaplight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemaplight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1802 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1803 r_editlights_sprcubemapnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemapnoshadowlight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1820 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1821 r_editlights_sprselection = R_SkinFrame_LoadInternal8bit("gfx/editlights/selection", TEXF_ALPHA | TEXF_CLAMP, (unsigned char *)
1838 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1841 void R_Shadow_ValidateCvars(void)
1843 if (r_shadow_texture3d.integer && !vid.support.ext_texture_3d)
1844 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1845 if (gl_ext_separatestencil.integer && !vid.support.ati_separate_stencil)
1846 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
1847 if (gl_ext_stenciltwoside.integer && !vid.support.ext_stencil_two_side)
1848 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1851 void R_Shadow_RenderMode_Begin(void)
1857 R_Shadow_ValidateCvars();
1859 if (!r_shadow_attenuation2dtexture
1860 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1861 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1862 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1863 R_Shadow_MakeTextures();
1866 R_Mesh_ResetTextureState();
1867 GL_BlendFunc(GL_ONE, GL_ZERO);
1868 GL_DepthRange(0, 1);
1869 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1871 GL_DepthMask(false);
1872 GL_Color(0, 0, 0, 1);
1873 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1875 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1877 if (gl_ext_separatestencil.integer && vid.support.ati_separate_stencil)
1879 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
1880 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
1882 else if (gl_ext_stenciltwoside.integer && vid.support.ext_stencil_two_side)
1884 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
1885 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
1889 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
1890 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
1893 switch(vid.renderpath)
1895 case RENDERPATH_GL20:
1896 case RENDERPATH_D3D9:
1897 case RENDERPATH_D3D10:
1898 case RENDERPATH_D3D11:
1899 case RENDERPATH_SOFT:
1900 case RENDERPATH_GLES2:
1901 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1903 case RENDERPATH_GL13:
1904 case RENDERPATH_GL11:
1905 if (r_textureunits.integer >= 2 && vid.texunits >= 2 && r_shadow_texture3d.integer && r_shadow_attenuation3dtexture)
1906 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN;
1907 else if (r_textureunits.integer >= 3 && vid.texunits >= 3)
1908 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN;
1909 else if (r_textureunits.integer >= 2 && vid.texunits >= 2)
1910 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN;
1912 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1918 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
1919 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
1920 r_shadow_drawbuffer = drawbuffer;
1921 r_shadow_readbuffer = readbuffer;
1923 r_shadow_cullface_front = r_refdef.view.cullface_front;
1924 r_shadow_cullface_back = r_refdef.view.cullface_back;
1927 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
1929 rsurface.rtlight = rtlight;
1932 void R_Shadow_RenderMode_Reset(void)
1934 R_Mesh_ResetRenderTargets();
1935 R_SetViewport(&r_refdef.view.viewport);
1936 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
1937 R_Mesh_ResetTextureState();
1938 GL_DepthRange(0, 1);
1940 GL_DepthMask(false);
1941 GL_DepthFunc(GL_LEQUAL);
1942 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1943 r_refdef.view.cullface_front = r_shadow_cullface_front;
1944 r_refdef.view.cullface_back = r_shadow_cullface_back;
1945 GL_CullFace(r_refdef.view.cullface_back);
1946 GL_Color(1, 1, 1, 1);
1947 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
1948 GL_BlendFunc(GL_ONE, GL_ZERO);
1949 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
1950 r_shadow_usingshadowmap2d = false;
1951 r_shadow_usingshadowmaportho = false;
1952 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
1955 void R_Shadow_ClearStencil(void)
1957 GL_Clear(GL_STENCIL_BUFFER_BIT, NULL, 1.0f, 128);
1958 r_refdef.stats.lights_clears++;
1961 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
1963 r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
1964 if (r_shadow_rendermode == mode)
1966 R_Shadow_RenderMode_Reset();
1967 GL_DepthFunc(GL_LESS);
1968 GL_ColorMask(0, 0, 0, 0);
1969 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1970 GL_CullFace(GL_NONE);
1971 R_SetupShader_DepthOrShadow();
1972 r_shadow_rendermode = mode;
1977 case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
1978 case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
1979 R_SetStencilSeparate(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, GL_ALWAYS, 128, 255);
1981 case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
1982 case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
1983 R_SetStencilSeparate(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, GL_ALWAYS, 128, 255);
1988 static void R_Shadow_MakeVSDCT(void)
1990 // maps to a 2x3 texture rectangle with normalized coordinates
1995 // stores abs(dir.xy), offset.xy/2.5
1996 unsigned char data[4*6] =
1998 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
1999 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
2000 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
2001 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
2002 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
2003 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
2005 r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
2008 static void R_Shadow_MakeShadowMap(int side, int size)
2010 switch (r_shadow_shadowmode)
2012 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2013 if (r_shadow_shadowmap2dtexture) return;
2014 r_shadow_shadowmap2dtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "shadowmap", size*2, size*(vid.support.arb_texture_non_power_of_two ? 3 : 4), r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
2015 r_shadow_shadowmap2dcolortexture = NULL;
2016 switch(vid.renderpath)
2019 case RENDERPATH_D3D9:
2020 r_shadow_shadowmap2dcolortexture = R_LoadTexture2D(r_shadow_texturepool, "shadowmaprendertarget", size*2, size*(vid.support.arb_texture_non_power_of_two ? 3 : 4), NULL, TEXTYPE_BGRA, TEXF_RENDERTARGET | TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
2021 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
2025 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2dtexture, NULL, NULL, NULL, NULL);
2033 // render depth into the fbo, do not render color at all
2034 // validate the fbo now
2038 qglDrawBuffer(GL_NONE);CHECKGLERROR
2039 qglReadBuffer(GL_NONE);CHECKGLERROR
2040 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2041 if (status != GL_FRAMEBUFFER_COMPLETE_EXT && (r_shadow_shadowmapping.integer || r_shadow_deferred.integer))
2043 Con_Printf("R_Shadow_MakeShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2044 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2045 Cvar_SetValueQuick(&r_shadow_deferred, 0);
2050 void R_Shadow_RenderMode_ShadowMap(int side, int clear, int size)
2052 float nearclip, farclip, bias;
2053 r_viewport_t viewport;
2056 float clearcolor[4];
2057 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
2059 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
2060 r_shadow_shadowmap_parameters[1] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
2061 r_shadow_shadowmap_parameters[3] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
2062 r_shadow_shadowmapside = side;
2063 r_shadow_shadowmapsize = size;
2065 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2066 r_shadow_shadowmap_parameters[2] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2067 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
2068 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D) goto init_done;
2070 // complex unrolled cube approach (more flexible)
2071 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2072 R_Shadow_MakeVSDCT();
2073 if (!r_shadow_shadowmap2dtexture)
2074 R_Shadow_MakeShadowMap(side, r_shadow_shadowmapmaxsize);
2075 if (r_shadow_shadowmap2dtexture) fbo = r_shadow_fbo2d;
2076 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
2077 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
2078 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
2080 R_Mesh_ResetTextureState();
2081 R_Mesh_ResetRenderTargets();
2082 R_Shadow_RenderMode_Reset();
2085 R_Mesh_SetRenderTargets(fbo, r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
2086 R_SetupShader_DepthOrShadow();
2089 R_SetupShader_ShowDepth();
2090 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
2095 R_SetViewport(&viewport);
2096 flipped = (side & 1) ^ (side >> 2);
2097 r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
2098 r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
2099 switch(vid.renderpath)
2101 case RENDERPATH_GL11:
2102 case RENDERPATH_GL13:
2103 case RENDERPATH_GL20:
2104 case RENDERPATH_SOFT:
2105 case RENDERPATH_GLES2:
2106 GL_CullFace(r_refdef.view.cullface_back);
2107 // OpenGL lets us scissor larger than the viewport, so go ahead and clear all views at once
2108 if ((clear & ((2 << side) - 1)) == (1 << side)) // only clear if the side is the first in the mask
2110 // get tightest scissor rectangle that encloses all viewports in the clear mask
2111 int x1 = clear & 0x15 ? 0 : size;
2112 int x2 = clear & 0x2A ? 2 * size : size;
2113 int y1 = clear & 0x03 ? 0 : (clear & 0xC ? size : 2 * size);
2114 int y2 = clear & 0x30 ? 3 * size : (clear & 0xC ? 2 * size : size);
2115 GL_Scissor(x1, y1, x2 - x1, y2 - y1);
2116 GL_Clear(GL_DEPTH_BUFFER_BIT, NULL, 1.0f, 0);
2118 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2120 case RENDERPATH_D3D9:
2121 case RENDERPATH_D3D10:
2122 case RENDERPATH_D3D11:
2123 Vector4Set(clearcolor, 1,1,1,1);
2124 // completely different meaning than in OpenGL path
2125 r_shadow_shadowmap_parameters[1] = 0;
2126 r_shadow_shadowmap_parameters[3] = -bias;
2127 // we invert the cull mode because we flip the projection matrix
2128 // NOTE: this actually does nothing because the DrawShadowMap code sets it to doublesided...
2129 GL_CullFace(r_refdef.view.cullface_front);
2130 // D3D considers it an error to use a scissor larger than the viewport... clear just this view
2131 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2132 if (r_shadow_shadowmapsampler)
2134 GL_ColorMask(0,0,0,0);
2136 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
2140 GL_ColorMask(1,1,1,1);
2142 GL_Clear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
2148 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
2150 R_Mesh_ResetTextureState();
2151 R_Mesh_ResetRenderTargets();
2154 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2155 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2156 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2157 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2159 R_Shadow_RenderMode_Reset();
2160 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2162 GL_DepthFunc(GL_EQUAL);
2163 // do global setup needed for the chosen lighting mode
2164 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2165 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2166 r_shadow_usingshadowmap2d = shadowmapping;
2167 r_shadow_rendermode = r_shadow_lightingrendermode;
2168 // only draw light where this geometry was already rendered AND the
2169 // stencil is 128 (values other than this mean shadow)
2171 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2173 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
2176 static const unsigned short bboxelements[36] =
2186 static const float bboxpoints[8][3] =
2198 void R_Shadow_RenderMode_DrawDeferredLight(qboolean stenciltest, qboolean shadowmapping)
2201 float vertex3f[8*3];
2202 const matrix4x4_t *matrix = &rsurface.rtlight->matrix_lighttoworld;
2203 // do global setup needed for the chosen lighting mode
2204 R_Shadow_RenderMode_Reset();
2205 r_shadow_rendermode = r_shadow_lightingrendermode;
2206 R_EntityMatrix(&identitymatrix);
2207 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2208 // only draw light where this geometry was already rendered AND the
2209 // stencil is 128 (values other than this mean shadow)
2210 R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2211 R_Mesh_SetRenderTargets(r_shadow_prepasslightingfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
2213 r_shadow_usingshadowmap2d = shadowmapping;
2215 // render the lighting
2216 R_SetupShader_DeferredLight(rsurface.rtlight);
2217 for (i = 0;i < 8;i++)
2218 Matrix4x4_Transform(matrix, bboxpoints[i], vertex3f + i*3);
2219 GL_ColorMask(1,1,1,1);
2220 GL_DepthMask(false);
2221 GL_DepthRange(0, 1);
2222 GL_PolygonOffset(0, 0);
2224 GL_DepthFunc(GL_GREATER);
2225 GL_CullFace(r_refdef.view.cullface_back);
2226 R_Mesh_PrepareVertices_Vertex3f(8, vertex3f, NULL);
2227 R_Mesh_Draw(0, 8, 0, 12, NULL, NULL, 0, bboxelements, NULL, 0);
2230 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
2232 R_Shadow_RenderMode_Reset();
2233 GL_BlendFunc(GL_ONE, GL_ONE);
2234 GL_DepthRange(0, 1);
2235 GL_DepthTest(r_showshadowvolumes.integer < 2);
2236 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
2237 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2238 GL_CullFace(GL_NONE);
2239 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
2242 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
2244 R_Shadow_RenderMode_Reset();
2245 GL_BlendFunc(GL_ONE, GL_ONE);
2246 GL_DepthRange(0, 1);
2247 GL_DepthTest(r_showlighting.integer < 2);
2248 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2250 GL_DepthFunc(GL_EQUAL);
2251 R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2252 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2255 void R_Shadow_RenderMode_End(void)
2257 R_Shadow_RenderMode_Reset();
2258 R_Shadow_RenderMode_ActiveLight(NULL);
2260 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2261 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2264 int bboxedges[12][2] =
2283 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2285 if (!r_shadow_scissor.integer)
2287 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2288 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2289 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2290 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2293 if(R_ScissorForBBox(mins, maxs, r_shadow_lightscissor))
2294 return true; // invisible
2295 if(r_shadow_lightscissor[0] != r_refdef.view.viewport.x
2296 || r_shadow_lightscissor[1] != r_refdef.view.viewport.y
2297 || r_shadow_lightscissor[2] != r_refdef.view.viewport.width
2298 || r_shadow_lightscissor[3] != r_refdef.view.viewport.height)
2299 r_refdef.stats.lights_scissored++;
2303 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, const float *diffusecolor, const float *ambientcolor)
2306 const float *vertex3f;
2307 const float *normal3f;
2309 float dist, dot, distintensity, shadeintensity, v[3], n[3];
2310 switch (r_shadow_rendermode)
2312 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2313 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2314 if (VectorLength2(diffusecolor) > 0)
2316 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, normal3f = rsurface.batchnormal3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, normal3f += 3, color4f += 4)
2318 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2319 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2320 if ((dot = DotProduct(n, v)) < 0)
2322 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2323 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
2326 VectorCopy(ambientcolor, color4f);
2327 if (r_refdef.fogenabled)
2330 f = RSurf_FogVertex(vertex3f);
2331 VectorScale(color4f, f, color4f);
2338 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
2340 VectorCopy(ambientcolor, color4f);
2341 if (r_refdef.fogenabled)
2344 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2345 f = RSurf_FogVertex(vertex3f);
2346 VectorScale(color4f + 4*i, f, color4f);
2352 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2353 if (VectorLength2(diffusecolor) > 0)
2355 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, normal3f = rsurface.batchnormal3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, normal3f += 3, color4f += 4)
2357 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2358 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2360 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2361 if ((dot = DotProduct(n, v)) < 0)
2363 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2364 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2365 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2366 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2370 color4f[0] = ambientcolor[0] * distintensity;
2371 color4f[1] = ambientcolor[1] * distintensity;
2372 color4f[2] = ambientcolor[2] * distintensity;
2374 if (r_refdef.fogenabled)
2377 f = RSurf_FogVertex(vertex3f);
2378 VectorScale(color4f, f, color4f);
2382 VectorClear(color4f);
2388 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
2390 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2391 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2393 color4f[0] = ambientcolor[0] * distintensity;
2394 color4f[1] = ambientcolor[1] * distintensity;
2395 color4f[2] = ambientcolor[2] * distintensity;
2396 if (r_refdef.fogenabled)
2399 f = RSurf_FogVertex(vertex3f);
2400 VectorScale(color4f, f, color4f);
2404 VectorClear(color4f);
2409 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2410 if (VectorLength2(diffusecolor) > 0)
2412 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, normal3f = rsurface.batchnormal3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, normal3f += 3, color4f += 4)
2414 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2415 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2417 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2418 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2419 if ((dot = DotProduct(n, v)) < 0)
2421 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2422 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2423 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2424 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2428 color4f[0] = ambientcolor[0] * distintensity;
2429 color4f[1] = ambientcolor[1] * distintensity;
2430 color4f[2] = ambientcolor[2] * distintensity;
2432 if (r_refdef.fogenabled)
2435 f = RSurf_FogVertex(vertex3f);
2436 VectorScale(color4f, f, color4f);
2440 VectorClear(color4f);
2446 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
2448 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2449 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2451 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2452 color4f[0] = ambientcolor[0] * distintensity;
2453 color4f[1] = ambientcolor[1] * distintensity;
2454 color4f[2] = ambientcolor[2] * distintensity;
2455 if (r_refdef.fogenabled)
2458 f = RSurf_FogVertex(vertex3f);
2459 VectorScale(color4f, f, color4f);
2463 VectorClear(color4f);
2473 static void R_Shadow_RenderLighting_VisibleLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
2475 // used to display how many times a surface is lit for level design purposes
2476 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
2477 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
2481 static void R_Shadow_RenderLighting_Light_GLSL(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale, float specularscale)
2483 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2484 R_SetupShader_Surface(lightcolor, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT, texturenumsurfaces, texturesurfacelist, NULL);
2485 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2486 GL_DepthFunc(GL_EQUAL);
2488 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2489 GL_DepthFunc(GL_LEQUAL);
2492 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
2499 int newnumtriangles;
2503 int maxtriangles = 4096;
2504 static int newelements[4096*3];
2505 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, diffusecolor2, ambientcolor2);
2506 for (renders = 0;renders < 4;renders++)
2511 newnumtriangles = 0;
2513 // due to low fillrate on the cards this vertex lighting path is
2514 // designed for, we manually cull all triangles that do not
2515 // contain a lit vertex
2516 // this builds batches of triangles from multiple surfaces and
2517 // renders them at once
2518 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
2520 if (VectorLength2(rsurface.passcolor4f + e[0] * 4) + VectorLength2(rsurface.passcolor4f + e[1] * 4) + VectorLength2(rsurface.passcolor4f + e[2] * 4) >= 0.01)
2522 if (newnumtriangles)
2524 newfirstvertex = min(newfirstvertex, e[0]);
2525 newlastvertex = max(newlastvertex, e[0]);
2529 newfirstvertex = e[0];
2530 newlastvertex = e[0];
2532 newfirstvertex = min(newfirstvertex, e[1]);
2533 newlastvertex = max(newlastvertex, e[1]);
2534 newfirstvertex = min(newfirstvertex, e[2]);
2535 newlastvertex = max(newlastvertex, e[2]);
2541 if (newnumtriangles >= maxtriangles)
2543 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
2544 newnumtriangles = 0;
2550 if (newnumtriangles >= 1)
2552 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
2555 // if we couldn't find any lit triangles, exit early
2558 // now reduce the intensity for the next overbright pass
2559 // we have to clamp to 0 here incase the drivers have improper
2560 // handling of negative colors
2561 // (some old drivers even have improper handling of >1 color)
2563 for (i = 0, c = rsurface.passcolor4f + 4 * firstvertex;i < numvertices;i++, c += 4)
2565 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
2567 c[0] = max(0, c[0] - 1);
2568 c[1] = max(0, c[1] - 1);
2569 c[2] = max(0, c[2] - 1);
2581 static void R_Shadow_RenderLighting_Light_Vertex(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale)
2583 // OpenGL 1.1 path (anything)
2584 float ambientcolorbase[3], diffusecolorbase[3];
2585 float ambientcolorpants[3], diffusecolorpants[3];
2586 float ambientcolorshirt[3], diffusecolorshirt[3];
2587 const float *surfacecolor = rsurface.texture->dlightcolor;
2588 const float *surfacepants = rsurface.colormap_pantscolor;
2589 const float *surfaceshirt = rsurface.colormap_shirtcolor;
2590 rtexture_t *basetexture = rsurface.texture->basetexture;
2591 rtexture_t *pantstexture = rsurface.texture->pantstexture;
2592 rtexture_t *shirttexture = rsurface.texture->shirttexture;
2593 qboolean dopants = pantstexture && VectorLength2(surfacepants) >= (1.0f / 1048576.0f);
2594 qboolean doshirt = shirttexture && VectorLength2(surfaceshirt) >= (1.0f / 1048576.0f);
2595 ambientscale *= 2 * r_refdef.view.colorscale;
2596 diffusescale *= 2 * r_refdef.view.colorscale;
2597 ambientcolorbase[0] = lightcolor[0] * ambientscale * surfacecolor[0];ambientcolorbase[1] = lightcolor[1] * ambientscale * surfacecolor[1];ambientcolorbase[2] = lightcolor[2] * ambientscale * surfacecolor[2];
2598 diffusecolorbase[0] = lightcolor[0] * diffusescale * surfacecolor[0];diffusecolorbase[1] = lightcolor[1] * diffusescale * surfacecolor[1];diffusecolorbase[2] = lightcolor[2] * diffusescale * surfacecolor[2];
2599 ambientcolorpants[0] = ambientcolorbase[0] * surfacepants[0];ambientcolorpants[1] = ambientcolorbase[1] * surfacepants[1];ambientcolorpants[2] = ambientcolorbase[2] * surfacepants[2];
2600 diffusecolorpants[0] = diffusecolorbase[0] * surfacepants[0];diffusecolorpants[1] = diffusecolorbase[1] * surfacepants[1];diffusecolorpants[2] = diffusecolorbase[2] * surfacepants[2];
2601 ambientcolorshirt[0] = ambientcolorbase[0] * surfaceshirt[0];ambientcolorshirt[1] = ambientcolorbase[1] * surfaceshirt[1];ambientcolorshirt[2] = ambientcolorbase[2] * surfaceshirt[2];
2602 diffusecolorshirt[0] = diffusecolorbase[0] * surfaceshirt[0];diffusecolorshirt[1] = diffusecolorbase[1] * surfaceshirt[1];diffusecolorshirt[2] = diffusecolorbase[2] * surfaceshirt[2];
2603 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | (diffusescale > 0 ? BATCHNEED_ARRAY_NORMAL : 0) | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
2604 rsurface.passcolor4f = (float *)R_FrameData_Alloc((rsurface.batchfirstvertex + rsurface.batchnumvertices) * sizeof(float[4]));
2605 R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
2606 R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.passcolor4f, 0, 0);
2607 R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
2608 R_Mesh_TexBind(0, basetexture);
2609 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
2610 R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
2611 switch(r_shadow_rendermode)
2613 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2614 R_Mesh_TexBind(1, r_shadow_attenuation3dtexture);
2615 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
2616 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
2617 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
2619 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2620 R_Mesh_TexBind(2, r_shadow_attenuation2dtexture);
2621 R_Mesh_TexMatrix(2, &rsurface.entitytoattenuationz);
2622 R_Mesh_TexCombine(2, GL_MODULATE, GL_MODULATE, 1, 1);
2623 R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
2625 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2626 R_Mesh_TexBind(1, r_shadow_attenuation2dtexture);
2627 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
2628 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
2629 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
2631 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2636 //R_Mesh_TexBind(0, basetexture);
2637 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorbase, ambientcolorbase);
2640 R_Mesh_TexBind(0, pantstexture);
2641 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorpants, ambientcolorpants);
2645 R_Mesh_TexBind(0, shirttexture);
2646 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorshirt, ambientcolorshirt);
2650 extern cvar_t gl_lightmaps;
2651 void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
2653 float ambientscale, diffusescale, specularscale;
2655 float lightcolor[3];
2656 VectorCopy(rsurface.rtlight->currentcolor, lightcolor);
2657 ambientscale = rsurface.rtlight->ambientscale;
2658 diffusescale = rsurface.rtlight->diffusescale;
2659 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
2660 if (!r_shadow_usenormalmap.integer)
2662 ambientscale += 1.0f * diffusescale;
2666 if ((ambientscale + diffusescale) * VectorLength2(lightcolor) + specularscale * VectorLength2(lightcolor) < (1.0f / 1048576.0f))
2668 negated = (lightcolor[0] + lightcolor[1] + lightcolor[2] < 0) && vid.support.ext_blend_subtract;
2671 VectorNegate(lightcolor, lightcolor);
2672 switch(vid.renderpath)
2674 case RENDERPATH_GL11:
2675 case RENDERPATH_GL13:
2676 case RENDERPATH_GL20:
2677 case RENDERPATH_GLES2:
2678 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
2680 case RENDERPATH_D3D9:
2682 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_SUBTRACT);
2685 case RENDERPATH_D3D10:
2686 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2688 case RENDERPATH_D3D11:
2689 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2691 case RENDERPATH_SOFT:
2692 DPSOFTRAST_BlendSubtract(true);
2696 RSurf_SetupDepthAndCulling();
2697 switch (r_shadow_rendermode)
2699 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2700 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2701 R_Shadow_RenderLighting_VisibleLighting(texturenumsurfaces, texturesurfacelist);
2703 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2704 R_Shadow_RenderLighting_Light_GLSL(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale, specularscale);
2706 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2707 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2708 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2709 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2710 R_Shadow_RenderLighting_Light_Vertex(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale);
2713 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2718 switch(vid.renderpath)
2720 case RENDERPATH_GL11:
2721 case RENDERPATH_GL13:
2722 case RENDERPATH_GL20:
2723 case RENDERPATH_GLES2:
2724 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
2726 case RENDERPATH_D3D9:
2728 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_ADD);
2731 case RENDERPATH_D3D10:
2732 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2734 case RENDERPATH_D3D11:
2735 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2737 case RENDERPATH_SOFT:
2738 DPSOFTRAST_BlendSubtract(false);
2744 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)
2746 matrix4x4_t tempmatrix = *matrix;
2747 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
2749 // if this light has been compiled before, free the associated data
2750 R_RTLight_Uncompile(rtlight);
2752 // clear it completely to avoid any lingering data
2753 memset(rtlight, 0, sizeof(*rtlight));
2755 // copy the properties
2756 rtlight->matrix_lighttoworld = tempmatrix;
2757 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
2758 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
2759 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
2760 VectorCopy(color, rtlight->color);
2761 rtlight->cubemapname[0] = 0;
2762 if (cubemapname && cubemapname[0])
2763 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
2764 rtlight->shadow = shadow;
2765 rtlight->corona = corona;
2766 rtlight->style = style;
2767 rtlight->isstatic = isstatic;
2768 rtlight->coronasizescale = coronasizescale;
2769 rtlight->ambientscale = ambientscale;
2770 rtlight->diffusescale = diffusescale;
2771 rtlight->specularscale = specularscale;
2772 rtlight->flags = flags;
2774 // compute derived data
2775 //rtlight->cullradius = rtlight->radius;
2776 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2777 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2778 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2779 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2780 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2781 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2782 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2785 // compiles rtlight geometry
2786 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2787 void R_RTLight_Compile(rtlight_t *rtlight)
2790 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
2791 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
2792 entity_render_t *ent = r_refdef.scene.worldentity;
2793 dp_model_t *model = r_refdef.scene.worldmodel;
2794 unsigned char *data;
2797 // compile the light
2798 rtlight->compiled = true;
2799 rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
2800 rtlight->static_numleafs = 0;
2801 rtlight->static_numleafpvsbytes = 0;
2802 rtlight->static_leaflist = NULL;
2803 rtlight->static_leafpvs = NULL;
2804 rtlight->static_numsurfaces = 0;
2805 rtlight->static_surfacelist = NULL;
2806 rtlight->static_shadowmap_receivers = 0x3F;
2807 rtlight->static_shadowmap_casters = 0x3F;
2808 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2809 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2810 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2811 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2812 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2813 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2815 if (model && model->GetLightInfo)
2817 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
2818 r_shadow_compilingrtlight = rtlight;
2819 R_FrameData_SetMark();
2820 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);
2821 R_FrameData_ReturnToMark();
2822 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2823 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
2824 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
2825 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
2826 rtlight->static_numsurfaces = numsurfaces;
2827 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
2828 rtlight->static_numleafs = numleafs;
2829 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
2830 rtlight->static_numleafpvsbytes = numleafpvsbytes;
2831 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
2832 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
2833 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
2834 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
2835 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
2836 if (rtlight->static_numsurfaces)
2837 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
2838 if (rtlight->static_numleafs)
2839 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
2840 if (rtlight->static_numleafpvsbytes)
2841 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
2842 if (rtlight->static_numshadowtrispvsbytes)
2843 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
2844 if (rtlight->static_numlighttrispvsbytes)
2845 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
2846 R_FrameData_SetMark();
2847 switch (rtlight->shadowmode)
2849 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2850 if (model->CompileShadowMap && rtlight->shadow)
2851 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2854 if (model->CompileShadowVolume && rtlight->shadow)
2855 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2858 R_FrameData_ReturnToMark();
2859 // now we're done compiling the rtlight
2860 r_shadow_compilingrtlight = NULL;
2864 // use smallest available cullradius - box radius or light radius
2865 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2866 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2868 shadowzpasstris = 0;
2869 if (rtlight->static_meshchain_shadow_zpass)
2870 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
2871 shadowzpasstris += mesh->numtriangles;
2873 shadowzfailtris = 0;
2874 if (rtlight->static_meshchain_shadow_zfail)
2875 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
2876 shadowzfailtris += mesh->numtriangles;
2879 if (rtlight->static_numlighttrispvsbytes)
2880 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
2881 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
2885 if (rtlight->static_numlighttrispvsbytes)
2886 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
2887 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
2890 if (developer_extra.integer)
2891 Con_DPrintf("static light built: %f %f %f : %f %f %f box, %i light triangles, %i shadow triangles, %i zpass/%i zfail compiled shadow volume triangles\n", rtlight->cullmins[0], rtlight->cullmins[1], rtlight->cullmins[2], rtlight->cullmaxs[0], rtlight->cullmaxs[1], rtlight->cullmaxs[2], lighttris, shadowtris, shadowzpasstris, shadowzfailtris);
2894 void R_RTLight_Uncompile(rtlight_t *rtlight)
2896 if (rtlight->compiled)
2898 if (rtlight->static_meshchain_shadow_zpass)
2899 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
2900 rtlight->static_meshchain_shadow_zpass = NULL;
2901 if (rtlight->static_meshchain_shadow_zfail)
2902 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
2903 rtlight->static_meshchain_shadow_zfail = NULL;
2904 if (rtlight->static_meshchain_shadow_shadowmap)
2905 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
2906 rtlight->static_meshchain_shadow_shadowmap = NULL;
2907 // these allocations are grouped
2908 if (rtlight->static_surfacelist)
2909 Mem_Free(rtlight->static_surfacelist);
2910 rtlight->static_numleafs = 0;
2911 rtlight->static_numleafpvsbytes = 0;
2912 rtlight->static_leaflist = NULL;
2913 rtlight->static_leafpvs = NULL;
2914 rtlight->static_numsurfaces = 0;
2915 rtlight->static_surfacelist = NULL;
2916 rtlight->static_numshadowtrispvsbytes = 0;
2917 rtlight->static_shadowtrispvs = NULL;
2918 rtlight->static_numlighttrispvsbytes = 0;
2919 rtlight->static_lighttrispvs = NULL;
2920 rtlight->compiled = false;
2924 void R_Shadow_UncompileWorldLights(void)
2928 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
2929 for (lightindex = 0;lightindex < range;lightindex++)
2931 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2934 R_RTLight_Uncompile(&light->rtlight);
2938 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
2942 // reset the count of frustum planes
2943 // see rtlight->cached_frustumplanes definition for how much this array
2945 rtlight->cached_numfrustumplanes = 0;
2947 // haven't implemented a culling path for ortho rendering
2948 if (!r_refdef.view.useperspective)
2950 // check if the light is on screen and copy the 4 planes if it is
2951 for (i = 0;i < 4;i++)
2952 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
2955 for (i = 0;i < 4;i++)
2956 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
2961 // generate a deformed frustum that includes the light origin, this is
2962 // used to cull shadow casting surfaces that can not possibly cast a
2963 // shadow onto the visible light-receiving surfaces, which can be a
2966 // if the light origin is onscreen the result will be 4 planes exactly
2967 // if the light origin is offscreen on only one axis the result will
2968 // be exactly 5 planes (split-side case)
2969 // if the light origin is offscreen on two axes the result will be
2970 // exactly 4 planes (stretched corner case)
2971 for (i = 0;i < 4;i++)
2973 // quickly reject standard frustum planes that put the light
2974 // origin outside the frustum
2975 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
2978 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
2980 // if all the standard frustum planes were accepted, the light is onscreen
2981 // otherwise we need to generate some more planes below...
2982 if (rtlight->cached_numfrustumplanes < 4)
2984 // at least one of the stock frustum planes failed, so we need to
2985 // create one or two custom planes to enclose the light origin
2986 for (i = 0;i < 4;i++)
2988 // create a plane using the view origin and light origin, and a
2989 // single point from the frustum corner set
2990 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
2991 VectorNormalize(plane.normal);
2992 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
2993 // see if this plane is backwards and flip it if so
2994 for (j = 0;j < 4;j++)
2995 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
2999 VectorNegate(plane.normal, plane.normal);
3001 // flipped plane, test again to see if it is now valid
3002 for (j = 0;j < 4;j++)
3003 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3005 // if the plane is still not valid, then it is dividing the
3006 // frustum and has to be rejected
3010 // we have created a valid plane, compute extra info
3011 PlaneClassify(&plane);
3013 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3015 // if we've found 5 frustum planes then we have constructed a
3016 // proper split-side case and do not need to keep searching for
3017 // planes to enclose the light origin
3018 if (rtlight->cached_numfrustumplanes == 5)
3026 for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
3028 plane = rtlight->cached_frustumplanes[i];
3029 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));
3034 // now add the light-space box planes if the light box is rotated, as any
3035 // caster outside the oriented light box is irrelevant (even if it passed
3036 // the worldspace light box, which is axial)
3037 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3039 for (i = 0;i < 6;i++)
3043 v[i >> 1] = (i & 1) ? -1 : 1;
3044 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3045 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3046 plane.dist = VectorNormalizeLength(plane.normal);
3047 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3048 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3054 // add the world-space reduced box planes
3055 for (i = 0;i < 6;i++)
3057 VectorClear(plane.normal);
3058 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3059 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
3060 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3069 // reduce all plane distances to tightly fit the rtlight cull box, which
3071 VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3072 VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3073 VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3074 VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3075 VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3076 VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3077 VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3078 VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3079 oldnum = rtlight->cached_numfrustumplanes;
3080 rtlight->cached_numfrustumplanes = 0;
3081 for (j = 0;j < oldnum;j++)
3083 // find the nearest point on the box to this plane
3084 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
3085 for (i = 1;i < 8;i++)
3087 dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
3088 if (bestdist > dist)
3091 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);
3092 // if the nearest point is near or behind the plane, we want this
3093 // plane, otherwise the plane is useless as it won't cull anything
3094 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
3096 PlaneClassify(&rtlight->cached_frustumplanes[j]);
3097 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
3104 void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
3108 RSurf_ActiveWorldEntity();
3110 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3113 GL_CullFace(GL_NONE);
3114 mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3115 for (;mesh;mesh = mesh->next)
3117 if (!mesh->sidetotals[r_shadow_shadowmapside])
3119 r_refdef.stats.lights_shadowtriangles += mesh->sidetotals[r_shadow_shadowmapside];
3120 if (mesh->vertex3fbuffer)
3121 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vertex3fbuffer);
3123 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer);
3124 R_Mesh_Draw(0, mesh->numverts, mesh->sideoffsets[r_shadow_shadowmapside], mesh->sidetotals[r_shadow_shadowmapside], mesh->element3i, mesh->element3i_indexbuffer, mesh->element3i_bufferoffset, mesh->element3s, mesh->element3s_indexbuffer, mesh->element3s_bufferoffset);
3128 else if (r_refdef.scene.worldentity->model)
3129 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);
3131 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3134 void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3136 qboolean zpass = false;
3139 int surfacelistindex;
3140 msurface_t *surface;
3142 // if triangle neighbors are disabled, shadowvolumes are disabled
3143 if (r_refdef.scene.worldmodel->brush.shadowmesh ? !r_refdef.scene.worldmodel->brush.shadowmesh->neighbor3i : !r_refdef.scene.worldmodel->surfmesh.data_neighbor3i)
3146 RSurf_ActiveWorldEntity();
3148 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3151 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
3153 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
3154 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
3156 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
3157 for (;mesh;mesh = mesh->next)
3159 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
3160 if (mesh->vertex3fbuffer)
3161 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vertex3fbuffer);
3163 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer);
3164 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
3166 // increment stencil if frontface is infront of depthbuffer
3167 GL_CullFace(r_refdef.view.cullface_back);
3168 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
3169 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3i_indexbuffer, mesh->element3i_bufferoffset, mesh->element3s, mesh->element3s_indexbuffer, mesh->element3s_bufferoffset);
3170 // decrement stencil if backface is infront of depthbuffer
3171 GL_CullFace(r_refdef.view.cullface_front);
3172 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
3174 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
3176 // decrement stencil if backface is behind depthbuffer
3177 GL_CullFace(r_refdef.view.cullface_front);
3178 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
3179 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3i_indexbuffer, mesh->element3i_bufferoffset, mesh->element3s, mesh->element3s_indexbuffer, mesh->element3s_bufferoffset);
3180 // increment stencil if frontface is behind depthbuffer
3181 GL_CullFace(r_refdef.view.cullface_back);
3182 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
3184 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3i_indexbuffer, mesh->element3i_bufferoffset, mesh->element3s, mesh->element3s_indexbuffer, mesh->element3s_bufferoffset);
3188 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh)
3190 // use the shadow trispvs calculated earlier by GetLightInfo to cull world triangles on this dynamic light
3191 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
3192 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
3194 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
3195 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
3196 if (CHECKPVSBIT(trispvs, t))
3197 shadowmarklist[numshadowmark++] = t;
3199 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);
3201 else if (numsurfaces)
3203 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);
3206 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3209 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3211 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3212 vec_t relativeshadowradius;
3213 RSurf_ActiveModelEntity(ent, false, false, false);
3214 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3215 // we need to re-init the shader for each entity because the matrix changed
3216 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3217 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3218 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3219 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3220 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3221 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3222 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3223 switch (r_shadow_rendermode)
3225 case R_SHADOW_RENDERMODE_SHADOWMAP2D:
3226 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
3229 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3232 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3235 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3237 // set up properties for rendering light onto this entity
3238 RSurf_ActiveModelEntity(ent, true, true, false);
3239 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3240 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3241 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3242 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3245 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
3247 if (!r_refdef.scene.worldmodel->DrawLight)
3250 // set up properties for rendering light onto this entity
3251 RSurf_ActiveWorldEntity();
3252 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3253 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3254 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3255 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3257 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
3259 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3262 void R_Shadow_DrawEntityLight(entity_render_t *ent)
3264 dp_model_t *model = ent->model;
3265 if (!model->DrawLight)
3268 R_Shadow_SetupEntityLight(ent);
3270 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3272 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3275 void R_Shadow_PrepareLight(rtlight_t *rtlight)
3279 int numleafs, numsurfaces;
3280 int *leaflist, *surfacelist;
3281 unsigned char *leafpvs;
3282 unsigned char *shadowtrispvs;
3283 unsigned char *lighttrispvs;
3284 //unsigned char *surfacesides;
3285 int numlightentities;
3286 int numlightentities_noselfshadow;
3287 int numshadowentities;
3288 int numshadowentities_noselfshadow;
3289 static entity_render_t *lightentities[MAX_EDICTS];
3290 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3291 static entity_render_t *shadowentities[MAX_EDICTS];
3292 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3295 rtlight->draw = false;
3297 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3298 // skip lights that are basically invisible (color 0 0 0)
3299 nolight = VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f);
3301 // loading is done before visibility checks because loading should happen
3302 // all at once at the start of a level, not when it stalls gameplay.
3303 // (especially important to benchmarks)
3305 if (rtlight->isstatic && !nolight && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
3307 if (rtlight->compiled)
3308 R_RTLight_Uncompile(rtlight);
3309 R_RTLight_Compile(rtlight);
3313 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
3315 // look up the light style value at this time
3316 f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3317 VectorScale(rtlight->color, f, rtlight->currentcolor);
3319 if (rtlight->selected)
3321 f = 2 + sin(realtime * M_PI * 4.0);
3322 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3326 // if lightstyle is currently off, don't draw the light
3327 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3330 // skip processing on corona-only lights
3334 // if the light box is offscreen, skip it
3335 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3338 VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
3339 VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
3341 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3343 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3345 // compiled light, world available and can receive realtime lighting
3346 // retrieve leaf information
3347 numleafs = rtlight->static_numleafs;
3348 leaflist = rtlight->static_leaflist;
3349 leafpvs = rtlight->static_leafpvs;
3350 numsurfaces = rtlight->static_numsurfaces;
3351 surfacelist = rtlight->static_surfacelist;
3352 //surfacesides = NULL;
3353 shadowtrispvs = rtlight->static_shadowtrispvs;
3354 lighttrispvs = rtlight->static_lighttrispvs;
3356 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3358 // dynamic light, world available and can receive realtime lighting
3359 // calculate lit surfaces and leafs
3360 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);
3361 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3362 leaflist = r_shadow_buffer_leaflist;
3363 leafpvs = r_shadow_buffer_leafpvs;
3364 surfacelist = r_shadow_buffer_surfacelist;
3365 //surfacesides = r_shadow_buffer_surfacesides;
3366 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3367 lighttrispvs = r_shadow_buffer_lighttrispvs;
3368 // if the reduced leaf bounds are offscreen, skip it
3369 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3380 //surfacesides = NULL;
3381 shadowtrispvs = NULL;
3382 lighttrispvs = NULL;
3384 // check if light is illuminating any visible leafs
3387 for (i = 0;i < numleafs;i++)
3388 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3394 // make a list of lit entities and shadow casting entities
3395 numlightentities = 0;
3396 numlightentities_noselfshadow = 0;
3397 numshadowentities = 0;
3398 numshadowentities_noselfshadow = 0;
3400 // add dynamic entities that are lit by the light
3401 for (i = 0;i < r_refdef.scene.numentities;i++)
3404 entity_render_t *ent = r_refdef.scene.entities[i];
3406 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3408 // skip the object entirely if it is not within the valid
3409 // shadow-casting region (which includes the lit region)
3410 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
3412 if (!(model = ent->model))
3414 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
3416 // this entity wants to receive light, is visible, and is
3417 // inside the light box
3418 // TODO: check if the surfaces in the model can receive light
3419 // so now check if it's in a leaf seen by the light
3420 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))
3422 if (ent->flags & RENDER_NOSELFSHADOW)
3423 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
3425 lightentities[numlightentities++] = ent;
3426 // since it is lit, it probably also casts a shadow...
3427 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3428 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3429 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3431 // note: exterior models without the RENDER_NOSELFSHADOW
3432 // flag still create a RENDER_NOSELFSHADOW shadow but
3433 // are lit normally, this means that they are
3434 // self-shadowing but do not shadow other
3435 // RENDER_NOSELFSHADOW entities such as the gun
3436 // (very weird, but keeps the player shadow off the gun)
3437 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3438 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3440 shadowentities[numshadowentities++] = ent;
3443 else if (ent->flags & RENDER_SHADOW)
3445 // this entity is not receiving light, but may still need to
3447 // TODO: check if the surfaces in the model can cast shadow
3448 // now check if it is in a leaf seen by the light
3449 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))
3451 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3452 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3453 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3455 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3456 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3458 shadowentities[numshadowentities++] = ent;
3463 // return if there's nothing at all to light
3464 if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
3467 // count this light in the r_speeds
3468 r_refdef.stats.lights++;
3470 // flag it as worth drawing later
3471 rtlight->draw = true;
3473 // cache all the animated entities that cast a shadow but are not visible
3474 for (i = 0;i < numshadowentities;i++)
3475 if (!shadowentities[i]->animcache_vertex3f)
3476 R_AnimCache_GetEntity(shadowentities[i], false, false);
3477 for (i = 0;i < numshadowentities_noselfshadow;i++)
3478 if (!shadowentities_noselfshadow[i]->animcache_vertex3f)
3479 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
3481 // allocate some temporary memory for rendering this light later in the frame
3482 // reusable buffers need to be copied, static data can be used as-is
3483 rtlight->cached_numlightentities = numlightentities;
3484 rtlight->cached_numlightentities_noselfshadow = numlightentities_noselfshadow;
3485 rtlight->cached_numshadowentities = numshadowentities;
3486 rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
3487 rtlight->cached_numsurfaces = numsurfaces;
3488 rtlight->cached_lightentities = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
3489 rtlight->cached_lightentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
3490 rtlight->cached_shadowentities = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
3491 rtlight->cached_shadowentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
3492 if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
3494 int numshadowtrispvsbytes = (((r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles) + 7) >> 3);
3495 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
3496 rtlight->cached_shadowtrispvs = (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
3497 rtlight->cached_lighttrispvs = (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
3498 rtlight->cached_surfacelist = (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
3502 // compiled light data
3503 rtlight->cached_shadowtrispvs = shadowtrispvs;
3504 rtlight->cached_lighttrispvs = lighttrispvs;
3505 rtlight->cached_surfacelist = surfacelist;
3509 void R_Shadow_DrawLight(rtlight_t *rtlight)
3513 unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
3514 int numlightentities;
3515 int numlightentities_noselfshadow;
3516 int numshadowentities;
3517 int numshadowentities_noselfshadow;
3518 entity_render_t **lightentities;
3519 entity_render_t **lightentities_noselfshadow;
3520 entity_render_t **shadowentities;
3521 entity_render_t **shadowentities_noselfshadow;
3523 static unsigned char entitysides[MAX_EDICTS];
3524 static unsigned char entitysides_noselfshadow[MAX_EDICTS];
3525 vec3_t nearestpoint;
3527 qboolean castshadows;
3530 // check if we cached this light this frame (meaning it is worth drawing)
3534 numlightentities = rtlight->cached_numlightentities;
3535 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
3536 numshadowentities = rtlight->cached_numshadowentities;
3537 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
3538 numsurfaces = rtlight->cached_numsurfaces;
3539 lightentities = rtlight->cached_lightentities;
3540 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
3541 shadowentities = rtlight->cached_shadowentities;
3542 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
3543 shadowtrispvs = rtlight->cached_shadowtrispvs;
3544 lighttrispvs = rtlight->cached_lighttrispvs;
3545 surfacelist = rtlight->cached_surfacelist;
3547 // set up a scissor rectangle for this light
3548 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3551 // don't let sound skip if going slow
3552 if (r_refdef.scene.extraupdate)
3555 // make this the active rtlight for rendering purposes
3556 R_Shadow_RenderMode_ActiveLight(rtlight);
3558 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
3560 // optionally draw visible shape of the shadow volumes
3561 // for performance analysis by level designers
3562 R_Shadow_RenderMode_VisibleShadowVolumes();
3564 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
3565 for (i = 0;i < numshadowentities;i++)
3566 R_Shadow_DrawEntityShadow(shadowentities[i]);
3567 for (i = 0;i < numshadowentities_noselfshadow;i++)
3568 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3569 R_Shadow_RenderMode_VisibleLighting(false, false);
3572 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
3574 // optionally draw the illuminated areas
3575 // for performance analysis by level designers
3576 R_Shadow_RenderMode_VisibleLighting(false, false);
3578 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3579 for (i = 0;i < numlightentities;i++)
3580 R_Shadow_DrawEntityLight(lightentities[i]);
3581 for (i = 0;i < numlightentities_noselfshadow;i++)
3582 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3585 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
3587 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
3588 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
3589 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
3590 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
3592 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance/rtlight->radius));
3593 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
3594 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
3596 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
3602 int receivermask = 0;
3603 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
3604 Matrix4x4_Abs(&radiustolight);
3606 r_shadow_shadowmaplod = 0;
3607 for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
3608 if ((r_shadow_shadowmapmaxsize >> i) > lodlinear)
3609 r_shadow_shadowmaplod = i;
3611 size = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
3613 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
3615 surfacesides = NULL;
3618 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3620 castermask = rtlight->static_shadowmap_casters;
3621 receivermask = rtlight->static_shadowmap_receivers;
3625 surfacesides = r_shadow_buffer_surfacesides;
3626 for(i = 0;i < numsurfaces;i++)
3628 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
3629 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3630 castermask |= surfacesides[i];
3631 receivermask |= surfacesides[i];
3635 if (receivermask < 0x3F)
3637 for (i = 0;i < numlightentities;i++)
3638 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3639 if (receivermask < 0x3F)
3640 for(i = 0; i < numlightentities_noselfshadow;i++)
3641 receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3644 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
3648 for (i = 0;i < numshadowentities;i++)
3649 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3650 for (i = 0;i < numshadowentities_noselfshadow;i++)
3651 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3654 //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
3656 // render shadow casters into 6 sided depth texture
3657 for (side = 0;side < 6;side++) if (receivermask & (1 << side))
3659 R_Shadow_RenderMode_ShadowMap(side, receivermask, size);
3660 if (! (castermask & (1 << side))) continue;
3662 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
3663 for (i = 0;i < numshadowentities;i++) if (entitysides[i] & (1 << side))
3664 R_Shadow_DrawEntityShadow(shadowentities[i]);
3667 if (numlightentities_noselfshadow)
3669 // render lighting using the depth texture as shadowmap
3670 // draw lighting in the unmasked areas
3671 R_Shadow_RenderMode_Lighting(false, false, true);
3672 for (i = 0;i < numlightentities_noselfshadow;i++)
3673 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3676 // render shadow casters into 6 sided depth texture
3677 if (numshadowentities_noselfshadow)
3679 for (side = 0;side < 6;side++) if ((receivermask & castermask) & (1 << side))
3681 R_Shadow_RenderMode_ShadowMap(side, 0, size);
3682 for (i = 0;i < numshadowentities_noselfshadow;i++) if (entitysides_noselfshadow[i] & (1 << side))
3683 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3687 // render lighting using the depth texture as shadowmap
3688 // draw lighting in the unmasked areas
3689 R_Shadow_RenderMode_Lighting(false, false, true);
3690 // draw lighting in the unmasked areas
3692 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3693 for (i = 0;i < numlightentities;i++)
3694 R_Shadow_DrawEntityLight(lightentities[i]);
3696 else if (castshadows && vid.stencil)
3698 // draw stencil shadow volumes to mask off pixels that are in shadow
3699 // so that they won't receive lighting
3700 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
3701 R_Shadow_ClearStencil();
3704 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
3705 for (i = 0;i < numshadowentities;i++)
3706 R_Shadow_DrawEntityShadow(shadowentities[i]);
3708 // draw lighting in the unmasked areas
3709 R_Shadow_RenderMode_Lighting(true, false, false);
3710 for (i = 0;i < numlightentities_noselfshadow;i++)
3711 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3713 for (i = 0;i < numshadowentities_noselfshadow;i++)
3714 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3716 // draw lighting in the unmasked areas
3717 R_Shadow_RenderMode_Lighting(true, false, false);
3719 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3720 for (i = 0;i < numlightentities;i++)
3721 R_Shadow_DrawEntityLight(lightentities[i]);
3725 // draw lighting in the unmasked areas
3726 R_Shadow_RenderMode_Lighting(false, false, false);
3728 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3729 for (i = 0;i < numlightentities;i++)
3730 R_Shadow_DrawEntityLight(lightentities[i]);
3731 for (i = 0;i < numlightentities_noselfshadow;i++)
3732 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3735 if (r_shadow_usingdeferredprepass)
3737 // when rendering deferred lighting, we simply rasterize the box
3738 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
3739 R_Shadow_RenderMode_DrawDeferredLight(false, true);
3740 else if (castshadows && vid.stencil)
3741 R_Shadow_RenderMode_DrawDeferredLight(true, false);
3743 R_Shadow_RenderMode_DrawDeferredLight(false, false);
3747 static void R_Shadow_FreeDeferred(void)
3749 R_Mesh_DestroyFramebufferObject(r_shadow_prepassgeometryfbo);
3750 r_shadow_prepassgeometryfbo = 0;
3752 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingfbo);
3753 r_shadow_prepasslightingfbo = 0;
3755 if (r_shadow_prepassgeometrydepthtexture)
3756 R_FreeTexture(r_shadow_prepassgeometrydepthtexture);
3757 r_shadow_prepassgeometrydepthtexture = NULL;
3759 if (r_shadow_prepassgeometrydepthcolortexture)
3760 R_FreeTexture(r_shadow_prepassgeometrydepthcolortexture);
3761 r_shadow_prepassgeometrydepthcolortexture = NULL;
3763 if (r_shadow_prepassgeometrynormalmaptexture)
3764 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
3765 r_shadow_prepassgeometrynormalmaptexture = NULL;
3767 if (r_shadow_prepasslightingdiffusetexture)
3768 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
3769 r_shadow_prepasslightingdiffusetexture = NULL;
3771 if (r_shadow_prepasslightingspeculartexture)
3772 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
3773 r_shadow_prepasslightingspeculartexture = NULL;
3776 void R_Shadow_DrawPrepass(void)
3784 entity_render_t *ent;
3785 float clearcolor[4];
3787 R_Mesh_ResetTextureState();
3789 GL_ColorMask(1,1,1,1);
3790 GL_BlendFunc(GL_ONE, GL_ZERO);
3793 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, r_shadow_prepassgeometrydepthcolortexture, NULL, NULL);
3794 Vector4Set(clearcolor, 0.5f,0.5f,0.5f,1.0f);
3795 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
3796 if (r_timereport_active)
3797 R_TimeReport("prepasscleargeom");
3799 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
3800 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
3801 if (r_timereport_active)
3802 R_TimeReport("prepassworld");
3804 for (i = 0;i < r_refdef.scene.numentities;i++)
3806 if (!r_refdef.viewcache.entityvisible[i])
3808 ent = r_refdef.scene.entities[i];
3809 if (ent->model && ent->model->DrawPrepass != NULL)
3810 ent->model->DrawPrepass(ent);
3813 if (r_timereport_active)
3814 R_TimeReport("prepassmodels");
3816 GL_DepthMask(false);
3817 GL_ColorMask(1,1,1,1);
3820 R_Mesh_SetRenderTargets(r_shadow_prepasslightingfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
3821 Vector4Set(clearcolor, 0, 0, 0, 0);
3822 GL_Clear(GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
3823 if (r_timereport_active)
3824 R_TimeReport("prepassclearlit");
3826 R_Shadow_RenderMode_Begin();
3828 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3829 if (r_shadow_debuglight.integer >= 0)
3831 lightindex = r_shadow_debuglight.integer;
3832 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3833 if (light && (light->flags & flag) && light->rtlight.draw)
3834 R_Shadow_DrawLight(&light->rtlight);
3838 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3839 for (lightindex = 0;lightindex < range;lightindex++)
3841 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3842 if (light && (light->flags & flag) && light->rtlight.draw)
3843 R_Shadow_DrawLight(&light->rtlight);
3846 if (r_refdef.scene.rtdlight)
3847 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
3848 if (r_refdef.scene.lights[lnum]->draw)
3849 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
3851 R_Mesh_ResetRenderTargets();
3853 R_Shadow_RenderMode_End();
3855 if (r_timereport_active)
3856 R_TimeReport("prepasslights");
3859 void R_Shadow_DrawLightSprites(void);
3860 void R_Shadow_PrepareLights(void)
3870 if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4) ||
3871 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
3872 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20) ||
3873 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
3874 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
3875 r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
3876 R_Shadow_FreeShadowMaps();
3878 r_shadow_usingshadowmaportho = false;
3880 switch (vid.renderpath)
3882 case RENDERPATH_GL20:
3883 case RENDERPATH_D3D9:
3884 case RENDERPATH_D3D10:
3885 case RENDERPATH_D3D11:
3886 case RENDERPATH_SOFT:
3887 case RENDERPATH_GLES2:
3888 if (!r_shadow_deferred.integer || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_STENCIL || !vid.support.ext_framebuffer_object || vid.maxdrawbuffers < 2)
3890 r_shadow_usingdeferredprepass = false;
3891 if (r_shadow_prepass_width)
3892 R_Shadow_FreeDeferred();
3893 r_shadow_prepass_width = r_shadow_prepass_height = 0;
3897 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
3899 R_Shadow_FreeDeferred();
3901 r_shadow_usingdeferredprepass = true;
3902 r_shadow_prepass_width = vid.width;
3903 r_shadow_prepass_height = vid.height;
3904 r_shadow_prepassgeometrydepthtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "prepassgeometrydepthmap", vid.width, vid.height, 24, false);
3905 switch (vid.renderpath)
3907 case RENDERPATH_D3D9:
3908 r_shadow_prepassgeometrydepthcolortexture = R_LoadTexture2D(r_shadow_texturepool, "prepassgeometrydepthcolormap", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, -1, NULL);
3913 r_shadow_prepassgeometrynormalmaptexture = R_LoadTexture2D(r_shadow_texturepool, "prepassgeometrynormalmap", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, -1, NULL);
3914 r_shadow_prepasslightingdiffusetexture = R_LoadTexture2D(r_shadow_texturepool, "prepasslightingdiffuse", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, -1, NULL);
3915 r_shadow_prepasslightingspeculartexture = R_LoadTexture2D(r_shadow_texturepool, "prepasslightingspecular", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, -1, NULL);
3917 // set up the geometry pass fbo (depth + normalmap)
3918 r_shadow_prepassgeometryfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
3919 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, r_shadow_prepassgeometrydepthcolortexture, NULL, NULL);
3920 // render depth into one texture and normalmap into the other
3921 if (qglDrawBuffersARB)
3923 qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);CHECKGLERROR
3924 qglReadBuffer(GL_NONE);CHECKGLERROR
3925 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
3926 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
3928 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
3929 Cvar_SetValueQuick(&r_shadow_deferred, 0);
3930 r_shadow_usingdeferredprepass = false;
3934 // set up the lighting pass fbo (diffuse + specular)
3935 r_shadow_prepasslightingfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
3936 R_Mesh_SetRenderTargets(r_shadow_prepasslightingfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
3937 // render diffuse into one texture and specular into another,
3938 // with depth and normalmap bound as textures,
3939 // with depth bound as attachment as well
3940 if (qglDrawBuffersARB)
3942 qglDrawBuffersARB(2, r_shadow_prepasslightingdrawbuffers);CHECKGLERROR
3943 qglReadBuffer(GL_NONE);CHECKGLERROR
3944 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
3945 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
3947 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
3948 Cvar_SetValueQuick(&r_shadow_deferred, 0);
3949 r_shadow_usingdeferredprepass = false;
3954 case RENDERPATH_GL13:
3955 case RENDERPATH_GL11:
3956 r_shadow_usingdeferredprepass = false;
3960 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);
3962 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3963 if (r_shadow_debuglight.integer >= 0)
3965 lightindex = r_shadow_debuglight.integer;
3966 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3967 if (light && (light->flags & flag))
3968 R_Shadow_PrepareLight(&light->rtlight);
3972 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3973 for (lightindex = 0;lightindex < range;lightindex++)
3975 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3976 if (light && (light->flags & flag))
3977 R_Shadow_PrepareLight(&light->rtlight);
3980 if (r_refdef.scene.rtdlight)
3982 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
3983 R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
3985 else if(gl_flashblend.integer)
3987 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
3989 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
3990 f = (rtlight->style >= 0 ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3991 VectorScale(rtlight->color, f, rtlight->currentcolor);
3995 if (r_editlights.integer)
3996 R_Shadow_DrawLightSprites();
3999 void R_Shadow_DrawLights(void)
4007 R_Shadow_RenderMode_Begin();
4009 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4010 if (r_shadow_debuglight.integer >= 0)
4012 lightindex = r_shadow_debuglight.integer;
4013 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4014 if (light && (light->flags & flag))
4015 R_Shadow_DrawLight(&light->rtlight);
4019 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4020 for (lightindex = 0;lightindex < range;lightindex++)
4022 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4023 if (light && (light->flags & flag))
4024 R_Shadow_DrawLight(&light->rtlight);
4027 if (r_refdef.scene.rtdlight)
4028 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4029 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4031 R_Shadow_RenderMode_End();
4034 extern const float r_screenvertex3f[12];
4035 extern void R_SetupView(qboolean allowwaterclippingplane);
4036 extern void R_ResetViewRendering3D(void);
4037 extern void R_ResetViewRendering2D(void);
4038 extern cvar_t r_shadows;
4039 extern cvar_t r_shadows_darken;
4040 extern cvar_t r_shadows_drawafterrtlighting;
4041 extern cvar_t r_shadows_castfrombmodels;
4042 extern cvar_t r_shadows_throwdistance;
4043 extern cvar_t r_shadows_throwdirection;
4044 extern cvar_t r_shadows_focus;
4045 extern cvar_t r_shadows_shadowmapscale;
4047 void R_Shadow_PrepareModelShadows(void)
4050 float scale, size, radius, dot1, dot2;
4051 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
4052 entity_render_t *ent;
4054 if (!r_refdef.scene.numentities)
4057 switch (r_shadow_shadowmode)
4059 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4060 if (r_shadows.integer >= 2)
4063 case R_SHADOW_SHADOWMODE_STENCIL:
4064 for (i = 0;i < r_refdef.scene.numentities;i++)
4066 ent = r_refdef.scene.entities[i];
4067 if (!ent->animcache_vertex3f && ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4068 R_AnimCache_GetEntity(ent, false, false);
4075 size = 2*r_shadow_shadowmapmaxsize;
4076 scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
4077 radius = 0.5f * size / scale;
4079 Math_atov(r_shadows_throwdirection.string, shadowdir);
4080 VectorNormalize(shadowdir);
4081 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4082 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4083 if (fabs(dot1) <= fabs(dot2))
4084 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4086 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4087 VectorNormalize(shadowforward);
4088 CrossProduct(shadowdir, shadowforward, shadowright);
4089 Math_atov(r_shadows_focus.string, shadowfocus);
4090 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4091 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4092 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4093 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4094 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4096 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4098 shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4099 shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4100 shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4101 shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4102 shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4103 shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4105 for (i = 0;i < r_refdef.scene.numentities;i++)
4107 ent = r_refdef.scene.entities[i];
4108 if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
4110 // cast shadows from anything of the map (submodels are optional)
4111 if (!ent->animcache_vertex3f && ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4112 R_AnimCache_GetEntity(ent, false, false);
4116 void R_DrawModelShadowMaps(void)
4119 float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
4120 entity_render_t *ent;
4121 vec3_t relativelightorigin;
4122 vec3_t relativelightdirection, relativeforward, relativeright;
4123 vec3_t relativeshadowmins, relativeshadowmaxs;
4124 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
4126 matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
4127 r_viewport_t viewport;
4129 float clearcolor[4];
4131 if (!r_refdef.scene.numentities)
4134 switch (r_shadow_shadowmode)
4136 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4142 R_ResetViewRendering3D();
4143 R_Shadow_RenderMode_Begin();
4144 R_Shadow_RenderMode_ActiveLight(NULL);
4146 switch (r_shadow_shadowmode)
4148 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4149 if (!r_shadow_shadowmap2dtexture)
4150 R_Shadow_MakeShadowMap(0, r_shadow_shadowmapmaxsize);
4151 fbo = r_shadow_fbo2d;
4152 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
4153 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
4154 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
4160 size = 2*r_shadow_shadowmapmaxsize;
4161 scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
4162 radius = 0.5f / scale;
4163 nearclip = -r_shadows_throwdistance.value;
4164 farclip = r_shadows_throwdistance.value;
4165 bias = r_shadow_shadowmapping_bias.value * r_shadow_shadowmapping_nearclip.value / (2 * r_shadows_throwdistance.value) * (1024.0f / size);
4167 r_shadow_shadowmap_parameters[0] = size;
4168 r_shadow_shadowmap_parameters[1] = size;
4169 r_shadow_shadowmap_parameters[2] = 1.0;
4170 r_shadow_shadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
4172 Math_atov(r_shadows_throwdirection.string, shadowdir);
4173 VectorNormalize(shadowdir);
4174 Math_atov(r_shadows_focus.string, shadowfocus);
4175 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4176 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4177 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4178 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4179 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4180 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4181 if (fabs(dot1) <= fabs(dot2))
4182 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4184 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4185 VectorNormalize(shadowforward);
4186 VectorM(scale, shadowforward, &m[0]);
4187 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4189 m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
4190 CrossProduct(shadowdir, shadowforward, shadowright);
4191 VectorM(scale, shadowright, &m[4]);
4192 m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
4193 VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
4194 m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
4195 Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
4196 Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
4197 R_Viewport_InitOrtho(&viewport, &cameramatrix, 0, 0, size, size, 0, 0, 1, 1, 0, -1, NULL);
4199 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4201 R_Mesh_SetRenderTargets(fbo, r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
4202 R_SetupShader_DepthOrShadow();
4203 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
4206 R_SetViewport(&viewport);
4207 GL_Scissor(viewport.x, viewport.y, min(viewport.width + r_shadow_shadowmapborder, 2*r_shadow_shadowmapmaxsize), viewport.height + r_shadow_shadowmapborder);
4208 Vector4Set(clearcolor, 1,1,1,1);
4209 // in D3D9 we have to render to a color texture shadowmap
4210 // in GL we render directly to a depth texture only
4211 if (r_shadow_shadowmap2dtexture)
4212 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4214 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4215 // render into a slightly restricted region so that the borders of the
4216 // shadowmap area fade away, rather than streaking across everything
4217 // outside the usable area
4218 GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
4222 R_Mesh_ResetRenderTargets();
4223 R_SetupShader_ShowDepth();
4224 GL_ColorMask(1,1,1,1);
4225 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4228 for (i = 0;i < r_refdef.scene.numentities;i++)
4230 ent = r_refdef.scene.entities[i];
4232 // cast shadows from anything of the map (submodels are optional)
4233 if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4235 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4236 Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
4237 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4238 Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
4239 Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
4240 relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4241 relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4242 relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4243 relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4244 relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4245 relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4246 RSurf_ActiveModelEntity(ent, false, false, false);
4247 ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
4248 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4255 unsigned char *rawpixels = Z_Malloc(viewport.width*viewport.height*4);
4257 qglReadPixels(viewport.x, viewport.y, viewport.width, viewport.height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, rawpixels);
4259 Image_WriteTGABGRA("r_shadows_2.tga", viewport.width, viewport.height, rawpixels);
4260 Cvar_SetValueQuick(&r_test, 0);
4265 R_Shadow_RenderMode_End();
4267 Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
4268 Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
4269 Matrix4x4_CreateScale3(&scalematrix, size, -size, 1);
4270 Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
4271 Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
4272 Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
4274 switch (vid.renderpath)
4276 case RENDERPATH_GL11:
4277 case RENDERPATH_GL13:
4278 case RENDERPATH_GL20:
4279 case RENDERPATH_SOFT:
4280 case RENDERPATH_GLES2:
4282 case RENDERPATH_D3D9:
4283 case RENDERPATH_D3D10:
4284 case RENDERPATH_D3D11:
4285 #ifdef OPENGL_ORIENTATION
4286 r_shadow_shadowmapmatrix.m[0][0] *= -1.0f;
4287 r_shadow_shadowmapmatrix.m[0][1] *= -1.0f;
4288 r_shadow_shadowmapmatrix.m[0][2] *= -1.0f;
4289 r_shadow_shadowmapmatrix.m[0][3] *= -1.0f;
4291 r_shadow_shadowmapmatrix.m[0][0] *= -1.0f;
4292 r_shadow_shadowmapmatrix.m[1][0] *= -1.0f;
4293 r_shadow_shadowmapmatrix.m[2][0] *= -1.0f;
4294 r_shadow_shadowmapmatrix.m[3][0] *= -1.0f;
4299 r_shadow_usingshadowmaportho = true;
4300 switch (r_shadow_shadowmode)
4302 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4303 r_shadow_usingshadowmap2d = true;
4310 void R_DrawModelShadows(void)
4313 float relativethrowdistance;
4314 entity_render_t *ent;
4315 vec3_t relativelightorigin;
4316 vec3_t relativelightdirection;
4317 vec3_t relativeshadowmins, relativeshadowmaxs;
4318 vec3_t tmp, shadowdir;
4320 if (!r_refdef.scene.numentities || !vid.stencil || (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL && r_shadows.integer != 1))
4323 R_ResetViewRendering3D();
4324 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4325 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4326 R_Shadow_RenderMode_Begin();
4327 R_Shadow_RenderMode_ActiveLight(NULL);
4328 r_shadow_lightscissor[0] = r_refdef.view.x;
4329 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
4330 r_shadow_lightscissor[2] = r_refdef.view.width;
4331 r_shadow_lightscissor[3] = r_refdef.view.height;
4332 R_Shadow_RenderMode_StencilShadowVolumes(false);
4335 if (r_shadows.integer == 2)
4337 Math_atov(r_shadows_throwdirection.string, shadowdir);
4338 VectorNormalize(shadowdir);
4341 R_Shadow_ClearStencil();
4343 for (i = 0;i < r_refdef.scene.numentities;i++)
4345 ent = r_refdef.scene.entities[i];
4347 // cast shadows from anything of the map (submodels are optional)
4348 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4350 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4351 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
4352 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
4353 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
4354 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4357 if(ent->entitynumber != 0)
4359 if(ent->entitynumber >= MAX_EDICTS) // csqc entity
4361 // FIXME handle this
4362 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4366 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
4367 int entnum, entnum2, recursion;
4368 entnum = entnum2 = ent->entitynumber;
4369 for(recursion = 32; recursion > 0; --recursion)
4371 entnum2 = cl.entities[entnum].state_current.tagentity;
4372 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
4377 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
4379 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
4380 // transform into modelspace of OUR entity
4381 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
4382 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
4385 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4389 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4392 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
4393 RSurf_ActiveModelEntity(ent, false, false, false);
4394 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4395 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4399 // not really the right mode, but this will disable any silly stencil features
4400 R_Shadow_RenderMode_End();
4402 // set up ortho view for rendering this pass
4403 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4404 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4405 //GL_ScissorTest(true);
4406 //R_EntityMatrix(&identitymatrix);
4407 //R_Mesh_ResetTextureState();
4408 R_ResetViewRendering2D();
4410 // set up a darkening blend on shadowed areas
4411 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4412 //GL_DepthRange(0, 1);
4413 //GL_DepthTest(false);
4414 //GL_DepthMask(false);
4415 //GL_PolygonOffset(0, 0);CHECKGLERROR
4416 GL_Color(0, 0, 0, r_shadows_darken.value);
4417 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4418 //GL_DepthFunc(GL_ALWAYS);
4419 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_NOTEQUAL, 128, 255);
4421 // apply the blend to the shadowed areas
4422 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, NULL);
4423 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
4424 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4426 // restore the viewport
4427 R_SetViewport(&r_refdef.view.viewport);
4429 // restore other state to normal
4430 //R_Shadow_RenderMode_End();
4433 void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4436 vec3_t centerorigin;
4438 // if it's too close, skip it
4439 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
4441 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4444 if (usequery && r_numqueries + 2 <= r_maxqueries)
4446 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4447 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4448 // 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
4449 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4451 switch(vid.renderpath)
4453 case RENDERPATH_GL20:
4454 case RENDERPATH_GL13:
4455 case RENDERPATH_GL11:
4456 case RENDERPATH_GLES2:
4458 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use GL_DepthFunc instead
4459 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
4460 GL_DepthFunc(GL_ALWAYS);
4461 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4462 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL);
4463 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4464 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4465 GL_DepthFunc(GL_LEQUAL);
4466 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
4467 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4468 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL);
4469 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4470 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4473 case RENDERPATH_D3D9:
4474 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4476 case RENDERPATH_D3D10:
4477 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4479 case RENDERPATH_D3D11:
4480 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4482 case RENDERPATH_SOFT:
4483 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4487 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4490 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
4492 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4495 GLint allpixels = 0, visiblepixels = 0;
4496 // now we have to check the query result
4497 if (rtlight->corona_queryindex_visiblepixels)
4499 switch(vid.renderpath)
4501 case RENDERPATH_GL20:
4502 case RENDERPATH_GL13:
4503 case RENDERPATH_GL11:
4504 case RENDERPATH_GLES2:
4506 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
4507 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
4510 case RENDERPATH_D3D9:
4511 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4513 case RENDERPATH_D3D10:
4514 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4516 case RENDERPATH_D3D11:
4517 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4519 case RENDERPATH_SOFT:
4520 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4523 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
4524 if (visiblepixels < 1 || allpixels < 1)
4526 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
4527 cscale *= rtlight->corona_visibility;
4531 // FIXME: these traces should scan all render entities instead of cl.world
4532 if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
4535 VectorScale(rtlight->currentcolor, cscale, color);
4536 if (VectorLength(color) > (1.0f / 256.0f))
4539 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
4542 VectorNegate(color, color);
4543 switch(vid.renderpath)
4545 case RENDERPATH_GL11:
4546 case RENDERPATH_GL13:
4547 case RENDERPATH_GL20:
4548 case RENDERPATH_GLES2:
4549 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
4551 case RENDERPATH_D3D9:
4553 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_SUBTRACT);
4556 case RENDERPATH_D3D10:
4557 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4559 case RENDERPATH_D3D11:
4560 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4562 case RENDERPATH_SOFT:
4563 DPSOFTRAST_BlendSubtract(true);
4567 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4568 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);
4569 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4572 switch(vid.renderpath)
4574 case RENDERPATH_GL11:
4575 case RENDERPATH_GL13:
4576 case RENDERPATH_GL20:
4577 case RENDERPATH_GLES2:
4578 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
4580 case RENDERPATH_D3D9:
4582 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_ADD);
4585 case RENDERPATH_D3D10:
4586 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4588 case RENDERPATH_D3D11:
4589 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4591 case RENDERPATH_SOFT:
4592 DPSOFTRAST_BlendSubtract(false);
4599 void R_Shadow_DrawCoronas(void)
4602 qboolean usequery = false;
4607 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4609 if (r_waterstate.renderingscene)
4611 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4612 R_EntityMatrix(&identitymatrix);
4614 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4616 // check occlusion of coronas
4617 // use GL_ARB_occlusion_query if available
4618 // otherwise use raytraces
4620 switch (vid.renderpath)
4622 case RENDERPATH_GL11:
4623 case RENDERPATH_GL13:
4624 case RENDERPATH_GL20:
4625 case RENDERPATH_GLES2:
4626 usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
4629 GL_ColorMask(0,0,0,0);
4630 if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
4631 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
4634 r_maxqueries = (range + r_refdef.scene.numlights) * 4;
4635 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
4637 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
4640 RSurf_ActiveWorldEntity();
4641 GL_BlendFunc(GL_ONE, GL_ZERO);
4642 GL_CullFace(GL_NONE);
4643 GL_DepthMask(false);
4644 GL_DepthRange(0, 1);
4645 GL_PolygonOffset(0, 0);
4647 R_Mesh_ResetTextureState();
4648 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
4651 case RENDERPATH_D3D9:
4653 //Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4655 case RENDERPATH_D3D10:
4656 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4658 case RENDERPATH_D3D11:
4659 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4661 case RENDERPATH_SOFT:
4663 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4666 for (lightindex = 0;lightindex < range;lightindex++)
4668 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4671 rtlight = &light->rtlight;
4672 rtlight->corona_visibility = 0;
4673 rtlight->corona_queryindex_visiblepixels = 0;
4674 rtlight->corona_queryindex_allpixels = 0;
4675 if (!(rtlight->flags & flag))
4677 if (rtlight->corona <= 0)
4679 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4681 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4683 for (i = 0;i < r_refdef.scene.numlights;i++)
4685 rtlight = r_refdef.scene.lights[i];
4686 rtlight->corona_visibility = 0;
4687 rtlight->corona_queryindex_visiblepixels = 0;
4688 rtlight->corona_queryindex_allpixels = 0;
4689 if (!(rtlight->flags & flag))
4691 if (rtlight->corona <= 0)
4693 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4696 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4698 // now draw the coronas using the query data for intensity info
4699 for (lightindex = 0;lightindex < range;lightindex++)
4701 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4704 rtlight = &light->rtlight;
4705 if (rtlight->corona_visibility <= 0)
4707 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4709 for (i = 0;i < r_refdef.scene.numlights;i++)
4711 rtlight = r_refdef.scene.lights[i];
4712 if (rtlight->corona_visibility <= 0)
4714 if (gl_flashblend.integer)
4715 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4717 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4723 dlight_t *R_Shadow_NewWorldLight(void)
4725 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4728 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)
4731 // validate parameters
4732 if (style < 0 || style >= MAX_LIGHTSTYLES)
4734 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
4740 // copy to light properties
4741 VectorCopy(origin, light->origin);
4742 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4743 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4744 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4746 light->color[0] = max(color[0], 0);
4747 light->color[1] = max(color[1], 0);
4748 light->color[2] = max(color[2], 0);
4750 light->color[0] = color[0];
4751 light->color[1] = color[1];
4752 light->color[2] = color[2];
4753 light->radius = max(radius, 0);
4754 light->style = style;
4755 light->shadow = shadowenable;
4756 light->corona = corona;
4757 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4758 light->coronasizescale = coronasizescale;
4759 light->ambientscale = ambientscale;
4760 light->diffusescale = diffusescale;
4761 light->specularscale = specularscale;
4762 light->flags = flags;
4764 // update renderable light data
4765 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4766 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);
4769 void R_Shadow_FreeWorldLight(dlight_t *light)
4771 if (r_shadow_selectedlight == light)
4772 r_shadow_selectedlight = NULL;
4773 R_RTLight_Uncompile(&light->rtlight);
4774 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4777 void R_Shadow_ClearWorldLights(void)
4781 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4782 for (lightindex = 0;lightindex < range;lightindex++)
4784 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4786 R_Shadow_FreeWorldLight(light);
4788 r_shadow_selectedlight = NULL;
4791 void R_Shadow_SelectLight(dlight_t *light)
4793 if (r_shadow_selectedlight)
4794 r_shadow_selectedlight->selected = false;
4795 r_shadow_selectedlight = light;
4796 if (r_shadow_selectedlight)
4797 r_shadow_selectedlight->selected = true;
4800 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4802 // this is never batched (there can be only one)
4804 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
4805 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4806 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4809 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4814 skinframe_t *skinframe;
4817 // this is never batched (due to the ent parameter changing every time)
4818 // so numsurfaces == 1 and surfacelist[0] == lightnumber
4819 const dlight_t *light = (dlight_t *)ent;
4822 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
4825 VectorScale(light->color, intensity, spritecolor);
4826 if (VectorLength(spritecolor) < 0.1732f)
4827 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
4828 if (VectorLength(spritecolor) > 1.0f)
4829 VectorNormalize(spritecolor);
4831 // draw light sprite
4832 if (light->cubemapname[0] && !light->shadow)
4833 skinframe = r_editlights_sprcubemapnoshadowlight;
4834 else if (light->cubemapname[0])
4835 skinframe = r_editlights_sprcubemaplight;
4836 else if (!light->shadow)
4837 skinframe = r_editlights_sprnoshadowlight;
4839 skinframe = r_editlights_sprlight;
4841 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);
4842 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4844 // draw selection sprite if light is selected
4845 if (light->selected)
4847 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4848 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4849 // VorteX todo: add normalmode/realtime mode light overlay sprites?
4853 void R_Shadow_DrawLightSprites(void)
4857 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4858 for (lightindex = 0;lightindex < range;lightindex++)
4860 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4862 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
4864 if (!r_editlights_lockcursor)
4865 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
4868 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
4873 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
4874 if (lightindex >= range)
4876 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4879 rtlight = &light->rtlight;
4880 //if (!(rtlight->flags & flag))
4882 VectorCopy(rtlight->shadoworigin, origin);
4883 *radius = rtlight->radius;
4884 VectorCopy(rtlight->color, color);
4888 void R_Shadow_SelectLightInView(void)
4890 float bestrating, rating, temp[3];
4894 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4898 if (r_editlights_lockcursor)
4900 for (lightindex = 0;lightindex < range;lightindex++)
4902 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4905 VectorSubtract(light->origin, r_refdef.view.origin, temp);
4906 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
4909 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
4910 if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1.0f)
4912 bestrating = rating;
4917 R_Shadow_SelectLight(best);
4920 void R_Shadow_LoadWorldLights(void)
4922 int n, a, style, shadow, flags;
4923 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
4924 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
4925 if (cl.worldmodel == NULL)
4927 Con_Print("No map loaded.\n");
4930 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
4931 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4941 for (;COM_Parse(t, true) && strcmp(
4942 if (COM_Parse(t, true))
4944 if (com_token[0] == '!')
4947 origin[0] = atof(com_token+1);
4950 origin[0] = atof(com_token);
4955 while (*s && *s != '\n' && *s != '\r')
4961 // check for modifier flags
4968 #if _MSC_VER >= 1400
4969 #define sscanf sscanf_s
4971 cubemapname[sizeof(cubemapname)-1] = 0;
4972 #if MAX_QPATH != 128
4973 #error update this code if MAX_QPATH changes
4975 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
4976 #if _MSC_VER >= 1400
4977 , sizeof(cubemapname)
4979 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
4982 flags = LIGHTFLAG_REALTIMEMODE;
4990 coronasizescale = 0.25f;
4992 VectorClear(angles);
4995 if (a < 9 || !strcmp(cubemapname, "\"\""))
4997 // remove quotes on cubemapname
4998 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
5001 namelen = strlen(cubemapname) - 2;
5002 memmove(cubemapname, cubemapname + 1, namelen);
5003 cubemapname[namelen] = '\0';
5007 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);
5010 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5018 Con_Printf("invalid rtlights file \"%s\"\n", name);
5019 Mem_Free(lightsstring);
5023 void R_Shadow_SaveWorldLights(void)
5027 size_t bufchars, bufmaxchars;
5029 char name[MAX_QPATH];
5030 char line[MAX_INPUTLINE];
5031 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
5032 // I hate lines which are 3 times my screen size :( --blub
5035 if (cl.worldmodel == NULL)
5037 Con_Print("No map loaded.\n");
5040 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
5041 bufchars = bufmaxchars = 0;
5043 for (lightindex = 0;lightindex < range;lightindex++)
5045 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5048 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
5049 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);
5050 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
5051 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]);
5053 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);
5054 if (bufchars + strlen(line) > bufmaxchars)
5056 bufmaxchars = bufchars + strlen(line) + 2048;
5058 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
5062 memcpy(buf, oldbuf, bufchars);
5068 memcpy(buf + bufchars, line, strlen(line));
5069 bufchars += strlen(line);
5073 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
5078 void R_Shadow_LoadLightsFile(void)
5081 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
5082 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
5083 if (cl.worldmodel == NULL)
5085 Con_Print("No map loaded.\n");
5088 dpsnprintf(name, sizeof(name), "%s.lights", cl.worldnamenoextension);
5089 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5097 while (*s && *s != '\n' && *s != '\r')
5103 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);
5107 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);
5110 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
5111 radius = bound(15, radius, 4096);
5112 VectorScale(color, (2.0f / (8388608.0f)), color);
5113 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5121 Con_Printf("invalid lights file \"%s\"\n", name);
5122 Mem_Free(lightsstring);
5126 // tyrlite/hmap2 light types in the delay field
5127 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
5129 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
5141 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
5142 char key[256], value[MAX_INPUTLINE];
5144 if (cl.worldmodel == NULL)
5146 Con_Print("No map loaded.\n");
5149 // try to load a .ent file first
5150 dpsnprintf(key, sizeof(key), "%s.ent", cl.worldnamenoextension);
5151 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
5152 // and if that is not found, fall back to the bsp file entity string
5154 data = cl.worldmodel->brush.entities;
5157 for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
5159 type = LIGHTTYPE_MINUSX;
5160 origin[0] = origin[1] = origin[2] = 0;
5161 originhack[0] = originhack[1] = originhack[2] = 0;
5162 angles[0] = angles[1] = angles[2] = 0;
5163 color[0] = color[1] = color[2] = 1;
5164 light[0] = light[1] = light[2] = 1;light[3] = 300;
5165 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
5175 if (!COM_ParseToken_Simple(&data, false, false))
5177 if (com_token[0] == '}')
5178 break; // end of entity
5179 if (com_token[0] == '_')
5180 strlcpy(key, com_token + 1, sizeof(key));
5182 strlcpy(key, com_token, sizeof(key));
5183 while (key[strlen(key)-1] == ' ') // remove trailing spaces
5184 key[strlen(key)-1] = 0;
5185 if (!COM_ParseToken_Simple(&data, false, false))
5187 strlcpy(value, com_token, sizeof(value));
5189 // now that we have the key pair worked out...
5190 if (!strcmp("light", key))
5192 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5196 light[0] = vec[0] * (1.0f / 256.0f);
5197 light[1] = vec[0] * (1.0f / 256.0f);
5198 light[2] = vec[0] * (1.0f / 256.0f);
5204 light[0] = vec[0] * (1.0f / 255.0f);
5205 light[1] = vec[1] * (1.0f / 255.0f);
5206 light[2] = vec[2] * (1.0f / 255.0f);
5210 else if (!strcmp("delay", key))
5212 else if (!strcmp("origin", key))
5213 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5214 else if (!strcmp("angle", key))
5215 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5216 else if (!strcmp("angles", key))
5217 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5218 else if (!strcmp("color", key))
5219 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5220 else if (!strcmp("wait", key))
5221 fadescale = atof(value);
5222 else if (!strcmp("classname", key))
5224 if (!strncmp(value, "light", 5))
5227 if (!strcmp(value, "light_fluoro"))
5232 overridecolor[0] = 1;
5233 overridecolor[1] = 1;
5234 overridecolor[2] = 1;
5236 if (!strcmp(value, "light_fluorospark"))
5241 overridecolor[0] = 1;
5242 overridecolor[1] = 1;
5243 overridecolor[2] = 1;
5245 if (!strcmp(value, "light_globe"))
5250 overridecolor[0] = 1;
5251 overridecolor[1] = 0.8;
5252 overridecolor[2] = 0.4;
5254 if (!strcmp(value, "light_flame_large_yellow"))
5259 overridecolor[0] = 1;
5260 overridecolor[1] = 0.5;
5261 overridecolor[2] = 0.1;
5263 if (!strcmp(value, "light_flame_small_yellow"))
5268 overridecolor[0] = 1;
5269 overridecolor[1] = 0.5;
5270 overridecolor[2] = 0.1;
5272 if (!strcmp(value, "light_torch_small_white"))
5277 overridecolor[0] = 1;
5278 overridecolor[1] = 0.5;
5279 overridecolor[2] = 0.1;
5281 if (!strcmp(value, "light_torch_small_walltorch"))
5286 overridecolor[0] = 1;
5287 overridecolor[1] = 0.5;
5288 overridecolor[2] = 0.1;
5292 else if (!strcmp("style", key))
5293 style = atoi(value);
5294 else if (!strcmp("skin", key))
5295 skin = (int)atof(value);
5296 else if (!strcmp("pflags", key))
5297 pflags = (int)atof(value);
5298 //else if (!strcmp("effects", key))
5299 // effects = (int)atof(value);
5300 else if (cl.worldmodel->type == mod_brushq3)
5302 if (!strcmp("scale", key))
5303 lightscale = atof(value);
5304 if (!strcmp("fade", key))
5305 fadescale = atof(value);
5310 if (lightscale <= 0)
5314 if (color[0] == color[1] && color[0] == color[2])
5316 color[0] *= overridecolor[0];
5317 color[1] *= overridecolor[1];
5318 color[2] *= overridecolor[2];
5320 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5321 color[0] = color[0] * light[0];
5322 color[1] = color[1] * light[1];
5323 color[2] = color[2] * light[2];
5326 case LIGHTTYPE_MINUSX:
5328 case LIGHTTYPE_RECIPX:
5330 VectorScale(color, (1.0f / 16.0f), color);
5332 case LIGHTTYPE_RECIPXX:
5334 VectorScale(color, (1.0f / 16.0f), color);
5337 case LIGHTTYPE_NONE:
5341 case LIGHTTYPE_MINUSXX:
5344 VectorAdd(origin, originhack, origin);
5346 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);
5349 Mem_Free(entfiledata);
5353 void R_Shadow_SetCursorLocationForView(void)
5356 vec3_t dest, endpos;
5358 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5359 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
5360 if (trace.fraction < 1)
5362 dist = trace.fraction * r_editlights_cursordistance.value;
5363 push = r_editlights_cursorpushback.value;
5367 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5368 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5372 VectorClear( endpos );
5374 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5375 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5376 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5379 void R_Shadow_UpdateWorldLightSelection(void)
5381 if (r_editlights.integer)
5383 R_Shadow_SetCursorLocationForView();
5384 R_Shadow_SelectLightInView();
5387 R_Shadow_SelectLight(NULL);
5390 void R_Shadow_EditLights_Clear_f(void)
5392 R_Shadow_ClearWorldLights();
5395 void R_Shadow_EditLights_Reload_f(void)
5399 strlcpy(r_shadow_mapname, cl.worldname, sizeof(r_shadow_mapname));
5400 R_Shadow_ClearWorldLights();
5401 R_Shadow_LoadWorldLights();
5402 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5404 R_Shadow_LoadLightsFile();
5405 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5406 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5410 void R_Shadow_EditLights_Save_f(void)
5414 R_Shadow_SaveWorldLights();
5417 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
5419 R_Shadow_ClearWorldLights();
5420 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5423 void R_Shadow_EditLights_ImportLightsFile_f(void)
5425 R_Shadow_ClearWorldLights();
5426 R_Shadow_LoadLightsFile();
5429 void R_Shadow_EditLights_Spawn_f(void)
5432 if (!r_editlights.integer)
5434 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5437 if (Cmd_Argc() != 1)
5439 Con_Print("r_editlights_spawn does not take parameters\n");
5442 color[0] = color[1] = color[2] = 1;
5443 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5446 void R_Shadow_EditLights_Edit_f(void)
5448 vec3_t origin, angles, color;
5449 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5450 int style, shadows, flags, normalmode, realtimemode;
5451 char cubemapname[MAX_INPUTLINE];
5452 if (!r_editlights.integer)
5454 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5457 if (!r_shadow_selectedlight)
5459 Con_Print("No selected light.\n");
5462 VectorCopy(r_shadow_selectedlight->origin, origin);
5463 VectorCopy(r_shadow_selectedlight->angles, angles);
5464 VectorCopy(r_shadow_selectedlight->color, color);
5465 radius = r_shadow_selectedlight->radius;
5466 style = r_shadow_selectedlight->style;
5467 if (r_shadow_selectedlight->cubemapname)
5468 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5471 shadows = r_shadow_selectedlight->shadow;
5472 corona = r_shadow_selectedlight->corona;
5473 coronasizescale = r_shadow_selectedlight->coronasizescale;
5474 ambientscale = r_shadow_selectedlight->ambientscale;
5475 diffusescale = r_shadow_selectedlight->diffusescale;
5476 specularscale = r_shadow_selectedlight->specularscale;
5477 flags = r_shadow_selectedlight->flags;
5478 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5479 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5480 if (!strcmp(Cmd_Argv(1), "origin"))
5482 if (Cmd_Argc() != 5)
5484 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5487 origin[0] = atof(Cmd_Argv(2));
5488 origin[1] = atof(Cmd_Argv(3));
5489 origin[2] = atof(Cmd_Argv(4));
5491 else if (!strcmp(Cmd_Argv(1), "originx"))
5493 if (Cmd_Argc() != 3)
5495 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5498 origin[0] = atof(Cmd_Argv(2));
5500 else if (!strcmp(Cmd_Argv(1), "originy"))
5502 if (Cmd_Argc() != 3)
5504 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5507 origin[1] = atof(Cmd_Argv(2));
5509 else if (!strcmp(Cmd_Argv(1), "originz"))
5511 if (Cmd_Argc() != 3)
5513 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5516 origin[2] = atof(Cmd_Argv(2));
5518 else if (!strcmp(Cmd_Argv(1), "move"))
5520 if (Cmd_Argc() != 5)
5522 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5525 origin[0] += atof(Cmd_Argv(2));
5526 origin[1] += atof(Cmd_Argv(3));
5527 origin[2] += atof(Cmd_Argv(4));
5529 else if (!strcmp(Cmd_Argv(1), "movex"))
5531 if (Cmd_Argc() != 3)
5533 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5536 origin[0] += atof(Cmd_Argv(2));
5538 else if (!strcmp(Cmd_Argv(1), "movey"))
5540 if (Cmd_Argc() != 3)
5542 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5545 origin[1] += atof(Cmd_Argv(2));
5547 else if (!strcmp(Cmd_Argv(1), "movez"))
5549 if (Cmd_Argc() != 3)
5551 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5554 origin[2] += atof(Cmd_Argv(2));
5556 else if (!strcmp(Cmd_Argv(1), "angles"))
5558 if (Cmd_Argc() != 5)
5560 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5563 angles[0] = atof(Cmd_Argv(2));
5564 angles[1] = atof(Cmd_Argv(3));
5565 angles[2] = atof(Cmd_Argv(4));
5567 else if (!strcmp(Cmd_Argv(1), "anglesx"))
5569 if (Cmd_Argc() != 3)
5571 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5574 angles[0] = atof(Cmd_Argv(2));
5576 else if (!strcmp(Cmd_Argv(1), "anglesy"))
5578 if (Cmd_Argc() != 3)
5580 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5583 angles[1] = atof(Cmd_Argv(2));
5585 else if (!strcmp(Cmd_Argv(1), "anglesz"))
5587 if (Cmd_Argc() != 3)
5589 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5592 angles[2] = atof(Cmd_Argv(2));
5594 else if (!strcmp(Cmd_Argv(1), "color"))
5596 if (Cmd_Argc() != 5)
5598 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
5601 color[0] = atof(Cmd_Argv(2));
5602 color[1] = atof(Cmd_Argv(3));
5603 color[2] = atof(Cmd_Argv(4));
5605 else if (!strcmp(Cmd_Argv(1), "radius"))
5607 if (Cmd_Argc() != 3)
5609 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5612 radius = atof(Cmd_Argv(2));
5614 else if (!strcmp(Cmd_Argv(1), "colorscale"))
5616 if (Cmd_Argc() == 3)
5618 double scale = atof(Cmd_Argv(2));
5625 if (Cmd_Argc() != 5)
5627 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
5630 color[0] *= atof(Cmd_Argv(2));
5631 color[1] *= atof(Cmd_Argv(3));
5632 color[2] *= atof(Cmd_Argv(4));
5635 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
5637 if (Cmd_Argc() != 3)
5639 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5642 radius *= atof(Cmd_Argv(2));
5644 else if (!strcmp(Cmd_Argv(1), "style"))
5646 if (Cmd_Argc() != 3)
5648 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5651 style = atoi(Cmd_Argv(2));
5653 else if (!strcmp(Cmd_Argv(1), "cubemap"))
5657 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5660 if (Cmd_Argc() == 3)
5661 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
5665 else if (!strcmp(Cmd_Argv(1), "shadows"))
5667 if (Cmd_Argc() != 3)
5669 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5672 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5674 else if (!strcmp(Cmd_Argv(1), "corona"))
5676 if (Cmd_Argc() != 3)
5678 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5681 corona = atof(Cmd_Argv(2));
5683 else if (!strcmp(Cmd_Argv(1), "coronasize"))
5685 if (Cmd_Argc() != 3)
5687 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5690 coronasizescale = atof(Cmd_Argv(2));
5692 else if (!strcmp(Cmd_Argv(1), "ambient"))
5694 if (Cmd_Argc() != 3)
5696 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5699 ambientscale = atof(Cmd_Argv(2));
5701 else if (!strcmp(Cmd_Argv(1), "diffuse"))
5703 if (Cmd_Argc() != 3)
5705 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5708 diffusescale = atof(Cmd_Argv(2));
5710 else if (!strcmp(Cmd_Argv(1), "specular"))
5712 if (Cmd_Argc() != 3)
5714 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5717 specularscale = atof(Cmd_Argv(2));
5719 else if (!strcmp(Cmd_Argv(1), "normalmode"))
5721 if (Cmd_Argc() != 3)
5723 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5726 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5728 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
5730 if (Cmd_Argc() != 3)
5732 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5735 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5739 Con_Print("usage: r_editlights_edit [property] [value]\n");
5740 Con_Print("Selected light's properties:\n");
5741 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5742 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5743 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5744 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
5745 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
5746 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
5747 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5748 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
5749 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
5750 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
5751 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
5752 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
5753 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5754 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5757 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5758 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5761 void R_Shadow_EditLights_EditAll_f(void)
5764 dlight_t *light, *oldselected;
5767 if (!r_editlights.integer)
5769 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5773 oldselected = r_shadow_selectedlight;
5774 // EditLights doesn't seem to have a "remove" command or something so:
5775 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5776 for (lightindex = 0;lightindex < range;lightindex++)
5778 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5781 R_Shadow_SelectLight(light);
5782 R_Shadow_EditLights_Edit_f();
5784 // return to old selected (to not mess editing once selection is locked)
5785 R_Shadow_SelectLight(oldselected);
5788 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
5790 int lightnumber, lightcount;
5791 size_t lightindex, range;
5795 if (!r_editlights.integer)
5797 x = vid_conwidth.value - 240;
5799 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
5802 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5803 for (lightindex = 0;lightindex < range;lightindex++)
5805 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5808 if (light == r_shadow_selectedlight)
5809 lightnumber = lightindex;
5812 dpsnprintf(temp, sizeof(temp), "Cursor origin: %.0f %.0f %.0f", r_editlights_cursorlocation[0], r_editlights_cursorlocation[1], r_editlights_cursorlocation[2]); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, false, FONT_DEFAULT);y += 8;
5813 dpsnprintf(temp, sizeof(temp), "Total lights : %i active (%i total)", lightcount, (int)Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray)); DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, false, FONT_DEFAULT);y += 8;
5815 if (r_shadow_selectedlight == NULL)
5817 dpsnprintf(temp, sizeof(temp), "Light #%i properties:", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
5818 dpsnprintf(temp, sizeof(temp), "Origin : %.0f %.0f %.0f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
5819 dpsnprintf(temp, sizeof(temp), "Angles : %.0f %.0f %.0f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
5820 dpsnprintf(temp, sizeof(temp), "Color : %.2f %.2f %.2f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
5821 dpsnprintf(temp, sizeof(temp), "Radius : %.0f\n", r_shadow_selectedlight->radius);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
5822 dpsnprintf(temp, sizeof(temp), "Corona : %.0f\n", r_shadow_selectedlight->corona);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
5823 dpsnprintf(temp, sizeof(temp), "Style : %i\n", r_shadow_selectedlight->style);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
5824 dpsnprintf(temp, sizeof(temp), "Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
5825 dpsnprintf(temp, sizeof(temp), "Cubemap : %s\n", r_shadow_selectedlight->cubemapname);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
5826 dpsnprintf(temp, sizeof(temp), "CoronaSize : %.2f\n", r_shadow_selectedlight->coronasizescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
5827 dpsnprintf(temp, sizeof(temp), "Ambient : %.2f\n", r_shadow_selectedlight->ambientscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
5828 dpsnprintf(temp, sizeof(temp), "Diffuse : %.2f\n", r_shadow_selectedlight->diffusescale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
5829 dpsnprintf(temp, sizeof(temp), "Specular : %.2f\n", r_shadow_selectedlight->specularscale);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
5830 dpsnprintf(temp, sizeof(temp), "NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
5831 dpsnprintf(temp, sizeof(temp), "RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true, FONT_DEFAULT);y += 8;
5834 void R_Shadow_EditLights_ToggleShadow_f(void)
5836 if (!r_editlights.integer)
5838 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5841 if (!r_shadow_selectedlight)
5843 Con_Print("No selected light.\n");
5846 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);
5849 void R_Shadow_EditLights_ToggleCorona_f(void)
5851 if (!r_editlights.integer)
5853 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5856 if (!r_shadow_selectedlight)
5858 Con_Print("No selected light.\n");
5861 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);
5864 void R_Shadow_EditLights_Remove_f(void)
5866 if (!r_editlights.integer)
5868 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
5871 if (!r_shadow_selectedlight)
5873 Con_Print("No selected light.\n");
5876 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
5877 r_shadow_selectedlight = NULL;
5880 void R_Shadow_EditLights_Help_f(void)
5883 "Documentation on r_editlights system:\n"
5885 "r_editlights : enable/disable editing mode\n"
5886 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
5887 "r_editlights_cursorpushback : push back cursor this far from surface\n"
5888 "r_editlights_cursorpushoff : push cursor off surface this far\n"
5889 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
5890 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
5892 "r_editlights_help : this help\n"
5893 "r_editlights_clear : remove all lights\n"
5894 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
5895 "r_editlights_lock : lock selection to current light, if already locked - unlock\n"
5896 "r_editlights_save : save to .rtlights file\n"
5897 "r_editlights_spawn : create a light with default settings\n"
5898 "r_editlights_edit command : edit selected light - more documentation below\n"
5899 "r_editlights_remove : remove selected light\n"
5900 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
5901 "r_editlights_importlightentitiesfrommap : reload light entities\n"
5902 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
5904 "origin x y z : set light location\n"
5905 "originx x: set x component of light location\n"
5906 "originy y: set y component of light location\n"
5907 "originz z: set z component of light location\n"
5908 "move x y z : adjust light location\n"
5909 "movex x: adjust x component of light location\n"
5910 "movey y: adjust y component of light location\n"
5911 "movez z: adjust z component of light location\n"
5912 "angles x y z : set light angles\n"
5913 "anglesx x: set x component of light angles\n"
5914 "anglesy y: set y component of light angles\n"
5915 "anglesz z: set z component of light angles\n"
5916 "color r g b : set color of light (can be brighter than 1 1 1)\n"
5917 "radius radius : set radius (size) of light\n"
5918 "colorscale grey : multiply color of light (1 does nothing)\n"
5919 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
5920 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
5921 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
5922 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
5923 "cubemap basename : set filter cubemap of light (not yet supported)\n"
5924 "shadows 1/0 : turn on/off shadows\n"
5925 "corona n : set corona intensity\n"
5926 "coronasize n : set corona size (0-1)\n"
5927 "ambient n : set ambient intensity (0-1)\n"
5928 "diffuse n : set diffuse intensity (0-1)\n"
5929 "specular n : set specular intensity (0-1)\n"
5930 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
5931 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
5932 "<nothing> : print light properties to console\n"
5936 void R_Shadow_EditLights_CopyInfo_f(void)
5938 if (!r_editlights.integer)
5940 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
5943 if (!r_shadow_selectedlight)
5945 Con_Print("No selected light.\n");
5948 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
5949 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
5950 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
5951 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
5952 if (r_shadow_selectedlight->cubemapname)
5953 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
5955 r_shadow_bufferlight.cubemapname[0] = 0;
5956 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
5957 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
5958 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
5959 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
5960 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
5961 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
5962 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
5965 void R_Shadow_EditLights_PasteInfo_f(void)
5967 if (!r_editlights.integer)
5969 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
5972 if (!r_shadow_selectedlight)
5974 Con_Print("No selected light.\n");
5977 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);
5980 void R_Shadow_EditLights_Lock_f(void)
5982 if (!r_editlights.integer)
5984 Con_Print("Cannot lock on light when not in editing mode. Set r_editlights to 1.\n");
5987 if (r_editlights_lockcursor)
5989 r_editlights_lockcursor = false;
5992 if (!r_shadow_selectedlight)
5994 Con_Print("No selected light to lock on.\n");
5997 r_editlights_lockcursor = true;
6000 void R_Shadow_EditLights_Init(void)
6002 Cvar_RegisterVariable(&r_editlights);
6003 Cvar_RegisterVariable(&r_editlights_cursordistance);
6004 Cvar_RegisterVariable(&r_editlights_cursorpushback);
6005 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
6006 Cvar_RegisterVariable(&r_editlights_cursorgrid);
6007 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
6008 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
6009 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
6010 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)");
6011 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
6012 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
6013 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
6014 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)");
6015 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
6016 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
6017 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
6018 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
6019 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
6020 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
6021 Cmd_AddCommand("r_editlights_pasteinfo", R_Shadow_EditLights_PasteInfo_f, "apply the stored properties onto the selected light (making it exactly identical except for origin)");
6022 Cmd_AddCommand("r_editlights_lock", R_Shadow_EditLights_Lock_f, "lock selection to current light, if already locked - unlock");
6028 =============================================================================
6032 =============================================================================
6035 void R_CompleteLightPoint(vec3_t ambient, vec3_t diffuse, vec3_t lightdir, const vec3_t p, const int flags)
6037 int i, numlights, flag;
6040 float relativepoint[3];
6049 if (r_fullbright.integer)
6051 VectorSet(ambient, 1, 1, 1);
6052 VectorClear(diffuse);
6053 VectorClear(lightdir);
6057 if (flags & LP_LIGHTMAP)
6059 VectorSet(ambient, r_refdef.scene.ambient, r_refdef.scene.ambient, r_refdef.scene.ambient);
6060 VectorClear(diffuse);
6061 VectorClear(lightdir);
6062 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
6063 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambient, diffuse, lightdir);
6067 memset(sample, 0, sizeof(sample));
6068 VectorSet(sample, r_refdef.scene.ambient, r_refdef.scene.ambient, r_refdef.scene.ambient);
6070 if ((flags & LP_LIGHTMAP) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
6073 VectorClear(tempambient);
6075 VectorClear(relativepoint);
6076 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, tempambient, color, relativepoint);
6077 VectorScale(tempambient, r_refdef.lightmapintensity, tempambient);
6078 VectorScale(color, r_refdef.lightmapintensity, color);
6079 VectorAdd(sample, tempambient, sample);
6080 VectorMA(sample , 0.5f , color, sample );
6081 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
6082 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
6083 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
6084 // calculate a weighted average light direction as well
6085 intensity = VectorLength(color);
6086 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
6089 if (flags & LP_RTWORLD)
6091 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
6092 numlights = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
6093 for (i = 0; i < numlights; i++)
6095 dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
6098 light = &dlight->rtlight;
6099 if (!(light->flags & flag))
6102 lightradius2 = light->radius * light->radius;
6103 VectorSubtract(light->shadoworigin, p, relativepoint);
6104 dist2 = VectorLength2(relativepoint);
6105 if (dist2 >= lightradius2)
6107 dist = sqrt(dist2) / light->radius;
6108 intensity = min(1.0f, (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) * r_shadow_lightintensityscale.value;
6109 if (intensity <= 0.0f)
6111 if (light->shadow && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
6113 // scale down intensity to add to both ambient and diffuse
6114 //intensity *= 0.5f;
6115 VectorNormalize(relativepoint);
6116 VectorScale(light->currentcolor, intensity, color);
6117 VectorMA(sample , 0.5f , color, sample );
6118 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
6119 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
6120 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
6121 // calculate a weighted average light direction as well
6122 intensity *= VectorLength(color);
6123 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
6127 if (flags & LP_DYNLIGHT)
6130 for (i = 0;i < r_refdef.scene.numlights;i++)
6132 light = r_refdef.scene.lights[i];
6134 lightradius2 = light->radius * light->radius;
6135 VectorSubtract(light->shadoworigin, p, relativepoint);
6136 dist2 = VectorLength2(relativepoint);
6137 if (dist2 >= lightradius2)
6139 dist = sqrt(dist2) / light->radius;
6140 intensity = (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist) * r_shadow_lightintensityscale.value;
6141 if (intensity <= 0.0f)
6143 if (light->shadow && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
6145 // scale down intensity to add to both ambient and diffuse
6146 //intensity *= 0.5f;
6147 VectorNormalize(relativepoint);
6148 VectorScale(light->currentcolor, intensity, color);
6149 VectorMA(sample , 0.5f , color, sample );
6150 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
6151 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
6152 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
6153 // calculate a weighted average light direction as well
6154 intensity *= VectorLength(color);
6155 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
6159 // calculate the direction we'll use to reduce the sample to a directional light source
6160 VectorCopy(sample + 12, dir);
6161 //VectorSet(dir, sample[3] + sample[4] + sample[5], sample[6] + sample[7] + sample[8], sample[9] + sample[10] + sample[11]);
6162 VectorNormalize(dir);
6163 // extract the diffuse color along the chosen direction and scale it
6164 diffuse[0] = (dir[0]*sample[3] + dir[1]*sample[6] + dir[2]*sample[ 9] + sample[ 0]);
6165 diffuse[1] = (dir[0]*sample[4] + dir[1]*sample[7] + dir[2]*sample[10] + sample[ 1]);
6166 diffuse[2] = (dir[0]*sample[5] + dir[1]*sample[8] + dir[2]*sample[11] + sample[ 2]);
6167 // subtract some of diffuse from ambient
6168 VectorMA(sample, -0.333f, diffuse, ambient);
6169 // store the normalized lightdir
6170 VectorCopy(dir, lightdir);