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"
145 extern LPDIRECT3DDEVICE9 vid_d3d9dev;
148 extern void R_Shadow_EditLights_Init(void);
150 typedef enum r_shadow_rendermode_e
152 R_SHADOW_RENDERMODE_NONE,
153 R_SHADOW_RENDERMODE_ZPASS_STENCIL,
154 R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL,
155 R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE,
156 R_SHADOW_RENDERMODE_ZFAIL_STENCIL,
157 R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL,
158 R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE,
159 R_SHADOW_RENDERMODE_LIGHT_VERTEX,
160 R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN,
161 R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN,
162 R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN,
163 R_SHADOW_RENDERMODE_LIGHT_GLSL,
164 R_SHADOW_RENDERMODE_VISIBLEVOLUMES,
165 R_SHADOW_RENDERMODE_VISIBLELIGHTING,
166 R_SHADOW_RENDERMODE_SHADOWMAP2D
168 r_shadow_rendermode_t;
170 typedef enum r_shadow_shadowmode_e
172 R_SHADOW_SHADOWMODE_STENCIL,
173 R_SHADOW_SHADOWMODE_SHADOWMAP2D
175 r_shadow_shadowmode_t;
177 r_shadow_rendermode_t r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
178 r_shadow_rendermode_t r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_NONE;
179 r_shadow_rendermode_t r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_NONE;
180 r_shadow_rendermode_t r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_NONE;
181 qboolean r_shadow_usingshadowmap2d;
182 qboolean r_shadow_usingshadowmaportho;
183 int r_shadow_shadowmapside;
184 float r_shadow_shadowmap_texturescale[2];
185 float r_shadow_shadowmap_parameters[4];
187 int r_shadow_drawbuffer;
188 int r_shadow_readbuffer;
190 int r_shadow_cullface_front, r_shadow_cullface_back;
191 GLuint r_shadow_fbo2d;
192 r_shadow_shadowmode_t r_shadow_shadowmode;
193 int r_shadow_shadowmapfilterquality;
194 int r_shadow_shadowmapdepthbits;
195 int r_shadow_shadowmapmaxsize;
196 qboolean r_shadow_shadowmapvsdct;
197 qboolean r_shadow_shadowmapsampler;
198 int r_shadow_shadowmappcf;
199 int r_shadow_shadowmapborder;
200 matrix4x4_t r_shadow_shadowmapmatrix;
201 int r_shadow_lightscissor[4];
202 qboolean r_shadow_usingdeferredprepass;
204 int maxshadowtriangles;
207 int maxshadowvertices;
208 float *shadowvertex3f;
218 unsigned char *shadowsides;
219 int *shadowsideslist;
226 int r_shadow_buffer_numleafpvsbytes;
227 unsigned char *r_shadow_buffer_visitingleafpvs;
228 unsigned char *r_shadow_buffer_leafpvs;
229 int *r_shadow_buffer_leaflist;
231 int r_shadow_buffer_numsurfacepvsbytes;
232 unsigned char *r_shadow_buffer_surfacepvs;
233 int *r_shadow_buffer_surfacelist;
234 unsigned char *r_shadow_buffer_surfacesides;
236 int r_shadow_buffer_numshadowtrispvsbytes;
237 unsigned char *r_shadow_buffer_shadowtrispvs;
238 int r_shadow_buffer_numlighttrispvsbytes;
239 unsigned char *r_shadow_buffer_lighttrispvs;
241 rtexturepool_t *r_shadow_texturepool;
242 rtexture_t *r_shadow_attenuationgradienttexture;
243 rtexture_t *r_shadow_attenuation2dtexture;
244 rtexture_t *r_shadow_attenuation3dtexture;
245 skinframe_t *r_shadow_lightcorona;
246 rtexture_t *r_shadow_shadowmap2dtexture;
247 rtexture_t *r_shadow_shadowmap2dcolortexture;
248 rtexture_t *r_shadow_shadowmapvsdcttexture;
249 int r_shadow_shadowmapsize; // changes for each light based on distance
250 int r_shadow_shadowmaplod; // changes for each light based on distance
252 GLuint r_shadow_prepassgeometryfbo;
253 GLuint r_shadow_prepasslightingfbo;
254 int r_shadow_prepass_width;
255 int r_shadow_prepass_height;
256 rtexture_t *r_shadow_prepassgeometrydepthtexture;
257 rtexture_t *r_shadow_prepassgeometrydepthcolortexture;
258 rtexture_t *r_shadow_prepassgeometrynormalmaptexture;
259 rtexture_t *r_shadow_prepasslightingdiffusetexture;
260 rtexture_t *r_shadow_prepasslightingspeculartexture;
262 // lights are reloaded when this changes
263 char r_shadow_mapname[MAX_QPATH];
265 // used only for light filters (cubemaps)
266 rtexturepool_t *r_shadow_filters_texturepool;
268 static const GLenum r_shadow_prepasslightingdrawbuffers[2] = {GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT};
270 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"};
271 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"};
272 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
273 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"};
274 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)"};
275 //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"};
276 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)"};
277 cvar_t r_shadow_usenormalmap = {CVAR_SAVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"};
278 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)"};
279 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"};
280 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
281 cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
282 cvar_t r_shadow_gloss2exponent = {0, "r_shadow_gloss2exponent", "32", "same as r_shadow_glossexponent but for forced gloss (gloss 2) surfaces"};
283 cvar_t r_shadow_glossexact = {0, "r_shadow_glossexact", "0", "use exact reflection math for gloss (slightly slower, but should look a tad better)"};
284 cvar_t r_shadow_lightattenuationdividebias = {0, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"};
285 cvar_t r_shadow_lightattenuationlinearscale = {0, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"};
286 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
287 cvar_t r_shadow_lightradiusscale = {0, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
288 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "0", "how far to cast shadows"};
289 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)"};
290 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
291 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
292 cvar_t r_shadow_realtime_dlight_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
293 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
294 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)"};
295 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"};
296 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
297 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
298 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"};
299 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)"};
300 cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "0", "enables portal-based culling optimization during compilation (overrides compilesvbsp)"};
301 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)"};
302 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"};
303 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)"};
304 cvar_t r_shadow_shadowmapping_depthbits = {CVAR_SAVE, "r_shadow_shadowmapping_depthbits", "24", "requested minimum shadowmap texture depth bits"};
305 cvar_t r_shadow_shadowmapping_vsdct = {CVAR_SAVE, "r_shadow_shadowmapping_vsdct", "1", "enables use of virtual shadow depth cube texture"};
306 cvar_t r_shadow_shadowmapping_minsize = {CVAR_SAVE, "r_shadow_shadowmapping_minsize", "32", "shadowmap size limit"};
307 cvar_t r_shadow_shadowmapping_maxsize = {CVAR_SAVE, "r_shadow_shadowmapping_maxsize", "512", "shadowmap size limit"};
308 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"};
309 //cvar_t r_shadow_shadowmapping_lod_bias = {CVAR_SAVE, "r_shadow_shadowmapping_lod_bias", "16", "shadowmap size bias"};
310 //cvar_t r_shadow_shadowmapping_lod_scale = {CVAR_SAVE, "r_shadow_shadowmapping_lod_scale", "128", "shadowmap size scaling parameter"};
311 cvar_t r_shadow_shadowmapping_bordersize = {CVAR_SAVE, "r_shadow_shadowmapping_bordersize", "4", "shadowmap size bias for filtering"};
312 cvar_t r_shadow_shadowmapping_nearclip = {CVAR_SAVE, "r_shadow_shadowmapping_nearclip", "1", "shadowmap nearclip in world units"};
313 cvar_t r_shadow_shadowmapping_bias = {CVAR_SAVE, "r_shadow_shadowmapping_bias", "0.03", "shadowmap bias parameter (this is multiplied by nearclip * 1024 / lodsize)"};
314 cvar_t r_shadow_shadowmapping_polygonfactor = {CVAR_SAVE, "r_shadow_shadowmapping_polygonfactor", "2", "slope-dependent shadowmapping bias"};
315 cvar_t r_shadow_shadowmapping_polygonoffset = {CVAR_SAVE, "r_shadow_shadowmapping_polygonoffset", "0", "constant shadowmapping bias"};
316 cvar_t r_shadow_sortsurfaces = {0, "r_shadow_sortsurfaces", "1", "improve performance by sorting illuminated surfaces by texture"};
317 cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
318 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)"};
319 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)"};
320 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "1", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
321 cvar_t r_coronas_occlusionsizescale = {CVAR_SAVE, "r_coronas_occlusionsizescale", "0.1", "size of light source for corona occlusion checksm the proportion of hidden pixels controls corona intensity"};
322 cvar_t r_coronas_occlusionquery = {CVAR_SAVE, "r_coronas_occlusionquery", "1", "use GL_ARB_occlusion_query extension if supported (fades coronas according to visibility)"};
323 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
324 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
325 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
326 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
327 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
328 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
329 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
330 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
331 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
333 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
334 #define ATTENTABLESIZE 256
335 // 1D gradient, 2D circle and 3D sphere attenuation textures
336 #define ATTEN1DSIZE 32
337 #define ATTEN2DSIZE 64
338 #define ATTEN3DSIZE 32
340 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
341 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
342 static float r_shadow_attentable[ATTENTABLESIZE+1];
344 rtlight_t *r_shadow_compilingrtlight;
345 static memexpandablearray_t r_shadow_worldlightsarray;
346 dlight_t *r_shadow_selectedlight;
347 dlight_t r_shadow_bufferlight;
348 vec3_t r_editlights_cursorlocation;
349 qboolean r_editlights_lockcursor;
351 extern int con_vislines;
353 void R_Shadow_UncompileWorldLights(void);
354 void R_Shadow_ClearWorldLights(void);
355 void R_Shadow_SaveWorldLights(void);
356 void R_Shadow_LoadWorldLights(void);
357 void R_Shadow_LoadLightsFile(void);
358 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
359 void R_Shadow_EditLights_Reload_f(void);
360 void R_Shadow_ValidateCvars(void);
361 static void R_Shadow_MakeTextures(void);
363 #define EDLIGHTSPRSIZE 8
364 skinframe_t *r_editlights_sprcursor;
365 skinframe_t *r_editlights_sprlight;
366 skinframe_t *r_editlights_sprnoshadowlight;
367 skinframe_t *r_editlights_sprcubemaplight;
368 skinframe_t *r_editlights_sprcubemapnoshadowlight;
369 skinframe_t *r_editlights_sprselection;
371 void R_Shadow_SetShadowMode(void)
373 r_shadow_shadowmapmaxsize = bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4);
374 r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20;
375 r_shadow_shadowmapfilterquality = r_shadow_shadowmapping_filterquality.integer;
376 r_shadow_shadowmapdepthbits = r_shadow_shadowmapping_depthbits.integer;
377 r_shadow_shadowmapborder = bound(0, r_shadow_shadowmapping_bordersize.integer, 16);
378 r_shadow_shadowmaplod = -1;
379 r_shadow_shadowmapsize = 0;
380 r_shadow_shadowmapsampler = false;
381 r_shadow_shadowmappcf = 0;
382 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
383 if ((r_shadow_shadowmapping.integer || r_shadow_deferred.integer) && vid.support.ext_framebuffer_object)
385 switch(vid.renderpath)
387 case RENDERPATH_GL20:
388 if(r_shadow_shadowmapfilterquality < 0)
390 if(vid.support.amd_texture_texture4 || vid.support.arb_texture_gather)
391 r_shadow_shadowmappcf = 1;
392 else if(strstr(gl_vendor, "NVIDIA") || strstr(gl_renderer, "Radeon HD"))
394 r_shadow_shadowmapsampler = vid.support.arb_shadow;
395 r_shadow_shadowmappcf = 1;
397 else if(strstr(gl_vendor, "ATI"))
398 r_shadow_shadowmappcf = 1;
400 r_shadow_shadowmapsampler = vid.support.arb_shadow;
404 switch (r_shadow_shadowmapfilterquality)
407 r_shadow_shadowmapsampler = vid.support.arb_shadow;
410 r_shadow_shadowmapsampler = vid.support.arb_shadow;
411 r_shadow_shadowmappcf = 1;
414 r_shadow_shadowmappcf = 1;
417 r_shadow_shadowmappcf = 2;
421 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
422 // Cg has very little choice in depth texture sampling
424 r_shadow_shadowmapsampler = false;
426 case RENDERPATH_CGGL:
427 case RENDERPATH_D3D9:
428 case RENDERPATH_D3D10:
429 case RENDERPATH_D3D11:
430 r_shadow_shadowmapsampler = false;
431 r_shadow_shadowmappcf = 1;
432 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
434 case RENDERPATH_GL13:
436 case RENDERPATH_GL11:
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_Position_Arrays(outverts, shadowvertex3f);
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_Position_Arrays(outverts, shadowvertex3f);
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 //static const r_vertexposition_t resetvertexposition[3] = {{0, 0, 0}};
1853 void R_Shadow_RenderMode_Begin(void)
1859 R_Shadow_ValidateCvars();
1861 if (!r_shadow_attenuation2dtexture
1862 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1863 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1864 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1865 R_Shadow_MakeTextures();
1868 R_Mesh_ResetTextureState();
1869 // R_Mesh_PrepareVertices_Position(0, resetvertexposition, NULL);
1870 GL_BlendFunc(GL_ONE, GL_ZERO);
1871 GL_DepthRange(0, 1);
1872 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1874 GL_DepthMask(false);
1875 GL_Color(0, 0, 0, 1);
1876 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1878 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1880 if (gl_ext_separatestencil.integer && vid.support.ati_separate_stencil)
1882 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
1883 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
1885 else if (gl_ext_stenciltwoside.integer && vid.support.ext_stencil_two_side)
1887 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
1888 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
1892 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
1893 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
1896 switch(vid.renderpath)
1898 case RENDERPATH_GL20:
1899 case RENDERPATH_CGGL:
1900 case RENDERPATH_D3D9:
1901 case RENDERPATH_D3D10:
1902 case RENDERPATH_D3D11:
1903 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1905 case RENDERPATH_GL13:
1906 case RENDERPATH_GL11:
1907 if (r_textureunits.integer >= 2 && vid.texunits >= 2 && r_shadow_texture3d.integer && r_shadow_attenuation3dtexture)
1908 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN;
1909 else if (r_textureunits.integer >= 3 && vid.texunits >= 3)
1910 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN;
1911 else if (r_textureunits.integer >= 2 && vid.texunits >= 2)
1912 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN;
1914 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1920 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
1921 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
1922 r_shadow_drawbuffer = drawbuffer;
1923 r_shadow_readbuffer = readbuffer;
1925 r_shadow_cullface_front = r_refdef.view.cullface_front;
1926 r_shadow_cullface_back = r_refdef.view.cullface_back;
1929 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
1931 rsurface.rtlight = rtlight;
1934 void R_Shadow_RenderMode_Reset(void)
1936 R_Mesh_ResetRenderTargets();
1937 R_SetViewport(&r_refdef.view.viewport);
1938 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
1939 R_Mesh_ResetTextureState();
1940 // R_Mesh_PrepareVertices_Position(0, resetvertexposition, NULL);
1941 GL_DepthRange(0, 1);
1943 GL_DepthMask(false);
1944 GL_DepthFunc(GL_LEQUAL);
1945 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1946 r_refdef.view.cullface_front = r_shadow_cullface_front;
1947 r_refdef.view.cullface_back = r_shadow_cullface_back;
1948 GL_CullFace(r_refdef.view.cullface_back);
1949 GL_Color(1, 1, 1, 1);
1950 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
1951 GL_BlendFunc(GL_ONE, GL_ZERO);
1952 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
1953 r_shadow_usingshadowmap2d = false;
1954 r_shadow_usingshadowmaportho = false;
1955 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
1958 void R_Shadow_ClearStencil(void)
1960 GL_Clear(GL_STENCIL_BUFFER_BIT, NULL, 1.0f, 128);
1961 r_refdef.stats.lights_clears++;
1964 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
1966 r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
1967 if (r_shadow_rendermode == mode)
1969 R_Shadow_RenderMode_Reset();
1970 GL_DepthFunc(GL_LESS);
1971 GL_ColorMask(0, 0, 0, 0);
1972 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1973 GL_CullFace(GL_NONE);
1974 R_SetupShader_DepthOrShadow();
1975 r_shadow_rendermode = mode;
1980 case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
1981 case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
1982 R_SetStencilSeparate(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, GL_ALWAYS, 128, 255);
1984 case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
1985 case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
1986 R_SetStencilSeparate(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, GL_ALWAYS, 128, 255);
1991 static void R_Shadow_MakeVSDCT(void)
1993 // maps to a 2x3 texture rectangle with normalized coordinates
1998 // stores abs(dir.xy), offset.xy/2.5
1999 unsigned char data[4*6] =
2001 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
2002 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
2003 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
2004 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
2005 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
2006 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
2008 r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
2011 static void R_Shadow_MakeShadowMap(int side, int size)
2013 switch (r_shadow_shadowmode)
2015 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2016 if (r_shadow_shadowmap2dtexture) return;
2017 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);
2018 r_shadow_shadowmap2dcolortexture = NULL;
2019 switch(vid.renderpath)
2022 case RENDERPATH_D3D9:
2023 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);
2024 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
2028 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2dtexture, NULL, NULL, NULL, NULL);
2036 // render depth into the fbo, do not render color at all
2037 // validate the fbo now
2041 qglDrawBuffer(GL_NONE);CHECKGLERROR
2042 qglReadBuffer(GL_NONE);CHECKGLERROR
2043 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2044 if (status != GL_FRAMEBUFFER_COMPLETE_EXT && (r_shadow_shadowmapping.integer || r_shadow_deferred.integer))
2046 Con_Printf("R_Shadow_MakeShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2047 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2048 Cvar_SetValueQuick(&r_shadow_deferred, 0);
2053 void R_Shadow_RenderMode_ShadowMap(int side, int clear, int size)
2055 float nearclip, farclip, bias;
2056 r_viewport_t viewport;
2059 float clearcolor[4];
2060 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
2062 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
2063 r_shadow_shadowmap_parameters[1] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
2064 r_shadow_shadowmap_parameters[3] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
2065 r_shadow_shadowmapside = side;
2066 r_shadow_shadowmapsize = size;
2068 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2069 r_shadow_shadowmap_parameters[2] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2070 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
2071 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D) goto init_done;
2073 // complex unrolled cube approach (more flexible)
2074 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2075 R_Shadow_MakeVSDCT();
2076 if (!r_shadow_shadowmap2dtexture)
2077 R_Shadow_MakeShadowMap(side, r_shadow_shadowmapmaxsize);
2078 if (r_shadow_shadowmap2dtexture) fbo = r_shadow_fbo2d;
2079 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
2080 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
2081 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
2083 R_Mesh_ResetTextureState();
2084 R_Mesh_ResetRenderTargets();
2085 R_Shadow_RenderMode_Reset();
2088 R_Mesh_SetRenderTargets(fbo, r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
2089 R_SetupShader_DepthOrShadow();
2092 R_SetupShader_ShowDepth();
2093 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
2098 R_SetViewport(&viewport);
2099 flipped = (side & 1) ^ (side >> 2);
2100 r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
2101 r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
2102 switch(vid.renderpath)
2104 case RENDERPATH_GL11:
2105 case RENDERPATH_GL13:
2106 case RENDERPATH_GL20:
2107 case RENDERPATH_CGGL:
2108 GL_CullFace(r_refdef.view.cullface_back);
2109 // OpenGL lets us scissor larger than the viewport, so go ahead and clear all views at once
2110 if ((clear & ((2 << side) - 1)) == (1 << side)) // only clear if the side is the first in the mask
2112 // get tightest scissor rectangle that encloses all viewports in the clear mask
2113 int x1 = clear & 0x15 ? 0 : size;
2114 int x2 = clear & 0x2A ? 2 * size : size;
2115 int y1 = clear & 0x03 ? 0 : (clear & 0xC ? size : 2 * size);
2116 int y2 = clear & 0x30 ? 3 * size : (clear & 0xC ? 2 * size : size);
2117 GL_Scissor(x1, y1, x2 - x1, y2 - y1);
2118 GL_Clear(GL_DEPTH_BUFFER_BIT, NULL, 1.0f, 0);
2120 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2122 case RENDERPATH_D3D9:
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);
2145 case RENDERPATH_D3D10:
2146 case RENDERPATH_D3D11:
2147 // D3D considers it an error to use a scissor larger than the viewport... clear just this view
2148 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2149 GL_ColorMask(0,0,0,0);
2151 GL_Clear(GL_DEPTH_BUFFER_BIT, NULL, 1.0f, 0);
2156 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
2158 R_Mesh_ResetTextureState();
2159 R_Mesh_ResetRenderTargets();
2162 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2163 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2164 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2165 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2167 R_Shadow_RenderMode_Reset();
2168 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2170 GL_DepthFunc(GL_EQUAL);
2171 // do global setup needed for the chosen lighting mode
2172 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2173 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2174 r_shadow_usingshadowmap2d = shadowmapping;
2175 r_shadow_rendermode = r_shadow_lightingrendermode;
2176 // only draw light where this geometry was already rendered AND the
2177 // stencil is 128 (values other than this mean shadow)
2179 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2181 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
2184 static const unsigned short bboxelements[36] =
2194 static const float bboxpoints[8][3] =
2206 void R_Shadow_RenderMode_DrawDeferredLight(qboolean stenciltest, qboolean shadowmapping)
2209 float vertex3f[8*3];
2210 const matrix4x4_t *matrix = &rsurface.rtlight->matrix_lighttoworld;
2211 // do global setup needed for the chosen lighting mode
2212 R_Shadow_RenderMode_Reset();
2213 r_shadow_rendermode = r_shadow_lightingrendermode;
2214 R_EntityMatrix(&identitymatrix);
2215 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2216 // only draw light where this geometry was already rendered AND the
2217 // stencil is 128 (values other than this mean shadow)
2218 R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2219 R_Mesh_SetRenderTargets(r_shadow_prepasslightingfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
2221 r_shadow_usingshadowmap2d = shadowmapping;
2223 // render the lighting
2224 R_SetupShader_DeferredLight(rsurface.rtlight);
2225 for (i = 0;i < 8;i++)
2226 Matrix4x4_Transform(matrix, bboxpoints[i], vertex3f + i*3);
2227 GL_ColorMask(1,1,1,1);
2228 GL_DepthMask(false);
2229 GL_DepthRange(0, 1);
2230 GL_PolygonOffset(0, 0);
2232 GL_DepthFunc(GL_GREATER);
2233 GL_CullFace(r_refdef.view.cullface_back);
2234 R_Mesh_PrepareVertices_Position_Arrays(8, vertex3f);
2235 R_Mesh_Draw(0, 8, 0, 12, NULL, NULL, 0, bboxelements, NULL, 0);
2238 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
2240 R_Shadow_RenderMode_Reset();
2241 GL_BlendFunc(GL_ONE, GL_ONE);
2242 GL_DepthRange(0, 1);
2243 GL_DepthTest(r_showshadowvolumes.integer < 2);
2244 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
2245 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2246 GL_CullFace(GL_NONE);
2247 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
2250 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
2252 R_Shadow_RenderMode_Reset();
2253 GL_BlendFunc(GL_ONE, GL_ONE);
2254 GL_DepthRange(0, 1);
2255 GL_DepthTest(r_showlighting.integer < 2);
2256 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2258 GL_DepthFunc(GL_EQUAL);
2259 R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2260 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2263 void R_Shadow_RenderMode_End(void)
2265 R_Shadow_RenderMode_Reset();
2266 R_Shadow_RenderMode_ActiveLight(NULL);
2268 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2269 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2272 int bboxedges[12][2] =
2291 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2293 if (!r_shadow_scissor.integer)
2295 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;
2301 if(R_ScissorForBBox(mins, maxs, r_shadow_lightscissor))
2302 return true; // invisible
2303 if(r_shadow_lightscissor[0] != r_refdef.view.viewport.x
2304 || r_shadow_lightscissor[1] != r_refdef.view.viewport.y
2305 || r_shadow_lightscissor[2] != r_refdef.view.viewport.width
2306 || r_shadow_lightscissor[3] != r_refdef.view.viewport.height)
2307 r_refdef.stats.lights_scissored++;
2311 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, const float *diffusecolor, const float *ambientcolor)
2314 const float *vertex3f;
2315 const float *normal3f;
2317 float dist, dot, distintensity, shadeintensity, v[3], n[3];
2318 switch (r_shadow_rendermode)
2320 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2321 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2322 if (VectorLength2(diffusecolor) > 0)
2324 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, normal3f = rsurface.batchnormal3f + 3*firstvertex, color4f = rsurface.array_passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, normal3f += 3, color4f += 4)
2326 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2327 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2328 if ((dot = DotProduct(n, v)) < 0)
2330 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2331 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
2334 VectorCopy(ambientcolor, color4f);
2335 if (r_refdef.fogenabled)
2338 f = RSurf_FogVertex(vertex3f);
2339 VectorScale(color4f, f, color4f);
2346 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.array_passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
2348 VectorCopy(ambientcolor, color4f);
2349 if (r_refdef.fogenabled)
2352 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2353 f = RSurf_FogVertex(vertex3f);
2354 VectorScale(color4f + 4*i, f, color4f);
2360 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2361 if (VectorLength2(diffusecolor) > 0)
2363 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, normal3f = rsurface.batchnormal3f + 3*firstvertex, color4f = rsurface.array_passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, normal3f += 3, color4f += 4)
2365 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2366 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2368 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2369 if ((dot = DotProduct(n, v)) < 0)
2371 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2372 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2373 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2374 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2378 color4f[0] = ambientcolor[0] * distintensity;
2379 color4f[1] = ambientcolor[1] * distintensity;
2380 color4f[2] = ambientcolor[2] * distintensity;
2382 if (r_refdef.fogenabled)
2385 f = RSurf_FogVertex(vertex3f);
2386 VectorScale(color4f, f, color4f);
2390 VectorClear(color4f);
2396 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.array_passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
2398 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2399 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2401 color4f[0] = ambientcolor[0] * distintensity;
2402 color4f[1] = ambientcolor[1] * distintensity;
2403 color4f[2] = ambientcolor[2] * distintensity;
2404 if (r_refdef.fogenabled)
2407 f = RSurf_FogVertex(vertex3f);
2408 VectorScale(color4f, f, color4f);
2412 VectorClear(color4f);
2417 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2418 if (VectorLength2(diffusecolor) > 0)
2420 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, normal3f = rsurface.batchnormal3f + 3*firstvertex, color4f = rsurface.array_passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, normal3f += 3, color4f += 4)
2422 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2423 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2425 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2426 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2427 if ((dot = DotProduct(n, v)) < 0)
2429 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2430 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2431 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2432 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2436 color4f[0] = ambientcolor[0] * distintensity;
2437 color4f[1] = ambientcolor[1] * distintensity;
2438 color4f[2] = ambientcolor[2] * distintensity;
2440 if (r_refdef.fogenabled)
2443 f = RSurf_FogVertex(vertex3f);
2444 VectorScale(color4f, f, color4f);
2448 VectorClear(color4f);
2454 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.array_passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
2456 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2457 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2459 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2460 color4f[0] = ambientcolor[0] * distintensity;
2461 color4f[1] = ambientcolor[1] * distintensity;
2462 color4f[2] = ambientcolor[2] * distintensity;
2463 if (r_refdef.fogenabled)
2466 f = RSurf_FogVertex(vertex3f);
2467 VectorScale(color4f, f, color4f);
2471 VectorClear(color4f);
2481 static void R_Shadow_RenderLighting_VisibleLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
2483 // used to display how many times a surface is lit for level design purposes
2484 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
2485 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
2489 static void R_Shadow_RenderLighting_Light_GLSL(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale, float specularscale)
2491 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2492 R_SetupShader_Surface(lightcolor, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT, texturenumsurfaces, texturesurfacelist, NULL);
2493 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2494 GL_DepthFunc(GL_EQUAL);
2496 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2497 GL_DepthFunc(GL_LEQUAL);
2500 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
2507 int newnumtriangles;
2511 int maxtriangles = 4096;
2512 static int newelements[4096*3];
2513 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, diffusecolor2, ambientcolor2);
2514 for (renders = 0;renders < 4;renders++)
2519 newnumtriangles = 0;
2521 // due to low fillrate on the cards this vertex lighting path is
2522 // designed for, we manually cull all triangles that do not
2523 // contain a lit vertex
2524 // this builds batches of triangles from multiple surfaces and
2525 // renders them at once
2526 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
2528 if (VectorLength2(rsurface.array_passcolor4f + e[0] * 4) + VectorLength2(rsurface.array_passcolor4f + e[1] * 4) + VectorLength2(rsurface.array_passcolor4f + e[2] * 4) >= 0.01)
2530 if (newnumtriangles)
2532 newfirstvertex = min(newfirstvertex, e[0]);
2533 newlastvertex = max(newlastvertex, e[0]);
2537 newfirstvertex = e[0];
2538 newlastvertex = e[0];
2540 newfirstvertex = min(newfirstvertex, e[1]);
2541 newlastvertex = max(newlastvertex, e[1]);
2542 newfirstvertex = min(newfirstvertex, e[2]);
2543 newlastvertex = max(newlastvertex, e[2]);
2549 if (newnumtriangles >= maxtriangles)
2551 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
2552 newnumtriangles = 0;
2558 if (newnumtriangles >= 1)
2560 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
2563 // if we couldn't find any lit triangles, exit early
2566 // now reduce the intensity for the next overbright pass
2567 // we have to clamp to 0 here incase the drivers have improper
2568 // handling of negative colors
2569 // (some old drivers even have improper handling of >1 color)
2571 for (i = 0, c = rsurface.array_passcolor4f + 4 * firstvertex;i < numvertices;i++, c += 4)
2573 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
2575 c[0] = max(0, c[0] - 1);
2576 c[1] = max(0, c[1] - 1);
2577 c[2] = max(0, c[2] - 1);
2589 static void R_Shadow_RenderLighting_Light_Vertex(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale)
2591 // OpenGL 1.1 path (anything)
2592 float ambientcolorbase[3], diffusecolorbase[3];
2593 float ambientcolorpants[3], diffusecolorpants[3];
2594 float ambientcolorshirt[3], diffusecolorshirt[3];
2595 const float *surfacecolor = rsurface.texture->dlightcolor;
2596 const float *surfacepants = rsurface.colormap_pantscolor;
2597 const float *surfaceshirt = rsurface.colormap_shirtcolor;
2598 rtexture_t *basetexture = rsurface.texture->basetexture;
2599 rtexture_t *pantstexture = rsurface.texture->pantstexture;
2600 rtexture_t *shirttexture = rsurface.texture->shirttexture;
2601 qboolean dopants = pantstexture && VectorLength2(surfacepants) >= (1.0f / 1048576.0f);
2602 qboolean doshirt = shirttexture && VectorLength2(surfaceshirt) >= (1.0f / 1048576.0f);
2603 ambientscale *= 2 * r_refdef.view.colorscale;
2604 diffusescale *= 2 * r_refdef.view.colorscale;
2605 ambientcolorbase[0] = lightcolor[0] * ambientscale * surfacecolor[0];ambientcolorbase[1] = lightcolor[1] * ambientscale * surfacecolor[1];ambientcolorbase[2] = lightcolor[2] * ambientscale * surfacecolor[2];
2606 diffusecolorbase[0] = lightcolor[0] * diffusescale * surfacecolor[0];diffusecolorbase[1] = lightcolor[1] * diffusescale * surfacecolor[1];diffusecolorbase[2] = lightcolor[2] * diffusescale * surfacecolor[2];
2607 ambientcolorpants[0] = ambientcolorbase[0] * surfacepants[0];ambientcolorpants[1] = ambientcolorbase[1] * surfacepants[1];ambientcolorpants[2] = ambientcolorbase[2] * surfacepants[2];
2608 diffusecolorpants[0] = diffusecolorbase[0] * surfacepants[0];diffusecolorpants[1] = diffusecolorbase[1] * surfacepants[1];diffusecolorpants[2] = diffusecolorbase[2] * surfacepants[2];
2609 ambientcolorshirt[0] = ambientcolorbase[0] * surfaceshirt[0];ambientcolorshirt[1] = ambientcolorbase[1] * surfaceshirt[1];ambientcolorshirt[2] = ambientcolorbase[2] * surfaceshirt[2];
2610 diffusecolorshirt[0] = diffusecolorbase[0] * surfaceshirt[0];diffusecolorshirt[1] = diffusecolorbase[1] * surfaceshirt[1];diffusecolorshirt[2] = diffusecolorbase[2] * surfaceshirt[2];
2611 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | (diffusescale > 0 ? BATCHNEED_ARRAY_NORMAL : 0) | BATCHNEED_ARRAY_TEXCOORD, texturenumsurfaces, texturesurfacelist);
2612 R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
2613 R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.array_passcolor4f, 0, 0);
2614 R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
2615 R_Mesh_TexBind(0, basetexture);
2616 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
2617 R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
2618 switch(r_shadow_rendermode)
2620 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2621 R_Mesh_TexBind(1, r_shadow_attenuation3dtexture);
2622 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
2623 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
2624 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
2626 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2627 R_Mesh_TexBind(2, r_shadow_attenuation2dtexture);
2628 R_Mesh_TexMatrix(2, &rsurface.entitytoattenuationz);
2629 R_Mesh_TexCombine(2, GL_MODULATE, GL_MODULATE, 1, 1);
2630 R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
2632 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2633 R_Mesh_TexBind(1, r_shadow_attenuation2dtexture);
2634 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
2635 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
2636 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
2638 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2643 //R_Mesh_TexBind(0, basetexture);
2644 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorbase, ambientcolorbase);
2647 R_Mesh_TexBind(0, pantstexture);
2648 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorpants, ambientcolorpants);
2652 R_Mesh_TexBind(0, shirttexture);
2653 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorshirt, ambientcolorshirt);
2657 extern cvar_t gl_lightmaps;
2658 void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
2660 float ambientscale, diffusescale, specularscale;
2662 float lightcolor[3];
2663 VectorCopy(rsurface.rtlight->currentcolor, lightcolor);
2664 ambientscale = rsurface.rtlight->ambientscale;
2665 diffusescale = rsurface.rtlight->diffusescale;
2666 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
2667 if (!r_shadow_usenormalmap.integer)
2669 ambientscale += 1.0f * diffusescale;
2673 if ((ambientscale + diffusescale) * VectorLength2(lightcolor) + specularscale * VectorLength2(lightcolor) < (1.0f / 1048576.0f))
2675 negated = (lightcolor[0] + lightcolor[1] + lightcolor[2] < 0) && vid.support.ext_blend_subtract;
2678 VectorNegate(lightcolor, lightcolor);
2679 switch(vid.renderpath)
2681 case RENDERPATH_GL11:
2682 case RENDERPATH_GL13:
2683 case RENDERPATH_GL20:
2684 case RENDERPATH_CGGL:
2685 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
2687 case RENDERPATH_D3D9:
2689 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_SUBTRACT);
2692 case RENDERPATH_D3D10:
2693 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2695 case RENDERPATH_D3D11:
2696 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2700 RSurf_SetupDepthAndCulling();
2701 switch (r_shadow_rendermode)
2703 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2704 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2705 R_Shadow_RenderLighting_VisibleLighting(texturenumsurfaces, texturesurfacelist);
2707 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2708 R_Shadow_RenderLighting_Light_GLSL(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale, specularscale);
2710 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2711 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2712 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2713 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2714 R_Shadow_RenderLighting_Light_Vertex(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale);
2717 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2722 switch(vid.renderpath)
2724 case RENDERPATH_GL11:
2725 case RENDERPATH_GL13:
2726 case RENDERPATH_GL20:
2727 case RENDERPATH_CGGL:
2728 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
2730 case RENDERPATH_D3D9:
2732 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_ADD);
2735 case RENDERPATH_D3D10:
2736 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2738 case RENDERPATH_D3D11:
2739 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2745 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)
2747 matrix4x4_t tempmatrix = *matrix;
2748 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
2750 // if this light has been compiled before, free the associated data
2751 R_RTLight_Uncompile(rtlight);
2753 // clear it completely to avoid any lingering data
2754 memset(rtlight, 0, sizeof(*rtlight));
2756 // copy the properties
2757 rtlight->matrix_lighttoworld = tempmatrix;
2758 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
2759 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
2760 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
2761 VectorCopy(color, rtlight->color);
2762 rtlight->cubemapname[0] = 0;
2763 if (cubemapname && cubemapname[0])
2764 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
2765 rtlight->shadow = shadow;
2766 rtlight->corona = corona;
2767 rtlight->style = style;
2768 rtlight->isstatic = isstatic;
2769 rtlight->coronasizescale = coronasizescale;
2770 rtlight->ambientscale = ambientscale;
2771 rtlight->diffusescale = diffusescale;
2772 rtlight->specularscale = specularscale;
2773 rtlight->flags = flags;
2775 // compute derived data
2776 //rtlight->cullradius = rtlight->radius;
2777 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2778 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2779 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2780 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2781 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2782 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2783 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2786 // compiles rtlight geometry
2787 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2788 void R_RTLight_Compile(rtlight_t *rtlight)
2791 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
2792 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
2793 entity_render_t *ent = r_refdef.scene.worldentity;
2794 dp_model_t *model = r_refdef.scene.worldmodel;
2795 unsigned char *data;
2798 // compile the light
2799 rtlight->compiled = true;
2800 rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
2801 rtlight->static_numleafs = 0;
2802 rtlight->static_numleafpvsbytes = 0;
2803 rtlight->static_leaflist = NULL;
2804 rtlight->static_leafpvs = NULL;
2805 rtlight->static_numsurfaces = 0;
2806 rtlight->static_surfacelist = NULL;
2807 rtlight->static_shadowmap_receivers = 0x3F;
2808 rtlight->static_shadowmap_casters = 0x3F;
2809 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2810 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2811 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2812 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2813 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2814 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2816 if (model && model->GetLightInfo)
2818 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
2819 r_shadow_compilingrtlight = rtlight;
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 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2822 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
2823 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
2824 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
2825 rtlight->static_numsurfaces = numsurfaces;
2826 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
2827 rtlight->static_numleafs = numleafs;
2828 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
2829 rtlight->static_numleafpvsbytes = numleafpvsbytes;
2830 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
2831 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
2832 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
2833 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
2834 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
2835 if (rtlight->static_numsurfaces)
2836 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
2837 if (rtlight->static_numleafs)
2838 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
2839 if (rtlight->static_numleafpvsbytes)
2840 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
2841 if (rtlight->static_numshadowtrispvsbytes)
2842 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
2843 if (rtlight->static_numlighttrispvsbytes)
2844 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
2845 switch (rtlight->shadowmode)
2847 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2848 if (model->CompileShadowMap && rtlight->shadow)
2849 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2852 if (model->CompileShadowVolume && rtlight->shadow)
2853 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2856 // now we're done compiling the rtlight
2857 r_shadow_compilingrtlight = NULL;
2861 // use smallest available cullradius - box radius or light radius
2862 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2863 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2865 shadowzpasstris = 0;
2866 if (rtlight->static_meshchain_shadow_zpass)
2867 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
2868 shadowzpasstris += mesh->numtriangles;
2870 shadowzfailtris = 0;
2871 if (rtlight->static_meshchain_shadow_zfail)
2872 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
2873 shadowzfailtris += mesh->numtriangles;
2876 if (rtlight->static_numlighttrispvsbytes)
2877 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
2878 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
2882 if (rtlight->static_numlighttrispvsbytes)
2883 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
2884 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
2887 if (developer_extra.integer)
2888 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);
2891 void R_RTLight_Uncompile(rtlight_t *rtlight)
2893 if (rtlight->compiled)
2895 if (rtlight->static_meshchain_shadow_zpass)
2896 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
2897 rtlight->static_meshchain_shadow_zpass = NULL;
2898 if (rtlight->static_meshchain_shadow_zfail)
2899 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
2900 rtlight->static_meshchain_shadow_zfail = NULL;
2901 if (rtlight->static_meshchain_shadow_shadowmap)
2902 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
2903 rtlight->static_meshchain_shadow_shadowmap = NULL;
2904 // these allocations are grouped
2905 if (rtlight->static_surfacelist)
2906 Mem_Free(rtlight->static_surfacelist);
2907 rtlight->static_numleafs = 0;
2908 rtlight->static_numleafpvsbytes = 0;
2909 rtlight->static_leaflist = NULL;
2910 rtlight->static_leafpvs = NULL;
2911 rtlight->static_numsurfaces = 0;
2912 rtlight->static_surfacelist = NULL;
2913 rtlight->static_numshadowtrispvsbytes = 0;
2914 rtlight->static_shadowtrispvs = NULL;
2915 rtlight->static_numlighttrispvsbytes = 0;
2916 rtlight->static_lighttrispvs = NULL;
2917 rtlight->compiled = false;
2921 void R_Shadow_UncompileWorldLights(void)
2925 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
2926 for (lightindex = 0;lightindex < range;lightindex++)
2928 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2931 R_RTLight_Uncompile(&light->rtlight);
2935 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
2939 // reset the count of frustum planes
2940 // see rtlight->cached_frustumplanes definition for how much this array
2942 rtlight->cached_numfrustumplanes = 0;
2944 // haven't implemented a culling path for ortho rendering
2945 if (!r_refdef.view.useperspective)
2947 // check if the light is on screen and copy the 4 planes if it is
2948 for (i = 0;i < 4;i++)
2949 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
2952 for (i = 0;i < 4;i++)
2953 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
2958 // generate a deformed frustum that includes the light origin, this is
2959 // used to cull shadow casting surfaces that can not possibly cast a
2960 // shadow onto the visible light-receiving surfaces, which can be a
2963 // if the light origin is onscreen the result will be 4 planes exactly
2964 // if the light origin is offscreen on only one axis the result will
2965 // be exactly 5 planes (split-side case)
2966 // if the light origin is offscreen on two axes the result will be
2967 // exactly 4 planes (stretched corner case)
2968 for (i = 0;i < 4;i++)
2970 // quickly reject standard frustum planes that put the light
2971 // origin outside the frustum
2972 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
2975 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
2977 // if all the standard frustum planes were accepted, the light is onscreen
2978 // otherwise we need to generate some more planes below...
2979 if (rtlight->cached_numfrustumplanes < 4)
2981 // at least one of the stock frustum planes failed, so we need to
2982 // create one or two custom planes to enclose the light origin
2983 for (i = 0;i < 4;i++)
2985 // create a plane using the view origin and light origin, and a
2986 // single point from the frustum corner set
2987 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
2988 VectorNormalize(plane.normal);
2989 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
2990 // see if this plane is backwards and flip it if so
2991 for (j = 0;j < 4;j++)
2992 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
2996 VectorNegate(plane.normal, plane.normal);
2998 // flipped plane, test again to see if it is now valid
2999 for (j = 0;j < 4;j++)
3000 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3002 // if the plane is still not valid, then it is dividing the
3003 // frustum and has to be rejected
3007 // we have created a valid plane, compute extra info
3008 PlaneClassify(&plane);
3010 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3012 // if we've found 5 frustum planes then we have constructed a
3013 // proper split-side case and do not need to keep searching for
3014 // planes to enclose the light origin
3015 if (rtlight->cached_numfrustumplanes == 5)
3023 for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
3025 plane = rtlight->cached_frustumplanes[i];
3026 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));
3031 // now add the light-space box planes if the light box is rotated, as any
3032 // caster outside the oriented light box is irrelevant (even if it passed
3033 // the worldspace light box, which is axial)
3034 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3036 for (i = 0;i < 6;i++)
3040 v[i >> 1] = (i & 1) ? -1 : 1;
3041 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3042 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3043 plane.dist = VectorNormalizeLength(plane.normal);
3044 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3045 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3051 // add the world-space reduced box planes
3052 for (i = 0;i < 6;i++)
3054 VectorClear(plane.normal);
3055 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3056 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
3057 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3066 // reduce all plane distances to tightly fit the rtlight cull box, which
3068 VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3069 VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3070 VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3071 VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3072 VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3073 VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3074 VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3075 VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3076 oldnum = rtlight->cached_numfrustumplanes;
3077 rtlight->cached_numfrustumplanes = 0;
3078 for (j = 0;j < oldnum;j++)
3080 // find the nearest point on the box to this plane
3081 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
3082 for (i = 1;i < 8;i++)
3084 dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
3085 if (bestdist > dist)
3088 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);
3089 // if the nearest point is near or behind the plane, we want this
3090 // plane, otherwise the plane is useless as it won't cull anything
3091 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
3093 PlaneClassify(&rtlight->cached_frustumplanes[j]);
3094 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
3101 void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
3105 RSurf_ActiveWorldEntity();
3107 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3110 GL_CullFace(GL_NONE);
3111 mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3112 for (;mesh;mesh = mesh->next)
3114 if (!mesh->sidetotals[r_shadow_shadowmapside])
3116 r_refdef.stats.lights_shadowtriangles += mesh->sidetotals[r_shadow_shadowmapside];
3117 R_Mesh_PrepareVertices_Position(mesh->numverts, mesh->vertexposition, mesh->vertexpositionbuffer);
3118 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);
3122 else if (r_refdef.scene.worldentity->model)
3123 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);
3125 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3128 void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3130 qboolean zpass = false;
3133 int surfacelistindex;
3134 msurface_t *surface;
3136 // if triangle neighbors are disabled, shadowvolumes are disabled
3137 if (r_refdef.scene.worldmodel->brush.shadowmesh ? !r_refdef.scene.worldmodel->brush.shadowmesh->neighbor3i : !r_refdef.scene.worldmodel->surfmesh.data_neighbor3i)
3140 RSurf_ActiveWorldEntity();
3142 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3145 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
3147 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
3148 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
3150 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
3151 for (;mesh;mesh = mesh->next)
3153 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
3154 R_Mesh_PrepareVertices_Position(mesh->numverts, mesh->vertexposition, mesh->vertexpositionbuffer);
3155 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
3157 // increment stencil if frontface is infront of depthbuffer
3158 GL_CullFace(r_refdef.view.cullface_back);
3159 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
3160 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);
3161 // decrement stencil if backface is infront of depthbuffer
3162 GL_CullFace(r_refdef.view.cullface_front);
3163 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
3165 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
3167 // decrement stencil if backface is behind depthbuffer
3168 GL_CullFace(r_refdef.view.cullface_front);
3169 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
3170 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);
3171 // increment stencil if frontface is behind depthbuffer
3172 GL_CullFace(r_refdef.view.cullface_back);
3173 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
3175 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);
3179 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh)
3181 // use the shadow trispvs calculated earlier by GetLightInfo to cull world triangles on this dynamic light
3182 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
3183 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
3185 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
3186 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
3187 if (CHECKPVSBIT(trispvs, t))
3188 shadowmarklist[numshadowmark++] = t;
3190 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);
3192 else if (numsurfaces)
3194 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);
3197 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3200 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3202 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3203 vec_t relativeshadowradius;
3204 RSurf_ActiveModelEntity(ent, false, false, false);
3205 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3206 // we need to re-init the shader for each entity because the matrix changed
3207 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3208 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3209 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3210 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3211 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3212 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3213 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3214 switch (r_shadow_rendermode)
3216 case R_SHADOW_RENDERMODE_SHADOWMAP2D:
3217 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
3220 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3223 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3226 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3228 // set up properties for rendering light onto this entity
3229 RSurf_ActiveModelEntity(ent, true, true, false);
3230 GL_AlphaTest(false);
3231 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3232 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3233 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3234 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3237 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
3239 if (!r_refdef.scene.worldmodel->DrawLight)
3242 // set up properties for rendering light onto this entity
3243 RSurf_ActiveWorldEntity();
3244 GL_AlphaTest(false);
3245 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3246 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3247 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3248 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3250 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
3252 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3255 void R_Shadow_DrawEntityLight(entity_render_t *ent)
3257 dp_model_t *model = ent->model;
3258 if (!model->DrawLight)
3261 R_Shadow_SetupEntityLight(ent);
3263 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3265 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3268 void R_Shadow_PrepareLight(rtlight_t *rtlight)
3272 int numleafs, numsurfaces;
3273 int *leaflist, *surfacelist;
3274 unsigned char *leafpvs;
3275 unsigned char *shadowtrispvs;
3276 unsigned char *lighttrispvs;
3277 //unsigned char *surfacesides;
3278 int numlightentities;
3279 int numlightentities_noselfshadow;
3280 int numshadowentities;
3281 int numshadowentities_noselfshadow;
3282 static entity_render_t *lightentities[MAX_EDICTS];
3283 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3284 static entity_render_t *shadowentities[MAX_EDICTS];
3285 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3288 rtlight->draw = false;
3290 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3291 // skip lights that are basically invisible (color 0 0 0)
3292 nolight = VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f);
3294 // loading is done before visibility checks because loading should happen
3295 // all at once at the start of a level, not when it stalls gameplay.
3296 // (especially important to benchmarks)
3298 if (rtlight->isstatic && !nolight && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
3300 if (rtlight->compiled)
3301 R_RTLight_Uncompile(rtlight);
3302 R_RTLight_Compile(rtlight);
3306 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
3308 // look up the light style value at this time
3309 f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3310 VectorScale(rtlight->color, f, rtlight->currentcolor);
3312 if (rtlight->selected)
3314 f = 2 + sin(realtime * M_PI * 4.0);
3315 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3319 // if lightstyle is currently off, don't draw the light
3320 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3323 // skip processing on corona-only lights
3327 // if the light box is offscreen, skip it
3328 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3331 VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
3332 VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
3334 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3336 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3338 // compiled light, world available and can receive realtime lighting
3339 // retrieve leaf information
3340 numleafs = rtlight->static_numleafs;
3341 leaflist = rtlight->static_leaflist;
3342 leafpvs = rtlight->static_leafpvs;
3343 numsurfaces = rtlight->static_numsurfaces;
3344 surfacelist = rtlight->static_surfacelist;
3345 //surfacesides = NULL;
3346 shadowtrispvs = rtlight->static_shadowtrispvs;
3347 lighttrispvs = rtlight->static_lighttrispvs;
3349 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3351 // dynamic light, world available and can receive realtime lighting
3352 // calculate lit surfaces and leafs
3353 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);
3354 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3355 leaflist = r_shadow_buffer_leaflist;
3356 leafpvs = r_shadow_buffer_leafpvs;
3357 surfacelist = r_shadow_buffer_surfacelist;
3358 //surfacesides = r_shadow_buffer_surfacesides;
3359 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3360 lighttrispvs = r_shadow_buffer_lighttrispvs;
3361 // if the reduced leaf bounds are offscreen, skip it
3362 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3373 //surfacesides = NULL;
3374 shadowtrispvs = NULL;
3375 lighttrispvs = NULL;
3377 // check if light is illuminating any visible leafs
3380 for (i = 0;i < numleafs;i++)
3381 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3387 // make a list of lit entities and shadow casting entities
3388 numlightentities = 0;
3389 numlightentities_noselfshadow = 0;
3390 numshadowentities = 0;
3391 numshadowentities_noselfshadow = 0;
3393 // add dynamic entities that are lit by the light
3394 for (i = 0;i < r_refdef.scene.numentities;i++)
3397 entity_render_t *ent = r_refdef.scene.entities[i];
3399 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3401 // skip the object entirely if it is not within the valid
3402 // shadow-casting region (which includes the lit region)
3403 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
3405 if (!(model = ent->model))
3407 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
3409 // this entity wants to receive light, is visible, and is
3410 // inside the light box
3411 // TODO: check if the surfaces in the model can receive light
3412 // so now check if it's in a leaf seen by the light
3413 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))
3415 if (ent->flags & RENDER_NOSELFSHADOW)
3416 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
3418 lightentities[numlightentities++] = ent;
3419 // since it is lit, it probably also casts a shadow...
3420 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3421 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3422 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3424 // note: exterior models without the RENDER_NOSELFSHADOW
3425 // flag still create a RENDER_NOSELFSHADOW shadow but
3426 // are lit normally, this means that they are
3427 // self-shadowing but do not shadow other
3428 // RENDER_NOSELFSHADOW entities such as the gun
3429 // (very weird, but keeps the player shadow off the gun)
3430 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3431 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3433 shadowentities[numshadowentities++] = ent;
3436 else if (ent->flags & RENDER_SHADOW)
3438 // this entity is not receiving light, but may still need to
3440 // TODO: check if the surfaces in the model can cast shadow
3441 // now check if it is in a leaf seen by the light
3442 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))
3444 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3445 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3446 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3448 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3449 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3451 shadowentities[numshadowentities++] = ent;
3456 // return if there's nothing at all to light
3457 if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
3460 // count this light in the r_speeds
3461 r_refdef.stats.lights++;
3463 // flag it as worth drawing later
3464 rtlight->draw = true;
3466 // cache all the animated entities that cast a shadow but are not visible
3467 for (i = 0;i < numshadowentities;i++)
3468 if (!shadowentities[i]->animcache_vertex3f)
3469 R_AnimCache_GetEntity(shadowentities[i], false, false);
3470 for (i = 0;i < numshadowentities_noselfshadow;i++)
3471 if (!shadowentities_noselfshadow[i]->animcache_vertex3f)
3472 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
3474 // allocate some temporary memory for rendering this light later in the frame
3475 // reusable buffers need to be copied, static data can be used as-is
3476 rtlight->cached_numlightentities = numlightentities;
3477 rtlight->cached_numlightentities_noselfshadow = numlightentities_noselfshadow;
3478 rtlight->cached_numshadowentities = numshadowentities;
3479 rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
3480 rtlight->cached_numsurfaces = numsurfaces;
3481 rtlight->cached_lightentities = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
3482 rtlight->cached_lightentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
3483 rtlight->cached_shadowentities = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
3484 rtlight->cached_shadowentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
3485 if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
3487 int numshadowtrispvsbytes = (((r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles) + 7) >> 3);
3488 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
3489 rtlight->cached_shadowtrispvs = (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
3490 rtlight->cached_lighttrispvs = (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
3491 rtlight->cached_surfacelist = (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
3495 // compiled light data
3496 rtlight->cached_shadowtrispvs = shadowtrispvs;
3497 rtlight->cached_lighttrispvs = lighttrispvs;
3498 rtlight->cached_surfacelist = surfacelist;
3502 void R_Shadow_DrawLight(rtlight_t *rtlight)
3506 unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
3507 int numlightentities;
3508 int numlightentities_noselfshadow;
3509 int numshadowentities;
3510 int numshadowentities_noselfshadow;
3511 entity_render_t **lightentities;
3512 entity_render_t **lightentities_noselfshadow;
3513 entity_render_t **shadowentities;
3514 entity_render_t **shadowentities_noselfshadow;
3516 static unsigned char entitysides[MAX_EDICTS];
3517 static unsigned char entitysides_noselfshadow[MAX_EDICTS];
3518 vec3_t nearestpoint;
3520 qboolean castshadows;
3523 // check if we cached this light this frame (meaning it is worth drawing)
3527 // if R_FrameData_Store ran out of space we skip anything dependent on it
3528 if (r_framedata_failed)
3531 numlightentities = rtlight->cached_numlightentities;
3532 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
3533 numshadowentities = rtlight->cached_numshadowentities;
3534 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
3535 numsurfaces = rtlight->cached_numsurfaces;
3536 lightentities = rtlight->cached_lightentities;
3537 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
3538 shadowentities = rtlight->cached_shadowentities;
3539 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
3540 shadowtrispvs = rtlight->cached_shadowtrispvs;
3541 lighttrispvs = rtlight->cached_lighttrispvs;
3542 surfacelist = rtlight->cached_surfacelist;
3544 // set up a scissor rectangle for this light
3545 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3548 // don't let sound skip if going slow
3549 if (r_refdef.scene.extraupdate)
3552 // make this the active rtlight for rendering purposes
3553 R_Shadow_RenderMode_ActiveLight(rtlight);
3555 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
3557 // optionally draw visible shape of the shadow volumes
3558 // for performance analysis by level designers
3559 R_Shadow_RenderMode_VisibleShadowVolumes();
3561 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
3562 for (i = 0;i < numshadowentities;i++)
3563 R_Shadow_DrawEntityShadow(shadowentities[i]);
3564 for (i = 0;i < numshadowentities_noselfshadow;i++)
3565 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3566 R_Shadow_RenderMode_VisibleLighting(false, false);
3569 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
3571 // optionally draw the illuminated areas
3572 // for performance analysis by level designers
3573 R_Shadow_RenderMode_VisibleLighting(false, false);
3575 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3576 for (i = 0;i < numlightentities;i++)
3577 R_Shadow_DrawEntityLight(lightentities[i]);
3578 for (i = 0;i < numlightentities_noselfshadow;i++)
3579 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3582 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
3584 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
3585 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
3586 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
3587 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
3589 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance/rtlight->radius));
3590 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
3591 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
3593 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
3599 int receivermask = 0;
3600 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
3601 Matrix4x4_Abs(&radiustolight);
3603 r_shadow_shadowmaplod = 0;
3604 for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
3605 if ((r_shadow_shadowmapmaxsize >> i) > lodlinear)
3606 r_shadow_shadowmaplod = i;
3608 size = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
3610 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
3612 surfacesides = NULL;
3615 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3617 castermask = rtlight->static_shadowmap_casters;
3618 receivermask = rtlight->static_shadowmap_receivers;
3622 surfacesides = r_shadow_buffer_surfacesides;
3623 for(i = 0;i < numsurfaces;i++)
3625 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
3626 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3627 castermask |= surfacesides[i];
3628 receivermask |= surfacesides[i];
3632 if (receivermask < 0x3F)
3634 for (i = 0;i < numlightentities;i++)
3635 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3636 if (receivermask < 0x3F)
3637 for(i = 0; i < numlightentities_noselfshadow;i++)
3638 receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3641 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
3645 for (i = 0;i < numshadowentities;i++)
3646 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3647 for (i = 0;i < numshadowentities_noselfshadow;i++)
3648 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3651 //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
3653 // render shadow casters into 6 sided depth texture
3654 for (side = 0;side < 6;side++) if (receivermask & (1 << side))
3656 R_Shadow_RenderMode_ShadowMap(side, receivermask, size);
3657 if (! (castermask & (1 << side))) continue;
3659 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
3660 for (i = 0;i < numshadowentities;i++) if (entitysides[i] & (1 << side))
3661 R_Shadow_DrawEntityShadow(shadowentities[i]);
3664 if (numlightentities_noselfshadow)
3666 // render lighting using the depth texture as shadowmap
3667 // draw lighting in the unmasked areas
3668 R_Shadow_RenderMode_Lighting(false, false, true);
3669 for (i = 0;i < numlightentities_noselfshadow;i++)
3670 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3673 // render shadow casters into 6 sided depth texture
3674 if (numshadowentities_noselfshadow)
3676 for (side = 0;side < 6;side++) if ((receivermask & castermask) & (1 << side))
3678 R_Shadow_RenderMode_ShadowMap(side, 0, size);
3679 for (i = 0;i < numshadowentities_noselfshadow;i++) if (entitysides_noselfshadow[i] & (1 << side))
3680 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3684 // render lighting using the depth texture as shadowmap
3685 // draw lighting in the unmasked areas
3686 R_Shadow_RenderMode_Lighting(false, false, true);
3687 // draw lighting in the unmasked areas
3689 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3690 for (i = 0;i < numlightentities;i++)
3691 R_Shadow_DrawEntityLight(lightentities[i]);
3693 else if (castshadows && vid.stencil)
3695 // draw stencil shadow volumes to mask off pixels that are in shadow
3696 // so that they won't receive lighting
3697 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
3698 R_Shadow_ClearStencil();
3701 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
3702 for (i = 0;i < numshadowentities;i++)
3703 R_Shadow_DrawEntityShadow(shadowentities[i]);
3705 // draw lighting in the unmasked areas
3706 R_Shadow_RenderMode_Lighting(true, false, false);
3707 for (i = 0;i < numlightentities_noselfshadow;i++)
3708 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3710 for (i = 0;i < numshadowentities_noselfshadow;i++)
3711 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3713 // draw lighting in the unmasked areas
3714 R_Shadow_RenderMode_Lighting(true, false, false);
3716 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3717 for (i = 0;i < numlightentities;i++)
3718 R_Shadow_DrawEntityLight(lightentities[i]);
3722 // draw lighting in the unmasked areas
3723 R_Shadow_RenderMode_Lighting(false, false, false);
3725 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3726 for (i = 0;i < numlightentities;i++)
3727 R_Shadow_DrawEntityLight(lightentities[i]);
3728 for (i = 0;i < numlightentities_noselfshadow;i++)
3729 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3732 if (r_shadow_usingdeferredprepass)
3734 // when rendering deferred lighting, we simply rasterize the box
3735 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
3736 R_Shadow_RenderMode_DrawDeferredLight(false, true);
3737 else if (castshadows && vid.stencil)
3738 R_Shadow_RenderMode_DrawDeferredLight(true, false);
3740 R_Shadow_RenderMode_DrawDeferredLight(false, false);
3744 static void R_Shadow_FreeDeferred(void)
3746 R_Mesh_DestroyFramebufferObject(r_shadow_prepassgeometryfbo);
3747 r_shadow_prepassgeometryfbo = 0;
3749 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingfbo);
3750 r_shadow_prepasslightingfbo = 0;
3752 if (r_shadow_prepassgeometrydepthtexture)
3753 R_FreeTexture(r_shadow_prepassgeometrydepthtexture);
3754 r_shadow_prepassgeometrydepthtexture = NULL;
3756 if (r_shadow_prepassgeometrydepthcolortexture)
3757 R_FreeTexture(r_shadow_prepassgeometrydepthcolortexture);
3758 r_shadow_prepassgeometrydepthcolortexture = NULL;
3760 if (r_shadow_prepassgeometrynormalmaptexture)
3761 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
3762 r_shadow_prepassgeometrynormalmaptexture = NULL;
3764 if (r_shadow_prepasslightingdiffusetexture)
3765 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
3766 r_shadow_prepasslightingdiffusetexture = NULL;
3768 if (r_shadow_prepasslightingspeculartexture)
3769 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
3770 r_shadow_prepasslightingspeculartexture = NULL;
3773 void R_Shadow_DrawPrepass(void)
3781 entity_render_t *ent;
3782 float clearcolor[4];
3784 GL_AlphaTest(false);
3785 R_Mesh_ResetTextureState();
3787 GL_ColorMask(1,1,1,1);
3788 GL_BlendFunc(GL_ONE, GL_ZERO);
3791 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, r_shadow_prepassgeometrydepthcolortexture, NULL, NULL);
3792 Vector4Set(clearcolor, 0.5f,0.5f,0.5f,1.0f);
3793 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
3794 if (r_timereport_active)
3795 R_TimeReport("prepasscleargeom");
3797 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
3798 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
3799 if (r_timereport_active)
3800 R_TimeReport("prepassworld");
3802 for (i = 0;i < r_refdef.scene.numentities;i++)
3804 if (!r_refdef.viewcache.entityvisible[i])
3806 ent = r_refdef.scene.entities[i];
3807 if (ent->model && ent->model->DrawPrepass != NULL)
3808 ent->model->DrawPrepass(ent);
3811 if (r_timereport_active)
3812 R_TimeReport("prepassmodels");
3814 GL_DepthMask(false);
3815 GL_ColorMask(1,1,1,1);
3818 R_Mesh_SetRenderTargets(r_shadow_prepasslightingfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
3819 Vector4Set(clearcolor, 0, 0, 0, 0);
3820 GL_Clear(GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
3821 if (r_timereport_active)
3822 R_TimeReport("prepassclearlit");
3824 R_Shadow_RenderMode_Begin();
3826 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3827 if (r_shadow_debuglight.integer >= 0)
3829 lightindex = r_shadow_debuglight.integer;
3830 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3831 if (light && (light->flags & flag) && light->rtlight.draw)
3832 R_Shadow_DrawLight(&light->rtlight);
3836 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3837 for (lightindex = 0;lightindex < range;lightindex++)
3839 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3840 if (light && (light->flags & flag) && light->rtlight.draw)
3841 R_Shadow_DrawLight(&light->rtlight);
3844 if (r_refdef.scene.rtdlight)
3845 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
3846 if (r_refdef.scene.lights[lnum]->draw)
3847 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
3849 R_Mesh_ResetRenderTargets();
3851 R_Shadow_RenderMode_End();
3853 if (r_timereport_active)
3854 R_TimeReport("prepasslights");
3857 void R_Shadow_DrawLightSprites(void);
3858 void R_Shadow_PrepareLights(void)
3868 if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4) ||
3869 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
3870 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20) ||
3871 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
3872 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
3873 r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
3874 R_Shadow_FreeShadowMaps();
3876 r_shadow_usingshadowmaportho = false;
3878 switch (vid.renderpath)
3880 case RENDERPATH_GL20:
3881 case RENDERPATH_CGGL:
3882 case RENDERPATH_D3D9:
3883 case RENDERPATH_D3D10:
3884 case RENDERPATH_D3D11:
3885 if (!r_shadow_deferred.integer || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_STENCIL || !vid.support.ext_framebuffer_object || vid.maxdrawbuffers < 2)
3887 r_shadow_usingdeferredprepass = false;
3888 if (r_shadow_prepass_width)
3889 R_Shadow_FreeDeferred();
3890 r_shadow_prepass_width = r_shadow_prepass_height = 0;
3894 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
3896 R_Shadow_FreeDeferred();
3898 r_shadow_usingdeferredprepass = true;
3899 r_shadow_prepass_width = vid.width;
3900 r_shadow_prepass_height = vid.height;
3901 r_shadow_prepassgeometrydepthtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "prepassgeometrydepthmap", vid.width, vid.height, 24, false);
3902 switch (vid.renderpath)
3904 case RENDERPATH_D3D9:
3905 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);
3910 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);
3911 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);
3912 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);
3914 // set up the geometry pass fbo (depth + normalmap)
3915 r_shadow_prepassgeometryfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
3916 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, r_shadow_prepassgeometrydepthcolortexture, NULL, NULL);
3917 // render depth into one texture and normalmap into the other
3918 if (qglDrawBuffersARB)
3920 qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);CHECKGLERROR
3921 qglReadBuffer(GL_NONE);CHECKGLERROR
3922 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
3923 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
3925 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
3926 Cvar_SetValueQuick(&r_shadow_deferred, 0);
3927 r_shadow_usingdeferredprepass = false;
3931 // set up the lighting pass fbo (diffuse + specular)
3932 r_shadow_prepasslightingfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
3933 R_Mesh_SetRenderTargets(r_shadow_prepasslightingfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
3934 // render diffuse into one texture and specular into another,
3935 // with depth and normalmap bound as textures,
3936 // with depth bound as attachment as well
3937 if (qglDrawBuffersARB)
3939 qglDrawBuffersARB(2, r_shadow_prepasslightingdrawbuffers);CHECKGLERROR
3940 qglReadBuffer(GL_NONE);CHECKGLERROR
3941 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
3942 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
3944 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
3945 Cvar_SetValueQuick(&r_shadow_deferred, 0);
3946 r_shadow_usingdeferredprepass = false;
3951 case RENDERPATH_GL13:
3952 case RENDERPATH_GL11:
3953 r_shadow_usingdeferredprepass = false;
3957 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);
3959 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3960 if (r_shadow_debuglight.integer >= 0)
3962 lightindex = r_shadow_debuglight.integer;
3963 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3964 if (light && (light->flags & flag))
3965 R_Shadow_PrepareLight(&light->rtlight);
3969 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3970 for (lightindex = 0;lightindex < range;lightindex++)
3972 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3973 if (light && (light->flags & flag))
3974 R_Shadow_PrepareLight(&light->rtlight);
3977 if (r_refdef.scene.rtdlight)
3979 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
3980 R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
3982 else if(gl_flashblend.integer)
3984 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
3986 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
3987 f = (rtlight->style >= 0 ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3988 VectorScale(rtlight->color, f, rtlight->currentcolor);
3992 if (r_editlights.integer)
3993 R_Shadow_DrawLightSprites();
3996 void R_Shadow_DrawLights(void)
4004 R_Shadow_RenderMode_Begin();
4006 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4007 if (r_shadow_debuglight.integer >= 0)
4009 lightindex = r_shadow_debuglight.integer;
4010 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4011 if (light && (light->flags & flag))
4012 R_Shadow_DrawLight(&light->rtlight);
4016 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4017 for (lightindex = 0;lightindex < range;lightindex++)
4019 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4020 if (light && (light->flags & flag))
4021 R_Shadow_DrawLight(&light->rtlight);
4024 if (r_refdef.scene.rtdlight)
4025 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4026 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4028 R_Shadow_RenderMode_End();
4031 extern const float r_screenvertex3f[12];
4032 extern void R_SetupView(qboolean allowwaterclippingplane);
4033 extern void R_ResetViewRendering3D(void);
4034 extern void R_ResetViewRendering2D(void);
4035 extern cvar_t r_shadows;
4036 extern cvar_t r_shadows_darken;
4037 extern cvar_t r_shadows_drawafterrtlighting;
4038 extern cvar_t r_shadows_castfrombmodels;
4039 extern cvar_t r_shadows_throwdistance;
4040 extern cvar_t r_shadows_throwdirection;
4041 extern cvar_t r_shadows_focus;
4042 extern cvar_t r_shadows_shadowmapscale;
4044 void R_Shadow_PrepareModelShadows(void)
4047 float scale, size, radius, dot1, dot2;
4048 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
4049 entity_render_t *ent;
4051 if (!r_refdef.scene.numentities)
4054 switch (r_shadow_shadowmode)
4056 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4057 if (r_shadows.integer >= 2)
4060 case R_SHADOW_SHADOWMODE_STENCIL:
4061 for (i = 0;i < r_refdef.scene.numentities;i++)
4063 ent = r_refdef.scene.entities[i];
4064 if (!ent->animcache_vertex3f && ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4065 R_AnimCache_GetEntity(ent, false, false);
4072 size = 2*r_shadow_shadowmapmaxsize;
4073 scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
4074 radius = 0.5f * size / scale;
4076 Math_atov(r_shadows_throwdirection.string, shadowdir);
4077 VectorNormalize(shadowdir);
4078 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4079 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4080 if (fabs(dot1) <= fabs(dot2))
4081 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4083 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4084 VectorNormalize(shadowforward);
4085 CrossProduct(shadowdir, shadowforward, shadowright);
4086 Math_atov(r_shadows_focus.string, shadowfocus);
4087 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4088 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4089 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4090 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4091 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4093 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4095 shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4096 shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4097 shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4098 shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4099 shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4100 shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4102 for (i = 0;i < r_refdef.scene.numentities;i++)
4104 ent = r_refdef.scene.entities[i];
4105 if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
4107 // cast shadows from anything of the map (submodels are optional)
4108 if (!ent->animcache_vertex3f && ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4109 R_AnimCache_GetEntity(ent, false, false);
4113 void R_DrawModelShadowMaps(void)
4116 float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
4117 entity_render_t *ent;
4118 vec3_t relativelightorigin;
4119 vec3_t relativelightdirection, relativeforward, relativeright;
4120 vec3_t relativeshadowmins, relativeshadowmaxs;
4121 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
4123 matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
4124 r_viewport_t viewport;
4126 float clearcolor[4];
4128 if (!r_refdef.scene.numentities)
4131 switch (r_shadow_shadowmode)
4133 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4139 R_ResetViewRendering3D();
4140 R_Shadow_RenderMode_Begin();
4141 R_Shadow_RenderMode_ActiveLight(NULL);
4143 switch (r_shadow_shadowmode)
4145 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4146 if (!r_shadow_shadowmap2dtexture)
4147 R_Shadow_MakeShadowMap(0, r_shadow_shadowmapmaxsize);
4148 fbo = r_shadow_fbo2d;
4149 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
4150 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
4151 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
4157 size = 2*r_shadow_shadowmapmaxsize;
4158 scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
4159 radius = 0.5f / scale;
4160 nearclip = -r_shadows_throwdistance.value;
4161 farclip = r_shadows_throwdistance.value;
4162 bias = r_shadow_shadowmapping_bias.value * r_shadow_shadowmapping_nearclip.value / (2 * r_shadows_throwdistance.value) * (1024.0f / size);
4164 r_shadow_shadowmap_parameters[0] = size;
4165 r_shadow_shadowmap_parameters[1] = size;
4166 r_shadow_shadowmap_parameters[2] = 1.0;
4167 r_shadow_shadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
4169 Math_atov(r_shadows_throwdirection.string, shadowdir);
4170 VectorNormalize(shadowdir);
4171 Math_atov(r_shadows_focus.string, shadowfocus);
4172 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4173 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4174 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4175 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4176 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4177 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4178 if (fabs(dot1) <= fabs(dot2))
4179 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4181 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4182 VectorNormalize(shadowforward);
4183 VectorM(scale, shadowforward, &m[0]);
4184 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4186 m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
4187 CrossProduct(shadowdir, shadowforward, shadowright);
4188 VectorM(scale, shadowright, &m[4]);
4189 m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
4190 VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
4191 m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
4192 Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
4193 Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
4194 R_Viewport_InitOrtho(&viewport, &cameramatrix, 0, 0, size, size, 0, 0, 1, 1, 0, -1, NULL);
4196 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4198 R_Mesh_SetRenderTargets(fbo, r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
4199 R_SetupShader_DepthOrShadow();
4200 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
4203 R_SetViewport(&viewport);
4204 GL_Scissor(viewport.x, viewport.y, min(viewport.width + r_shadow_shadowmapborder, 2*r_shadow_shadowmapmaxsize), viewport.height + r_shadow_shadowmapborder);
4205 Vector4Set(clearcolor, 1,1,1,1);
4206 // in D3D9 we have to render to a color texture shadowmap
4207 // in GL we render directly to a depth texture only
4208 if (r_shadow_shadowmap2dtexture)
4209 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4211 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4212 // render into a slightly restricted region so that the borders of the
4213 // shadowmap area fade away, rather than streaking across everything
4214 // outside the usable area
4215 GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
4219 R_Mesh_ResetRenderTargets();
4220 R_SetupShader_ShowDepth();
4221 GL_ColorMask(1,1,1,1);
4222 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4225 for (i = 0;i < r_refdef.scene.numentities;i++)
4227 ent = r_refdef.scene.entities[i];
4229 // cast shadows from anything of the map (submodels are optional)
4230 if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4232 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4233 Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
4234 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4235 Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
4236 Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
4237 relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4238 relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4239 relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4240 relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4241 relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4242 relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4243 RSurf_ActiveModelEntity(ent, false, false, false);
4244 ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
4245 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4252 unsigned char *rawpixels = Z_Malloc(viewport.width*viewport.height*4);
4254 qglReadPixels(viewport.x, viewport.y, viewport.width, viewport.height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, rawpixels);
4256 Image_WriteTGABGRA("r_shadows_2.tga", viewport.width, viewport.height, rawpixels);
4257 Cvar_SetValueQuick(&r_test, 0);
4262 R_Shadow_RenderMode_End();
4264 Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
4265 Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
4266 Matrix4x4_CreateScale3(&scalematrix, size, -size, 1);
4267 Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
4268 Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
4269 Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
4271 switch (vid.renderpath)
4273 case RENDERPATH_GL11:
4274 case RENDERPATH_GL13:
4275 case RENDERPATH_GL20:
4276 case RENDERPATH_CGGL:
4278 case RENDERPATH_D3D9:
4279 case RENDERPATH_D3D10:
4280 case RENDERPATH_D3D11:
4281 #ifdef OPENGL_ORIENTATION
4282 r_shadow_shadowmapmatrix.m[0][0] *= -1.0f;
4283 r_shadow_shadowmapmatrix.m[0][1] *= -1.0f;
4284 r_shadow_shadowmapmatrix.m[0][2] *= -1.0f;
4285 r_shadow_shadowmapmatrix.m[0][3] *= -1.0f;
4287 r_shadow_shadowmapmatrix.m[0][0] *= -1.0f;
4288 r_shadow_shadowmapmatrix.m[1][0] *= -1.0f;
4289 r_shadow_shadowmapmatrix.m[2][0] *= -1.0f;
4290 r_shadow_shadowmapmatrix.m[3][0] *= -1.0f;
4295 r_shadow_usingshadowmaportho = true;
4296 switch (r_shadow_shadowmode)
4298 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4299 r_shadow_usingshadowmap2d = true;
4306 void R_DrawModelShadows(void)
4309 float relativethrowdistance;
4310 entity_render_t *ent;
4311 vec3_t relativelightorigin;
4312 vec3_t relativelightdirection;
4313 vec3_t relativeshadowmins, relativeshadowmaxs;
4314 vec3_t tmp, shadowdir;
4316 if (!r_refdef.scene.numentities || !vid.stencil || (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL && r_shadows.integer != 1))
4319 R_ResetViewRendering3D();
4320 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4321 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4322 R_Shadow_RenderMode_Begin();
4323 R_Shadow_RenderMode_ActiveLight(NULL);
4324 r_shadow_lightscissor[0] = r_refdef.view.x;
4325 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
4326 r_shadow_lightscissor[2] = r_refdef.view.width;
4327 r_shadow_lightscissor[3] = r_refdef.view.height;
4328 R_Shadow_RenderMode_StencilShadowVolumes(false);
4331 if (r_shadows.integer == 2)
4333 Math_atov(r_shadows_throwdirection.string, shadowdir);
4334 VectorNormalize(shadowdir);
4337 R_Shadow_ClearStencil();
4339 for (i = 0;i < r_refdef.scene.numentities;i++)
4341 ent = r_refdef.scene.entities[i];
4343 // cast shadows from anything of the map (submodels are optional)
4344 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4346 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4347 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
4348 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
4349 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
4350 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4353 if(ent->entitynumber != 0)
4355 if(ent->entitynumber >= MAX_EDICTS) // csqc entity
4357 // FIXME handle this
4358 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4362 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
4363 int entnum, entnum2, recursion;
4364 entnum = entnum2 = ent->entitynumber;
4365 for(recursion = 32; recursion > 0; --recursion)
4367 entnum2 = cl.entities[entnum].state_current.tagentity;
4368 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
4373 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
4375 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
4376 // transform into modelspace of OUR entity
4377 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
4378 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
4381 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4385 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4388 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
4389 RSurf_ActiveModelEntity(ent, false, false, false);
4390 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4391 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4395 // not really the right mode, but this will disable any silly stencil features
4396 R_Shadow_RenderMode_End();
4398 // set up ortho view for rendering this pass
4399 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4400 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4401 //GL_ScissorTest(true);
4402 //R_EntityMatrix(&identitymatrix);
4403 //R_Mesh_ResetTextureState();
4404 R_ResetViewRendering2D();
4406 // set up a darkening blend on shadowed areas
4407 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4408 //GL_DepthRange(0, 1);
4409 //GL_DepthTest(false);
4410 //GL_DepthMask(false);
4411 //GL_PolygonOffset(0, 0);CHECKGLERROR
4412 GL_Color(0, 0, 0, r_shadows_darken.value);
4413 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4414 //GL_DepthFunc(GL_ALWAYS);
4415 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_NOTEQUAL, 128, 255);
4417 // apply the blend to the shadowed areas
4418 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, NULL);
4419 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
4420 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4422 // restore the viewport
4423 R_SetViewport(&r_refdef.view.viewport);
4425 // restore other state to normal
4426 //R_Shadow_RenderMode_End();
4429 void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4432 vec3_t centerorigin;
4434 // if it's too close, skip it
4435 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
4437 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4440 if (usequery && r_numqueries + 2 <= r_maxqueries)
4442 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4443 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4444 // 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
4445 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4447 switch(vid.renderpath)
4449 case RENDERPATH_GL20:
4450 case RENDERPATH_GL13:
4451 case RENDERPATH_GL11:
4452 case RENDERPATH_CGGL:
4454 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use GL_DepthFunc instead
4455 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
4456 GL_DepthFunc(GL_ALWAYS);
4457 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4458 R_Mesh_PrepareVertices_Position_Arrays(4, vertex3f);
4459 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4460 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4461 GL_DepthFunc(GL_LEQUAL);
4462 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
4463 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4464 R_Mesh_PrepareVertices_Position_Arrays(4, vertex3f);
4465 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4466 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4469 case RENDERPATH_D3D9:
4470 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4472 case RENDERPATH_D3D10:
4473 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4475 case RENDERPATH_D3D11:
4476 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4480 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4483 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
4485 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4488 GLint allpixels = 0, visiblepixels = 0;
4489 // now we have to check the query result
4490 if (rtlight->corona_queryindex_visiblepixels)
4492 switch(vid.renderpath)
4494 case RENDERPATH_GL20:
4495 case RENDERPATH_GL13:
4496 case RENDERPATH_GL11:
4497 case RENDERPATH_CGGL:
4499 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
4500 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
4503 case RENDERPATH_D3D9:
4504 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4506 case RENDERPATH_D3D10:
4507 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4509 case RENDERPATH_D3D11:
4510 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4513 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
4514 if (visiblepixels < 1 || allpixels < 1)
4516 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
4517 cscale *= rtlight->corona_visibility;
4521 // FIXME: these traces should scan all render entities instead of cl.world
4522 if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
4525 VectorScale(rtlight->currentcolor, cscale, color);
4526 if (VectorLength(color) > (1.0f / 256.0f))
4529 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
4532 VectorNegate(color, color);
4533 switch(vid.renderpath)
4535 case RENDERPATH_GL11:
4536 case RENDERPATH_GL13:
4537 case RENDERPATH_GL20:
4538 case RENDERPATH_CGGL:
4539 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
4541 case RENDERPATH_D3D9:
4543 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_SUBTRACT);
4546 case RENDERPATH_D3D10:
4547 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4549 case RENDERPATH_D3D11:
4550 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4554 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4555 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);
4556 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4559 switch(vid.renderpath)
4561 case RENDERPATH_GL11:
4562 case RENDERPATH_GL13:
4563 case RENDERPATH_GL20:
4564 case RENDERPATH_CGGL:
4565 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
4567 case RENDERPATH_D3D9:
4569 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_ADD);
4572 case RENDERPATH_D3D10:
4573 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4575 case RENDERPATH_D3D11:
4576 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4583 void R_Shadow_DrawCoronas(void)
4586 qboolean usequery = false;
4591 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4593 if (r_waterstate.renderingscene)
4595 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4596 R_EntityMatrix(&identitymatrix);
4598 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4600 // check occlusion of coronas
4601 // use GL_ARB_occlusion_query if available
4602 // otherwise use raytraces
4604 switch (vid.renderpath)
4606 case RENDERPATH_GL11:
4607 case RENDERPATH_GL13:
4608 case RENDERPATH_GL20:
4609 case RENDERPATH_CGGL:
4610 usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
4613 GL_ColorMask(0,0,0,0);
4614 if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
4615 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
4618 r_maxqueries = (range + r_refdef.scene.numlights) * 4;
4619 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
4621 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
4624 RSurf_ActiveWorldEntity();
4625 GL_BlendFunc(GL_ONE, GL_ZERO);
4626 GL_CullFace(GL_NONE);
4627 GL_DepthMask(false);
4628 GL_DepthRange(0, 1);
4629 GL_PolygonOffset(0, 0);
4631 R_Mesh_ResetTextureState();
4632 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
4635 case RENDERPATH_D3D9:
4637 //Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4639 case RENDERPATH_D3D10:
4640 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4642 case RENDERPATH_D3D11:
4643 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4646 for (lightindex = 0;lightindex < range;lightindex++)
4648 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4651 rtlight = &light->rtlight;
4652 rtlight->corona_visibility = 0;
4653 rtlight->corona_queryindex_visiblepixels = 0;
4654 rtlight->corona_queryindex_allpixels = 0;
4655 if (!(rtlight->flags & flag))
4657 if (rtlight->corona <= 0)
4659 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4661 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4663 for (i = 0;i < r_refdef.scene.numlights;i++)
4665 rtlight = r_refdef.scene.lights[i];
4666 rtlight->corona_visibility = 0;
4667 rtlight->corona_queryindex_visiblepixels = 0;
4668 rtlight->corona_queryindex_allpixels = 0;
4669 if (!(rtlight->flags & flag))
4671 if (rtlight->corona <= 0)
4673 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4676 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4678 // now draw the coronas using the query data for intensity info
4679 for (lightindex = 0;lightindex < range;lightindex++)
4681 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4684 rtlight = &light->rtlight;
4685 if (rtlight->corona_visibility <= 0)
4687 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4689 for (i = 0;i < r_refdef.scene.numlights;i++)
4691 rtlight = r_refdef.scene.lights[i];
4692 if (rtlight->corona_visibility <= 0)
4694 if (gl_flashblend.integer)
4695 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4697 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4703 dlight_t *R_Shadow_NewWorldLight(void)
4705 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4708 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)
4711 // validate parameters
4712 if (style < 0 || style >= MAX_LIGHTSTYLES)
4714 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
4720 // copy to light properties
4721 VectorCopy(origin, light->origin);
4722 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4723 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4724 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4726 light->color[0] = max(color[0], 0);
4727 light->color[1] = max(color[1], 0);
4728 light->color[2] = max(color[2], 0);
4730 light->color[0] = color[0];
4731 light->color[1] = color[1];
4732 light->color[2] = color[2];
4733 light->radius = max(radius, 0);
4734 light->style = style;
4735 light->shadow = shadowenable;
4736 light->corona = corona;
4737 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4738 light->coronasizescale = coronasizescale;
4739 light->ambientscale = ambientscale;
4740 light->diffusescale = diffusescale;
4741 light->specularscale = specularscale;
4742 light->flags = flags;
4744 // update renderable light data
4745 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4746 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);
4749 void R_Shadow_FreeWorldLight(dlight_t *light)
4751 if (r_shadow_selectedlight == light)
4752 r_shadow_selectedlight = NULL;
4753 R_RTLight_Uncompile(&light->rtlight);
4754 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4757 void R_Shadow_ClearWorldLights(void)
4761 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4762 for (lightindex = 0;lightindex < range;lightindex++)
4764 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4766 R_Shadow_FreeWorldLight(light);
4768 r_shadow_selectedlight = NULL;
4771 void R_Shadow_SelectLight(dlight_t *light)
4773 if (r_shadow_selectedlight)
4774 r_shadow_selectedlight->selected = false;
4775 r_shadow_selectedlight = light;
4776 if (r_shadow_selectedlight)
4777 r_shadow_selectedlight->selected = true;
4780 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4782 // this is never batched (there can be only one)
4784 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
4785 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4786 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4789 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4794 skinframe_t *skinframe;
4797 // this is never batched (due to the ent parameter changing every time)
4798 // so numsurfaces == 1 and surfacelist[0] == lightnumber
4799 const dlight_t *light = (dlight_t *)ent;
4802 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
4805 VectorScale(light->color, intensity, spritecolor);
4806 if (VectorLength(spritecolor) < 0.1732f)
4807 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
4808 if (VectorLength(spritecolor) > 1.0f)
4809 VectorNormalize(spritecolor);
4811 // draw light sprite
4812 if (light->cubemapname[0] && !light->shadow)
4813 skinframe = r_editlights_sprcubemapnoshadowlight;
4814 else if (light->cubemapname[0])
4815 skinframe = r_editlights_sprcubemaplight;
4816 else if (!light->shadow)
4817 skinframe = r_editlights_sprnoshadowlight;
4819 skinframe = r_editlights_sprlight;
4821 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);
4822 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4824 // draw selection sprite if light is selected
4825 if (light->selected)
4827 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4828 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4829 // VorteX todo: add normalmode/realtime mode light overlay sprites?
4833 void R_Shadow_DrawLightSprites(void)
4837 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4838 for (lightindex = 0;lightindex < range;lightindex++)
4840 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4842 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
4844 if (!r_editlights_lockcursor)
4845 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
4848 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
4853 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
4854 if (lightindex >= range)
4856 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4859 rtlight = &light->rtlight;
4860 //if (!(rtlight->flags & flag))
4862 VectorCopy(rtlight->shadoworigin, origin);
4863 *radius = rtlight->radius;
4864 VectorCopy(rtlight->color, color);
4868 void R_Shadow_SelectLightInView(void)
4870 float bestrating, rating, temp[3];
4874 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4878 if (r_editlights_lockcursor)
4880 for (lightindex = 0;lightindex < range;lightindex++)
4882 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4885 VectorSubtract(light->origin, r_refdef.view.origin, temp);
4886 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
4889 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
4890 if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1.0f)
4892 bestrating = rating;
4897 R_Shadow_SelectLight(best);
4900 void R_Shadow_LoadWorldLights(void)
4902 int n, a, style, shadow, flags;
4903 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
4904 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
4905 if (cl.worldmodel == NULL)
4907 Con_Print("No map loaded.\n");
4910 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
4911 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4921 for (;COM_Parse(t, true) && strcmp(
4922 if (COM_Parse(t, true))
4924 if (com_token[0] == '!')
4927 origin[0] = atof(com_token+1);
4930 origin[0] = atof(com_token);
4935 while (*s && *s != '\n' && *s != '\r')
4941 // check for modifier flags
4948 #if _MSC_VER >= 1400
4949 #define sscanf sscanf_s
4951 cubemapname[sizeof(cubemapname)-1] = 0;
4952 #if MAX_QPATH != 128
4953 #error update this code if MAX_QPATH changes
4955 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
4956 #if _MSC_VER >= 1400
4957 , sizeof(cubemapname)
4959 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
4962 flags = LIGHTFLAG_REALTIMEMODE;
4970 coronasizescale = 0.25f;
4972 VectorClear(angles);
4975 if (a < 9 || !strcmp(cubemapname, "\"\""))
4977 // remove quotes on cubemapname
4978 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
4981 namelen = strlen(cubemapname) - 2;
4982 memmove(cubemapname, cubemapname + 1, namelen);
4983 cubemapname[namelen] = '\0';
4987 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);
4990 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4998 Con_Printf("invalid rtlights file \"%s\"\n", name);
4999 Mem_Free(lightsstring);
5003 void R_Shadow_SaveWorldLights(void)
5007 size_t bufchars, bufmaxchars;
5009 char name[MAX_QPATH];
5010 char line[MAX_INPUTLINE];
5011 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
5012 // I hate lines which are 3 times my screen size :( --blub
5015 if (cl.worldmodel == NULL)
5017 Con_Print("No map loaded.\n");
5020 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
5021 bufchars = bufmaxchars = 0;
5023 for (lightindex = 0;lightindex < range;lightindex++)
5025 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5028 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
5029 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);
5030 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
5031 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]);
5033 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);
5034 if (bufchars + strlen(line) > bufmaxchars)
5036 bufmaxchars = bufchars + strlen(line) + 2048;
5038 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
5042 memcpy(buf, oldbuf, bufchars);
5048 memcpy(buf + bufchars, line, strlen(line));
5049 bufchars += strlen(line);
5053 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
5058 void R_Shadow_LoadLightsFile(void)
5061 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
5062 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
5063 if (cl.worldmodel == NULL)
5065 Con_Print("No map loaded.\n");
5068 dpsnprintf(name, sizeof(name), "%s.lights", cl.worldnamenoextension);
5069 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5077 while (*s && *s != '\n' && *s != '\r')
5083 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);
5087 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);
5090 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
5091 radius = bound(15, radius, 4096);
5092 VectorScale(color, (2.0f / (8388608.0f)), color);
5093 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5101 Con_Printf("invalid lights file \"%s\"\n", name);
5102 Mem_Free(lightsstring);
5106 // tyrlite/hmap2 light types in the delay field
5107 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
5109 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
5121 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
5122 char key[256], value[MAX_INPUTLINE];
5124 if (cl.worldmodel == NULL)
5126 Con_Print("No map loaded.\n");
5129 // try to load a .ent file first
5130 dpsnprintf(key, sizeof(key), "%s.ent", cl.worldnamenoextension);
5131 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
5132 // and if that is not found, fall back to the bsp file entity string
5134 data = cl.worldmodel->brush.entities;
5137 for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
5139 type = LIGHTTYPE_MINUSX;
5140 origin[0] = origin[1] = origin[2] = 0;
5141 originhack[0] = originhack[1] = originhack[2] = 0;
5142 angles[0] = angles[1] = angles[2] = 0;
5143 color[0] = color[1] = color[2] = 1;
5144 light[0] = light[1] = light[2] = 1;light[3] = 300;
5145 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
5155 if (!COM_ParseToken_Simple(&data, false, false))
5157 if (com_token[0] == '}')
5158 break; // end of entity
5159 if (com_token[0] == '_')
5160 strlcpy(key, com_token + 1, sizeof(key));
5162 strlcpy(key, com_token, sizeof(key));
5163 while (key[strlen(key)-1] == ' ') // remove trailing spaces
5164 key[strlen(key)-1] = 0;
5165 if (!COM_ParseToken_Simple(&data, false, false))
5167 strlcpy(value, com_token, sizeof(value));
5169 // now that we have the key pair worked out...
5170 if (!strcmp("light", key))
5172 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5176 light[0] = vec[0] * (1.0f / 256.0f);
5177 light[1] = vec[0] * (1.0f / 256.0f);
5178 light[2] = vec[0] * (1.0f / 256.0f);
5184 light[0] = vec[0] * (1.0f / 255.0f);
5185 light[1] = vec[1] * (1.0f / 255.0f);
5186 light[2] = vec[2] * (1.0f / 255.0f);
5190 else if (!strcmp("delay", key))
5192 else if (!strcmp("origin", key))
5193 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5194 else if (!strcmp("angle", key))
5195 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5196 else if (!strcmp("angles", key))
5197 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5198 else if (!strcmp("color", key))
5199 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5200 else if (!strcmp("wait", key))
5201 fadescale = atof(value);
5202 else if (!strcmp("classname", key))
5204 if (!strncmp(value, "light", 5))
5207 if (!strcmp(value, "light_fluoro"))
5212 overridecolor[0] = 1;
5213 overridecolor[1] = 1;
5214 overridecolor[2] = 1;
5216 if (!strcmp(value, "light_fluorospark"))
5221 overridecolor[0] = 1;
5222 overridecolor[1] = 1;
5223 overridecolor[2] = 1;
5225 if (!strcmp(value, "light_globe"))
5230 overridecolor[0] = 1;
5231 overridecolor[1] = 0.8;
5232 overridecolor[2] = 0.4;
5234 if (!strcmp(value, "light_flame_large_yellow"))
5239 overridecolor[0] = 1;
5240 overridecolor[1] = 0.5;
5241 overridecolor[2] = 0.1;
5243 if (!strcmp(value, "light_flame_small_yellow"))
5248 overridecolor[0] = 1;
5249 overridecolor[1] = 0.5;
5250 overridecolor[2] = 0.1;
5252 if (!strcmp(value, "light_torch_small_white"))
5257 overridecolor[0] = 1;
5258 overridecolor[1] = 0.5;
5259 overridecolor[2] = 0.1;
5261 if (!strcmp(value, "light_torch_small_walltorch"))
5266 overridecolor[0] = 1;
5267 overridecolor[1] = 0.5;
5268 overridecolor[2] = 0.1;
5272 else if (!strcmp("style", key))
5273 style = atoi(value);
5274 else if (!strcmp("skin", key))
5275 skin = (int)atof(value);
5276 else if (!strcmp("pflags", key))
5277 pflags = (int)atof(value);
5278 //else if (!strcmp("effects", key))
5279 // effects = (int)atof(value);
5280 else if (cl.worldmodel->type == mod_brushq3)
5282 if (!strcmp("scale", key))
5283 lightscale = atof(value);
5284 if (!strcmp("fade", key))
5285 fadescale = atof(value);
5290 if (lightscale <= 0)
5294 if (color[0] == color[1] && color[0] == color[2])
5296 color[0] *= overridecolor[0];
5297 color[1] *= overridecolor[1];
5298 color[2] *= overridecolor[2];
5300 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5301 color[0] = color[0] * light[0];
5302 color[1] = color[1] * light[1];
5303 color[2] = color[2] * light[2];
5306 case LIGHTTYPE_MINUSX:
5308 case LIGHTTYPE_RECIPX:
5310 VectorScale(color, (1.0f / 16.0f), color);
5312 case LIGHTTYPE_RECIPXX:
5314 VectorScale(color, (1.0f / 16.0f), color);
5317 case LIGHTTYPE_NONE:
5321 case LIGHTTYPE_MINUSXX:
5324 VectorAdd(origin, originhack, origin);
5326 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);
5329 Mem_Free(entfiledata);
5333 void R_Shadow_SetCursorLocationForView(void)
5336 vec3_t dest, endpos;
5338 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5339 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
5340 if (trace.fraction < 1)
5342 dist = trace.fraction * r_editlights_cursordistance.value;
5343 push = r_editlights_cursorpushback.value;
5347 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5348 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5352 VectorClear( endpos );
5354 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5355 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5356 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5359 void R_Shadow_UpdateWorldLightSelection(void)
5361 if (r_editlights.integer)
5363 R_Shadow_SetCursorLocationForView();
5364 R_Shadow_SelectLightInView();
5367 R_Shadow_SelectLight(NULL);
5370 void R_Shadow_EditLights_Clear_f(void)
5372 R_Shadow_ClearWorldLights();
5375 void R_Shadow_EditLights_Reload_f(void)
5379 strlcpy(r_shadow_mapname, cl.worldname, sizeof(r_shadow_mapname));
5380 R_Shadow_ClearWorldLights();
5381 R_Shadow_LoadWorldLights();
5382 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5384 R_Shadow_LoadLightsFile();
5385 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5386 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5390 void R_Shadow_EditLights_Save_f(void)
5394 R_Shadow_SaveWorldLights();
5397 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
5399 R_Shadow_ClearWorldLights();
5400 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5403 void R_Shadow_EditLights_ImportLightsFile_f(void)
5405 R_Shadow_ClearWorldLights();
5406 R_Shadow_LoadLightsFile();
5409 void R_Shadow_EditLights_Spawn_f(void)
5412 if (!r_editlights.integer)
5414 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5417 if (Cmd_Argc() != 1)
5419 Con_Print("r_editlights_spawn does not take parameters\n");
5422 color[0] = color[1] = color[2] = 1;
5423 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5426 void R_Shadow_EditLights_Edit_f(void)
5428 vec3_t origin, angles, color;
5429 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5430 int style, shadows, flags, normalmode, realtimemode;
5431 char cubemapname[MAX_INPUTLINE];
5432 if (!r_editlights.integer)
5434 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5437 if (!r_shadow_selectedlight)
5439 Con_Print("No selected light.\n");
5442 VectorCopy(r_shadow_selectedlight->origin, origin);
5443 VectorCopy(r_shadow_selectedlight->angles, angles);
5444 VectorCopy(r_shadow_selectedlight->color, color);
5445 radius = r_shadow_selectedlight->radius;
5446 style = r_shadow_selectedlight->style;
5447 if (r_shadow_selectedlight->cubemapname)
5448 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5451 shadows = r_shadow_selectedlight->shadow;
5452 corona = r_shadow_selectedlight->corona;
5453 coronasizescale = r_shadow_selectedlight->coronasizescale;
5454 ambientscale = r_shadow_selectedlight->ambientscale;
5455 diffusescale = r_shadow_selectedlight->diffusescale;
5456 specularscale = r_shadow_selectedlight->specularscale;
5457 flags = r_shadow_selectedlight->flags;
5458 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5459 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5460 if (!strcmp(Cmd_Argv(1), "origin"))
5462 if (Cmd_Argc() != 5)
5464 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5467 origin[0] = atof(Cmd_Argv(2));
5468 origin[1] = atof(Cmd_Argv(3));
5469 origin[2] = atof(Cmd_Argv(4));
5471 else if (!strcmp(Cmd_Argv(1), "originx"))
5473 if (Cmd_Argc() != 3)
5475 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5478 origin[0] = atof(Cmd_Argv(2));
5480 else if (!strcmp(Cmd_Argv(1), "originy"))
5482 if (Cmd_Argc() != 3)
5484 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5487 origin[1] = atof(Cmd_Argv(2));
5489 else if (!strcmp(Cmd_Argv(1), "originz"))
5491 if (Cmd_Argc() != 3)
5493 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5496 origin[2] = atof(Cmd_Argv(2));
5498 else if (!strcmp(Cmd_Argv(1), "move"))
5500 if (Cmd_Argc() != 5)
5502 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5505 origin[0] += atof(Cmd_Argv(2));
5506 origin[1] += atof(Cmd_Argv(3));
5507 origin[2] += atof(Cmd_Argv(4));
5509 else if (!strcmp(Cmd_Argv(1), "movex"))
5511 if (Cmd_Argc() != 3)
5513 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5516 origin[0] += atof(Cmd_Argv(2));
5518 else if (!strcmp(Cmd_Argv(1), "movey"))
5520 if (Cmd_Argc() != 3)
5522 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5525 origin[1] += atof(Cmd_Argv(2));
5527 else if (!strcmp(Cmd_Argv(1), "movez"))
5529 if (Cmd_Argc() != 3)
5531 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5534 origin[2] += atof(Cmd_Argv(2));
5536 else if (!strcmp(Cmd_Argv(1), "angles"))
5538 if (Cmd_Argc() != 5)
5540 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5543 angles[0] = atof(Cmd_Argv(2));
5544 angles[1] = atof(Cmd_Argv(3));
5545 angles[2] = atof(Cmd_Argv(4));
5547 else if (!strcmp(Cmd_Argv(1), "anglesx"))
5549 if (Cmd_Argc() != 3)
5551 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5554 angles[0] = atof(Cmd_Argv(2));
5556 else if (!strcmp(Cmd_Argv(1), "anglesy"))
5558 if (Cmd_Argc() != 3)
5560 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5563 angles[1] = atof(Cmd_Argv(2));
5565 else if (!strcmp(Cmd_Argv(1), "anglesz"))
5567 if (Cmd_Argc() != 3)
5569 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5572 angles[2] = atof(Cmd_Argv(2));
5574 else if (!strcmp(Cmd_Argv(1), "color"))
5576 if (Cmd_Argc() != 5)
5578 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
5581 color[0] = atof(Cmd_Argv(2));
5582 color[1] = atof(Cmd_Argv(3));
5583 color[2] = atof(Cmd_Argv(4));
5585 else if (!strcmp(Cmd_Argv(1), "radius"))
5587 if (Cmd_Argc() != 3)
5589 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5592 radius = atof(Cmd_Argv(2));
5594 else if (!strcmp(Cmd_Argv(1), "colorscale"))
5596 if (Cmd_Argc() == 3)
5598 double scale = atof(Cmd_Argv(2));
5605 if (Cmd_Argc() != 5)
5607 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
5610 color[0] *= atof(Cmd_Argv(2));
5611 color[1] *= atof(Cmd_Argv(3));
5612 color[2] *= atof(Cmd_Argv(4));
5615 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
5617 if (Cmd_Argc() != 3)
5619 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5622 radius *= atof(Cmd_Argv(2));
5624 else if (!strcmp(Cmd_Argv(1), "style"))
5626 if (Cmd_Argc() != 3)
5628 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5631 style = atoi(Cmd_Argv(2));
5633 else if (!strcmp(Cmd_Argv(1), "cubemap"))
5637 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5640 if (Cmd_Argc() == 3)
5641 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
5645 else if (!strcmp(Cmd_Argv(1), "shadows"))
5647 if (Cmd_Argc() != 3)
5649 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5652 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5654 else if (!strcmp(Cmd_Argv(1), "corona"))
5656 if (Cmd_Argc() != 3)
5658 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5661 corona = atof(Cmd_Argv(2));
5663 else if (!strcmp(Cmd_Argv(1), "coronasize"))
5665 if (Cmd_Argc() != 3)
5667 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5670 coronasizescale = atof(Cmd_Argv(2));
5672 else if (!strcmp(Cmd_Argv(1), "ambient"))
5674 if (Cmd_Argc() != 3)
5676 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5679 ambientscale = atof(Cmd_Argv(2));
5681 else if (!strcmp(Cmd_Argv(1), "diffuse"))
5683 if (Cmd_Argc() != 3)
5685 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5688 diffusescale = atof(Cmd_Argv(2));
5690 else if (!strcmp(Cmd_Argv(1), "specular"))
5692 if (Cmd_Argc() != 3)
5694 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5697 specularscale = atof(Cmd_Argv(2));
5699 else if (!strcmp(Cmd_Argv(1), "normalmode"))
5701 if (Cmd_Argc() != 3)
5703 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5706 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5708 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
5710 if (Cmd_Argc() != 3)
5712 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5715 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5719 Con_Print("usage: r_editlights_edit [property] [value]\n");
5720 Con_Print("Selected light's properties:\n");
5721 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5722 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5723 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5724 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
5725 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
5726 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
5727 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5728 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
5729 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
5730 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
5731 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
5732 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
5733 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5734 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5737 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5738 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5741 void R_Shadow_EditLights_EditAll_f(void)
5744 dlight_t *light, *oldselected;
5747 if (!r_editlights.integer)
5749 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5753 oldselected = r_shadow_selectedlight;
5754 // EditLights doesn't seem to have a "remove" command or something so:
5755 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5756 for (lightindex = 0;lightindex < range;lightindex++)
5758 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5761 R_Shadow_SelectLight(light);
5762 R_Shadow_EditLights_Edit_f();
5764 // return to old selected (to not mess editing once selection is locked)
5765 R_Shadow_SelectLight(oldselected);
5768 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
5770 int lightnumber, lightcount;
5771 size_t lightindex, range;
5775 if (!r_editlights.integer)
5777 x = vid_conwidth.value - 240;
5779 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
5782 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5783 for (lightindex = 0;lightindex < range;lightindex++)
5785 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5788 if (light == r_shadow_selectedlight)
5789 lightnumber = lightindex;
5792 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;
5793 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;
5795 if (r_shadow_selectedlight == NULL)
5797 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;
5798 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;
5799 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;
5800 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;
5801 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;
5802 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;
5803 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;
5804 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;
5805 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;
5806 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;
5807 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;
5808 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;
5809 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;
5810 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;
5811 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;
5814 void R_Shadow_EditLights_ToggleShadow_f(void)
5816 if (!r_editlights.integer)
5818 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5821 if (!r_shadow_selectedlight)
5823 Con_Print("No selected light.\n");
5826 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);
5829 void R_Shadow_EditLights_ToggleCorona_f(void)
5831 if (!r_editlights.integer)
5833 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5836 if (!r_shadow_selectedlight)
5838 Con_Print("No selected light.\n");
5841 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);
5844 void R_Shadow_EditLights_Remove_f(void)
5846 if (!r_editlights.integer)
5848 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
5851 if (!r_shadow_selectedlight)
5853 Con_Print("No selected light.\n");
5856 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
5857 r_shadow_selectedlight = NULL;
5860 void R_Shadow_EditLights_Help_f(void)
5863 "Documentation on r_editlights system:\n"
5865 "r_editlights : enable/disable editing mode\n"
5866 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
5867 "r_editlights_cursorpushback : push back cursor this far from surface\n"
5868 "r_editlights_cursorpushoff : push cursor off surface this far\n"
5869 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
5870 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
5872 "r_editlights_help : this help\n"
5873 "r_editlights_clear : remove all lights\n"
5874 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
5875 "r_editlights_lock : lock selection to current light, if already locked - unlock\n"
5876 "r_editlights_save : save to .rtlights file\n"
5877 "r_editlights_spawn : create a light with default settings\n"
5878 "r_editlights_edit command : edit selected light - more documentation below\n"
5879 "r_editlights_remove : remove selected light\n"
5880 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
5881 "r_editlights_importlightentitiesfrommap : reload light entities\n"
5882 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
5884 "origin x y z : set light location\n"
5885 "originx x: set x component of light location\n"
5886 "originy y: set y component of light location\n"
5887 "originz z: set z component of light location\n"
5888 "move x y z : adjust light location\n"
5889 "movex x: adjust x component of light location\n"
5890 "movey y: adjust y component of light location\n"
5891 "movez z: adjust z component of light location\n"
5892 "angles x y z : set light angles\n"
5893 "anglesx x: set x component of light angles\n"
5894 "anglesy y: set y component of light angles\n"
5895 "anglesz z: set z component of light angles\n"
5896 "color r g b : set color of light (can be brighter than 1 1 1)\n"
5897 "radius radius : set radius (size) of light\n"
5898 "colorscale grey : multiply color of light (1 does nothing)\n"
5899 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
5900 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
5901 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
5902 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
5903 "cubemap basename : set filter cubemap of light (not yet supported)\n"
5904 "shadows 1/0 : turn on/off shadows\n"
5905 "corona n : set corona intensity\n"
5906 "coronasize n : set corona size (0-1)\n"
5907 "ambient n : set ambient intensity (0-1)\n"
5908 "diffuse n : set diffuse intensity (0-1)\n"
5909 "specular n : set specular intensity (0-1)\n"
5910 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
5911 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
5912 "<nothing> : print light properties to console\n"
5916 void R_Shadow_EditLights_CopyInfo_f(void)
5918 if (!r_editlights.integer)
5920 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
5923 if (!r_shadow_selectedlight)
5925 Con_Print("No selected light.\n");
5928 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
5929 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
5930 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
5931 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
5932 if (r_shadow_selectedlight->cubemapname)
5933 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
5935 r_shadow_bufferlight.cubemapname[0] = 0;
5936 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
5937 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
5938 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
5939 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
5940 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
5941 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
5942 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
5945 void R_Shadow_EditLights_PasteInfo_f(void)
5947 if (!r_editlights.integer)
5949 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
5952 if (!r_shadow_selectedlight)
5954 Con_Print("No selected light.\n");
5957 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);
5960 void R_Shadow_EditLights_Lock_f(void)
5962 if (!r_editlights.integer)
5964 Con_Print("Cannot lock on light when not in editing mode. Set r_editlights to 1.\n");
5967 if (r_editlights_lockcursor)
5969 r_editlights_lockcursor = false;
5972 if (!r_shadow_selectedlight)
5974 Con_Print("No selected light to lock on.\n");
5977 r_editlights_lockcursor = true;
5980 void R_Shadow_EditLights_Init(void)
5982 Cvar_RegisterVariable(&r_editlights);
5983 Cvar_RegisterVariable(&r_editlights_cursordistance);
5984 Cvar_RegisterVariable(&r_editlights_cursorpushback);
5985 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
5986 Cvar_RegisterVariable(&r_editlights_cursorgrid);
5987 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
5988 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
5989 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
5990 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)");
5991 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
5992 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
5993 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
5994 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)");
5995 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
5996 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
5997 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
5998 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
5999 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
6000 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
6001 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)");
6002 Cmd_AddCommand("r_editlights_lock", R_Shadow_EditLights_Lock_f, "lock selection to current light, if already locked - unlock");
6008 =============================================================================
6012 =============================================================================
6015 void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, const int flags)
6017 int i, numlights, flag;
6018 float f, relativepoint[3], dist, dist2, lightradius2;
6022 VectorClear(diffusecolor);
6023 VectorClear(diffusenormal);
6025 if (flags & LP_LIGHTMAP)
6027 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
6029 ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_refdef.scene.ambient;
6030 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
6033 VectorSet(ambientcolor, 1, 1, 1);
6035 if (flags & LP_RTWORLD)
6037 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
6038 numlights = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
6039 for (i = 0; i < numlights; i++)
6041 dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
6044 light = &dlight->rtlight;
6045 if (!(light->flags & flag))
6048 lightradius2 = light->radius * light->radius;
6049 VectorSubtract(light->shadoworigin, p, relativepoint);
6050 dist2 = VectorLength2(relativepoint);
6051 if (dist2 >= lightradius2)
6053 dist = sqrt(dist2) / light->radius;
6054 f = dist < 1 ? (r_shadow_lightintensityscale.value * ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist))) : 0;
6057 // todo: add to both ambient and diffuse
6058 if (!light->shadow || CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
6059 VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);
6062 if (flags & LP_DYNLIGHT)
6065 for (i = 0;i < r_refdef.scene.numlights;i++)
6067 light = r_refdef.scene.lights[i];
6069 lightradius2 = light->radius * light->radius;
6070 VectorSubtract(light->shadoworigin, p, relativepoint);
6071 dist2 = VectorLength2(relativepoint);
6072 if (dist2 >= lightradius2)
6074 dist = sqrt(dist2) / light->radius;
6075 f = dist < 1 ? (r_shadow_lightintensityscale.value * ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist))) : 0;
6078 // todo: add to both ambient and diffuse
6079 if (!light->shadow || CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
6080 VectorMA(ambientcolor, f, light->color, ambientcolor);