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_Vertex3f(outverts, shadowvertex3f, NULL);
1282 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1286 // decide which type of shadow to generate and set stencil mode
1287 R_Shadow_RenderMode_StencilShadowVolumes(R_Shadow_UseZPass(trismins, trismaxs));
1288 // generate the sides or a solid volume, depending on type
1289 if (r_shadow_rendermode >= R_SHADOW_RENDERMODE_ZPASS_STENCIL && r_shadow_rendermode <= R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE)
1290 tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1292 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1293 r_refdef.stats.lights_dynamicshadowtriangles += tris;
1294 r_refdef.stats.lights_shadowtriangles += tris;
1295 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
1297 // increment stencil if frontface is infront of depthbuffer
1298 GL_CullFace(r_refdef.view.cullface_front);
1299 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
1300 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1301 // decrement stencil if backface is infront of depthbuffer
1302 GL_CullFace(r_refdef.view.cullface_back);
1303 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
1305 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
1307 // decrement stencil if backface is behind depthbuffer
1308 GL_CullFace(r_refdef.view.cullface_front);
1309 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
1310 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1311 // increment stencil if frontface is behind depthbuffer
1312 GL_CullFace(r_refdef.view.cullface_back);
1313 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
1315 R_Mesh_PrepareVertices_Vertex3f(outverts, shadowvertex3f, NULL);
1316 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1320 int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias)
1322 // p1, p2, p3 are in the cubemap's local coordinate system
1323 // bias = border/(size - border)
1326 float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1327 dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2),
1328 dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3);
1329 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1331 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1332 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1333 | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1334 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1336 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1337 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1338 | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1340 dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1341 dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2),
1342 dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3);
1343 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1345 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1346 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1347 | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1348 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1350 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1351 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1352 | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1354 dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1355 dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2),
1356 dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3);
1357 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1359 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1360 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1361 | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1362 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1364 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1365 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1366 | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1371 int R_Shadow_CalcBBoxSideMask(const vec3_t mins, const vec3_t maxs, const matrix4x4_t *worldtolight, const matrix4x4_t *radiustolight, float bias)
1373 vec3_t center, radius, lightcenter, lightradius, pmin, pmax;
1374 float dp1, dn1, ap1, an1, dp2, dn2, ap2, an2;
1377 VectorSubtract(maxs, mins, radius);
1378 VectorScale(radius, 0.5f, radius);
1379 VectorAdd(mins, radius, center);
1380 Matrix4x4_Transform(worldtolight, center, lightcenter);
1381 Matrix4x4_Transform3x3(radiustolight, radius, lightradius);
1382 VectorSubtract(lightcenter, lightradius, pmin);
1383 VectorAdd(lightcenter, lightradius, pmax);
1385 dp1 = pmax[0] + pmax[1], dn1 = pmax[0] - pmin[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1386 dp2 = pmin[0] + pmin[1], dn2 = pmin[0] - pmax[1], ap2 = fabs(dp2), an2 = fabs(dn2);
1387 if(ap1 > bias*an1 && ap2 > bias*an2)
1389 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1390 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1391 if(an1 > bias*ap1 && an2 > bias*ap2)
1393 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1394 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1396 dp1 = pmax[1] + pmax[2], dn1 = pmax[1] - pmin[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1397 dp2 = pmin[1] + pmin[2], dn2 = pmin[1] - pmax[2], ap2 = fabs(dp2), an2 = fabs(dn2);
1398 if(ap1 > bias*an1 && ap2 > bias*an2)
1400 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1401 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1402 if(an1 > bias*ap1 && an2 > bias*ap2)
1404 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1405 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1407 dp1 = pmax[2] + pmax[0], dn1 = pmax[2] - pmin[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1408 dp2 = pmin[2] + pmin[0], dn2 = pmin[2] - pmax[0], ap2 = fabs(dp2), an2 = fabs(dn2);
1409 if(ap1 > bias*an1 && ap2 > bias*an2)
1411 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1412 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1413 if(an1 > bias*ap1 && an2 > bias*ap2)
1415 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1416 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1421 #define R_Shadow_CalcEntitySideMask(ent, worldtolight, radiustolight, bias) R_Shadow_CalcBBoxSideMask((ent)->mins, (ent)->maxs, worldtolight, radiustolight, bias)
1423 int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
1425 // p is in the cubemap's local coordinate system
1426 // bias = border/(size - border)
1427 float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn);
1428 float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn);
1429 float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn);
1431 if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
1432 if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
1433 if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
1434 if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
1435 if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
1436 if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
1440 int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
1444 int sides = 0x3F, masks[6] = { 3<<4, 3<<4, 3<<0, 3<<0, 3<<2, 3<<2 };
1445 float scale = (size - 2*border)/size, len;
1446 float bias = border / (float)(size - border), dp, dn, ap, an;
1447 // check if cone enclosing side would cross frustum plane
1448 scale = 2 / (scale*scale + 2);
1449 for (i = 0;i < 5;i++)
1451 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) > -0.03125)
1453 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[i].normal, n);
1454 len = scale*VectorLength2(n);
1455 if(n[0]*n[0] > len) sides &= n[0] < 0 ? ~(1<<0) : ~(2 << 0);
1456 if(n[1]*n[1] > len) sides &= n[1] < 0 ? ~(1<<2) : ~(2 << 2);
1457 if(n[2]*n[2] > len) sides &= n[2] < 0 ? ~(1<<4) : ~(2 << 4);
1459 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[4]) >= r_refdef.farclip - r_refdef.nearclip + 0.03125)
1461 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[4].normal, n);
1462 len = scale*VectorLength(n);
1463 if(n[0]*n[0] > len) sides &= n[0] >= 0 ? ~(1<<0) : ~(2 << 0);
1464 if(n[1]*n[1] > len) sides &= n[1] >= 0 ? ~(1<<2) : ~(2 << 2);
1465 if(n[2]*n[2] > len) sides &= n[2] >= 0 ? ~(1<<4) : ~(2 << 4);
1467 // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results
1468 // check if frustum corners/origin cross plane sides
1470 // infinite version, assumes frustum corners merely give direction and extend to infinite distance
1471 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.origin, p);
1472 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1473 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1474 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1475 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1476 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1477 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1478 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1479 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1480 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1481 for (i = 0;i < 4;i++)
1483 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.frustumcorner[i], n);
1484 VectorSubtract(n, p, n);
1485 dp = n[0] + n[1], dn = n[0] - n[1], ap = fabs(dp), an = fabs(dn);
1486 if(ap > 0) masks[0] |= dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2);
1487 if(an > 0) masks[1] |= dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2);
1488 dp = n[1] + n[2], dn = n[1] - n[2], ap = fabs(dp), an = fabs(dn);
1489 if(ap > 0) masks[2] |= dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4);
1490 if(an > 0) masks[3] |= dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4);
1491 dp = n[2] + n[0], dn = n[2] - n[0], ap = fabs(dp), an = fabs(dn);
1492 if(ap > 0) masks[4] |= dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0);
1493 if(an > 0) masks[5] |= dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0);
1496 // finite version, assumes corners are a finite distance from origin dependent on far plane
1497 for (i = 0;i < 5;i++)
1499 Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p);
1500 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1501 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1502 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1503 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1504 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1505 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1506 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1507 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1508 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1511 return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5];
1514 int R_Shadow_ChooseSidesFromBox(int firsttriangle, int numtris, const float *invertex3f, const int *elements, const matrix4x4_t *worldtolight, const vec3_t projectorigin, const vec3_t projectdirection, const vec3_t lightmins, const vec3_t lightmaxs, const vec3_t surfacemins, const vec3_t surfacemaxs, int *totals)
1522 int mask, surfacemask = 0;
1523 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1525 bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
1526 tend = firsttriangle + numtris;
1527 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1529 // surface box entirely inside light box, no box cull
1530 if (projectdirection)
1532 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1534 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1535 TriangleNormal(v[0], v[1], v[2], normal);
1536 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1538 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1539 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1540 surfacemask |= mask;
1543 totals[0] += mask&1, totals[1] += (mask>>1)&1, totals[2] += (mask>>2)&1, totals[3] += (mask>>3)&1, totals[4] += (mask>>4)&1, totals[5] += mask>>5;
1544 shadowsides[numshadowsides] = mask;
1545 shadowsideslist[numshadowsides++] = t;
1552 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1554 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1555 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]))
1557 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1558 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1559 surfacemask |= mask;
1562 totals[0] += mask&1, totals[1] += (mask>>1)&1, totals[2] += (mask>>2)&1, totals[3] += (mask>>3)&1, totals[4] += (mask>>4)&1, totals[5] += mask>>5;
1563 shadowsides[numshadowsides] = mask;
1564 shadowsideslist[numshadowsides++] = t;
1572 // surface box not entirely inside light box, cull each triangle
1573 if (projectdirection)
1575 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1577 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1578 TriangleNormal(v[0], v[1], v[2], normal);
1579 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1580 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1582 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1583 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1584 surfacemask |= mask;
1587 totals[0] += mask&1, totals[1] += (mask>>1)&1, totals[2] += (mask>>2)&1, totals[3] += (mask>>3)&1, totals[4] += (mask>>4)&1, totals[5] += mask>>5;
1588 shadowsides[numshadowsides] = mask;
1589 shadowsideslist[numshadowsides++] = t;
1596 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1598 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1599 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1600 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1602 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1603 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1604 surfacemask |= mask;
1607 totals[0] += mask&1, totals[1] += (mask>>1)&1, totals[2] += (mask>>2)&1, totals[3] += (mask>>3)&1, totals[4] += (mask>>4)&1, totals[5] += mask>>5;
1608 shadowsides[numshadowsides] = mask;
1609 shadowsideslist[numshadowsides++] = t;
1618 void R_Shadow_ShadowMapFromList(int numverts, int numtris, const float *vertex3f, const int *elements, int numsidetris, const int *sidetotals, const unsigned char *sides, const int *sidetris)
1620 int i, j, outtriangles = 0;
1621 int *outelement3i[6];
1622 if (!numverts || !numsidetris || !r_shadow_compilingrtlight)
1624 outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5];
1625 // make sure shadowelements is big enough for this mesh
1626 if (maxshadowtriangles < outtriangles)
1627 R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1);
1629 // compute the offset and size of the separate index lists for each cubemap side
1631 for (i = 0;i < 6;i++)
1633 outelement3i[i] = shadowelements + outtriangles * 3;
1634 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles;
1635 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i];
1636 outtriangles += sidetotals[i];
1639 // gather up the (sparse) triangles into separate index lists for each cubemap side
1640 for (i = 0;i < numsidetris;i++)
1642 const int *element = elements + sidetris[i] * 3;
1643 for (j = 0;j < 6;j++)
1645 if (sides[i] & (1 << j))
1647 outelement3i[j][0] = element[0];
1648 outelement3i[j][1] = element[1];
1649 outelement3i[j][2] = element[2];
1650 outelement3i[j] += 3;
1655 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, outtriangles, shadowelements);
1658 static void R_Shadow_MakeTextures_MakeCorona(void)
1662 unsigned char pixels[32][32][4];
1663 for (y = 0;y < 32;y++)
1665 dy = (y - 15.5f) * (1.0f / 16.0f);
1666 for (x = 0;x < 32;x++)
1668 dx = (x - 15.5f) * (1.0f / 16.0f);
1669 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1670 a = bound(0, a, 255);
1671 pixels[y][x][0] = a;
1672 pixels[y][x][1] = a;
1673 pixels[y][x][2] = a;
1674 pixels[y][x][3] = 255;
1677 r_shadow_lightcorona = R_SkinFrame_LoadInternalBGRA("lightcorona", TEXF_FORCELINEAR, &pixels[0][0][0], 32, 32);
1680 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1682 float dist = sqrt(x*x+y*y+z*z);
1683 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1684 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1685 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1688 static void R_Shadow_MakeTextures(void)
1691 float intensity, dist;
1693 R_Shadow_FreeShadowMaps();
1694 R_FreeTexturePool(&r_shadow_texturepool);
1695 r_shadow_texturepool = R_AllocTexturePool();
1696 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1697 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1698 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1699 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1700 for (x = 0;x <= ATTENTABLESIZE;x++)
1702 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1703 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1704 r_shadow_attentable[x] = bound(0, intensity, 1);
1706 // 1D gradient texture
1707 for (x = 0;x < ATTEN1DSIZE;x++)
1708 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1709 r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1710 // 2D circle texture
1711 for (y = 0;y < ATTEN2DSIZE;y++)
1712 for (x = 0;x < ATTEN2DSIZE;x++)
1713 data[y*ATTEN2DSIZE+x] = R_Shadow_MakeTextures_SamplePoint(((x + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375), ((y + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375), 0);
1714 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1715 // 3D sphere texture
1716 if (r_shadow_texture3d.integer && vid.support.ext_texture_3d)
1718 for (z = 0;z < ATTEN3DSIZE;z++)
1719 for (y = 0;y < ATTEN3DSIZE;y++)
1720 for (x = 0;x < ATTEN3DSIZE;x++)
1721 data[(z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x] = R_Shadow_MakeTextures_SamplePoint(((x + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375), ((y + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375), ((z + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375));
1722 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1725 r_shadow_attenuation3dtexture = NULL;
1728 R_Shadow_MakeTextures_MakeCorona();
1730 // Editor light sprites
1731 r_editlights_sprcursor = R_SkinFrame_LoadInternal8bit("gfx/editlights/cursor", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1748 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1749 r_editlights_sprlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/light", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1766 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1767 r_editlights_sprnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/noshadow", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1784 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1785 r_editlights_sprcubemaplight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemaplight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1802 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1803 r_editlights_sprcubemapnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemapnoshadowlight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1820 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1821 r_editlights_sprselection = R_SkinFrame_LoadInternal8bit("gfx/editlights/selection", TEXF_ALPHA | TEXF_CLAMP, (unsigned char *)
1838 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1841 void R_Shadow_ValidateCvars(void)
1843 if (r_shadow_texture3d.integer && !vid.support.ext_texture_3d)
1844 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1845 if (gl_ext_separatestencil.integer && !vid.support.ati_separate_stencil)
1846 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
1847 if (gl_ext_stenciltwoside.integer && !vid.support.ext_stencil_two_side)
1848 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1851 void R_Shadow_RenderMode_Begin(void)
1857 R_Shadow_ValidateCvars();
1859 if (!r_shadow_attenuation2dtexture
1860 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1861 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1862 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1863 R_Shadow_MakeTextures();
1866 R_Mesh_ResetTextureState();
1867 GL_BlendFunc(GL_ONE, GL_ZERO);
1868 GL_DepthRange(0, 1);
1869 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1871 GL_DepthMask(false);
1872 GL_Color(0, 0, 0, 1);
1873 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1875 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1877 if (gl_ext_separatestencil.integer && vid.support.ati_separate_stencil)
1879 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
1880 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
1882 else if (gl_ext_stenciltwoside.integer && vid.support.ext_stencil_two_side)
1884 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
1885 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
1889 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
1890 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
1893 switch(vid.renderpath)
1895 case RENDERPATH_GL20:
1896 case RENDERPATH_CGGL:
1897 case RENDERPATH_D3D9:
1898 case RENDERPATH_D3D10:
1899 case RENDERPATH_D3D11:
1900 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1902 case RENDERPATH_GL13:
1903 case RENDERPATH_GL11:
1904 if (r_textureunits.integer >= 2 && vid.texunits >= 2 && r_shadow_texture3d.integer && r_shadow_attenuation3dtexture)
1905 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN;
1906 else if (r_textureunits.integer >= 3 && vid.texunits >= 3)
1907 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN;
1908 else if (r_textureunits.integer >= 2 && vid.texunits >= 2)
1909 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN;
1911 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1917 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
1918 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
1919 r_shadow_drawbuffer = drawbuffer;
1920 r_shadow_readbuffer = readbuffer;
1922 r_shadow_cullface_front = r_refdef.view.cullface_front;
1923 r_shadow_cullface_back = r_refdef.view.cullface_back;
1926 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
1928 rsurface.rtlight = rtlight;
1931 void R_Shadow_RenderMode_Reset(void)
1933 R_Mesh_ResetRenderTargets();
1934 R_SetViewport(&r_refdef.view.viewport);
1935 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
1936 R_Mesh_ResetTextureState();
1937 GL_DepthRange(0, 1);
1939 GL_DepthMask(false);
1940 GL_DepthFunc(GL_LEQUAL);
1941 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1942 r_refdef.view.cullface_front = r_shadow_cullface_front;
1943 r_refdef.view.cullface_back = r_shadow_cullface_back;
1944 GL_CullFace(r_refdef.view.cullface_back);
1945 GL_Color(1, 1, 1, 1);
1946 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
1947 GL_BlendFunc(GL_ONE, GL_ZERO);
1948 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
1949 r_shadow_usingshadowmap2d = false;
1950 r_shadow_usingshadowmaportho = false;
1951 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
1954 void R_Shadow_ClearStencil(void)
1956 GL_Clear(GL_STENCIL_BUFFER_BIT, NULL, 1.0f, 128);
1957 r_refdef.stats.lights_clears++;
1960 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
1962 r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
1963 if (r_shadow_rendermode == mode)
1965 R_Shadow_RenderMode_Reset();
1966 GL_DepthFunc(GL_LESS);
1967 GL_ColorMask(0, 0, 0, 0);
1968 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1969 GL_CullFace(GL_NONE);
1970 R_SetupShader_DepthOrShadow();
1971 r_shadow_rendermode = mode;
1976 case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
1977 case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
1978 R_SetStencilSeparate(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, GL_ALWAYS, 128, 255);
1980 case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
1981 case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
1982 R_SetStencilSeparate(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, GL_ALWAYS, 128, 255);
1987 static void R_Shadow_MakeVSDCT(void)
1989 // maps to a 2x3 texture rectangle with normalized coordinates
1994 // stores abs(dir.xy), offset.xy/2.5
1995 unsigned char data[4*6] =
1997 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
1998 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
1999 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
2000 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
2001 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
2002 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
2004 r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
2007 static void R_Shadow_MakeShadowMap(int side, int size)
2009 switch (r_shadow_shadowmode)
2011 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2012 if (r_shadow_shadowmap2dtexture) return;
2013 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);
2014 r_shadow_shadowmap2dcolortexture = NULL;
2015 switch(vid.renderpath)
2018 case RENDERPATH_D3D9:
2019 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);
2020 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
2024 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2dtexture, NULL, NULL, NULL, NULL);
2032 // render depth into the fbo, do not render color at all
2033 // validate the fbo now
2037 qglDrawBuffer(GL_NONE);CHECKGLERROR
2038 qglReadBuffer(GL_NONE);CHECKGLERROR
2039 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2040 if (status != GL_FRAMEBUFFER_COMPLETE_EXT && (r_shadow_shadowmapping.integer || r_shadow_deferred.integer))
2042 Con_Printf("R_Shadow_MakeShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2043 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2044 Cvar_SetValueQuick(&r_shadow_deferred, 0);
2049 void R_Shadow_RenderMode_ShadowMap(int side, int clear, int size)
2051 float nearclip, farclip, bias;
2052 r_viewport_t viewport;
2055 float clearcolor[4];
2056 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
2058 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
2059 r_shadow_shadowmap_parameters[1] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
2060 r_shadow_shadowmap_parameters[3] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
2061 r_shadow_shadowmapside = side;
2062 r_shadow_shadowmapsize = size;
2064 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2065 r_shadow_shadowmap_parameters[2] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2066 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
2067 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D) goto init_done;
2069 // complex unrolled cube approach (more flexible)
2070 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2071 R_Shadow_MakeVSDCT();
2072 if (!r_shadow_shadowmap2dtexture)
2073 R_Shadow_MakeShadowMap(side, r_shadow_shadowmapmaxsize);
2074 if (r_shadow_shadowmap2dtexture) fbo = r_shadow_fbo2d;
2075 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
2076 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
2077 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
2079 R_Mesh_ResetTextureState();
2080 R_Mesh_ResetRenderTargets();
2081 R_Shadow_RenderMode_Reset();
2084 R_Mesh_SetRenderTargets(fbo, r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
2085 R_SetupShader_DepthOrShadow();
2088 R_SetupShader_ShowDepth();
2089 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
2094 R_SetViewport(&viewport);
2095 flipped = (side & 1) ^ (side >> 2);
2096 r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
2097 r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
2098 switch(vid.renderpath)
2100 case RENDERPATH_GL11:
2101 case RENDERPATH_GL13:
2102 case RENDERPATH_GL20:
2103 case RENDERPATH_CGGL:
2104 GL_CullFace(r_refdef.view.cullface_back);
2105 // OpenGL lets us scissor larger than the viewport, so go ahead and clear all views at once
2106 if ((clear & ((2 << side) - 1)) == (1 << side)) // only clear if the side is the first in the mask
2108 // get tightest scissor rectangle that encloses all viewports in the clear mask
2109 int x1 = clear & 0x15 ? 0 : size;
2110 int x2 = clear & 0x2A ? 2 * size : size;
2111 int y1 = clear & 0x03 ? 0 : (clear & 0xC ? size : 2 * size);
2112 int y2 = clear & 0x30 ? 3 * size : (clear & 0xC ? 2 * size : size);
2113 GL_Scissor(x1, y1, x2 - x1, y2 - y1);
2114 GL_Clear(GL_DEPTH_BUFFER_BIT, NULL, 1.0f, 0);
2116 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2118 case RENDERPATH_D3D9:
2119 Vector4Set(clearcolor, 1,1,1,1);
2120 // completely different meaning than in OpenGL path
2121 r_shadow_shadowmap_parameters[1] = 0;
2122 r_shadow_shadowmap_parameters[3] = -bias;
2123 // we invert the cull mode because we flip the projection matrix
2124 // NOTE: this actually does nothing because the DrawShadowMap code sets it to doublesided...
2125 GL_CullFace(r_refdef.view.cullface_front);
2126 // D3D considers it an error to use a scissor larger than the viewport... clear just this view
2127 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2128 if (r_shadow_shadowmapsampler)
2130 GL_ColorMask(0,0,0,0);
2132 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
2136 GL_ColorMask(1,1,1,1);
2138 GL_Clear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
2141 case RENDERPATH_D3D10:
2142 case RENDERPATH_D3D11:
2143 // D3D considers it an error to use a scissor larger than the viewport... clear just this view
2144 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2145 GL_ColorMask(0,0,0,0);
2147 GL_Clear(GL_DEPTH_BUFFER_BIT, NULL, 1.0f, 0);
2152 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
2154 R_Mesh_ResetTextureState();
2155 R_Mesh_ResetRenderTargets();
2158 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2159 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2160 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2161 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2163 R_Shadow_RenderMode_Reset();
2164 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2166 GL_DepthFunc(GL_EQUAL);
2167 // do global setup needed for the chosen lighting mode
2168 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2169 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2170 r_shadow_usingshadowmap2d = shadowmapping;
2171 r_shadow_rendermode = r_shadow_lightingrendermode;
2172 // only draw light where this geometry was already rendered AND the
2173 // stencil is 128 (values other than this mean shadow)
2175 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2177 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
2180 static const unsigned short bboxelements[36] =
2190 static const float bboxpoints[8][3] =
2202 void R_Shadow_RenderMode_DrawDeferredLight(qboolean stenciltest, qboolean shadowmapping)
2205 float vertex3f[8*3];
2206 const matrix4x4_t *matrix = &rsurface.rtlight->matrix_lighttoworld;
2207 // do global setup needed for the chosen lighting mode
2208 R_Shadow_RenderMode_Reset();
2209 r_shadow_rendermode = r_shadow_lightingrendermode;
2210 R_EntityMatrix(&identitymatrix);
2211 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2212 // only draw light where this geometry was already rendered AND the
2213 // stencil is 128 (values other than this mean shadow)
2214 R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2215 R_Mesh_SetRenderTargets(r_shadow_prepasslightingfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
2217 r_shadow_usingshadowmap2d = shadowmapping;
2219 // render the lighting
2220 R_SetupShader_DeferredLight(rsurface.rtlight);
2221 for (i = 0;i < 8;i++)
2222 Matrix4x4_Transform(matrix, bboxpoints[i], vertex3f + i*3);
2223 GL_ColorMask(1,1,1,1);
2224 GL_DepthMask(false);
2225 GL_DepthRange(0, 1);
2226 GL_PolygonOffset(0, 0);
2228 GL_DepthFunc(GL_GREATER);
2229 GL_CullFace(r_refdef.view.cullface_back);
2230 R_Mesh_PrepareVertices_Vertex3f(8, vertex3f, NULL);
2231 R_Mesh_Draw(0, 8, 0, 12, NULL, NULL, 0, bboxelements, NULL, 0);
2234 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
2236 R_Shadow_RenderMode_Reset();
2237 GL_BlendFunc(GL_ONE, GL_ONE);
2238 GL_DepthRange(0, 1);
2239 GL_DepthTest(r_showshadowvolumes.integer < 2);
2240 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
2241 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2242 GL_CullFace(GL_NONE);
2243 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
2246 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
2248 R_Shadow_RenderMode_Reset();
2249 GL_BlendFunc(GL_ONE, GL_ONE);
2250 GL_DepthRange(0, 1);
2251 GL_DepthTest(r_showlighting.integer < 2);
2252 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2254 GL_DepthFunc(GL_EQUAL);
2255 R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2256 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2259 void R_Shadow_RenderMode_End(void)
2261 R_Shadow_RenderMode_Reset();
2262 R_Shadow_RenderMode_ActiveLight(NULL);
2264 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2265 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2268 int bboxedges[12][2] =
2287 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2289 if (!r_shadow_scissor.integer)
2291 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2292 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2293 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2294 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2297 if(R_ScissorForBBox(mins, maxs, r_shadow_lightscissor))
2298 return true; // invisible
2299 if(r_shadow_lightscissor[0] != r_refdef.view.viewport.x
2300 || r_shadow_lightscissor[1] != r_refdef.view.viewport.y
2301 || r_shadow_lightscissor[2] != r_refdef.view.viewport.width
2302 || r_shadow_lightscissor[3] != r_refdef.view.viewport.height)
2303 r_refdef.stats.lights_scissored++;
2307 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, const float *diffusecolor, const float *ambientcolor)
2310 const float *vertex3f;
2311 const float *normal3f;
2313 float dist, dot, distintensity, shadeintensity, v[3], n[3];
2314 switch (r_shadow_rendermode)
2316 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2317 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2318 if (VectorLength2(diffusecolor) > 0)
2320 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, normal3f = rsurface.batchnormal3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, normal3f += 3, color4f += 4)
2322 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2323 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2324 if ((dot = DotProduct(n, v)) < 0)
2326 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2327 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
2330 VectorCopy(ambientcolor, color4f);
2331 if (r_refdef.fogenabled)
2334 f = RSurf_FogVertex(vertex3f);
2335 VectorScale(color4f, f, color4f);
2342 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
2344 VectorCopy(ambientcolor, color4f);
2345 if (r_refdef.fogenabled)
2348 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2349 f = RSurf_FogVertex(vertex3f);
2350 VectorScale(color4f + 4*i, f, color4f);
2356 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2357 if (VectorLength2(diffusecolor) > 0)
2359 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, normal3f = rsurface.batchnormal3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, normal3f += 3, color4f += 4)
2361 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2362 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2364 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2365 if ((dot = DotProduct(n, v)) < 0)
2367 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2368 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2369 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2370 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2374 color4f[0] = ambientcolor[0] * distintensity;
2375 color4f[1] = ambientcolor[1] * distintensity;
2376 color4f[2] = ambientcolor[2] * distintensity;
2378 if (r_refdef.fogenabled)
2381 f = RSurf_FogVertex(vertex3f);
2382 VectorScale(color4f, f, color4f);
2386 VectorClear(color4f);
2392 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
2394 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2395 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2397 color4f[0] = ambientcolor[0] * distintensity;
2398 color4f[1] = ambientcolor[1] * distintensity;
2399 color4f[2] = ambientcolor[2] * distintensity;
2400 if (r_refdef.fogenabled)
2403 f = RSurf_FogVertex(vertex3f);
2404 VectorScale(color4f, f, color4f);
2408 VectorClear(color4f);
2413 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2414 if (VectorLength2(diffusecolor) > 0)
2416 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, normal3f = rsurface.batchnormal3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, normal3f += 3, color4f += 4)
2418 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2419 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2421 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2422 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2423 if ((dot = DotProduct(n, v)) < 0)
2425 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2426 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2427 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2428 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2432 color4f[0] = ambientcolor[0] * distintensity;
2433 color4f[1] = ambientcolor[1] * distintensity;
2434 color4f[2] = ambientcolor[2] * distintensity;
2436 if (r_refdef.fogenabled)
2439 f = RSurf_FogVertex(vertex3f);
2440 VectorScale(color4f, f, color4f);
2444 VectorClear(color4f);
2450 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
2452 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2453 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2455 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2456 color4f[0] = ambientcolor[0] * distintensity;
2457 color4f[1] = ambientcolor[1] * distintensity;
2458 color4f[2] = ambientcolor[2] * distintensity;
2459 if (r_refdef.fogenabled)
2462 f = RSurf_FogVertex(vertex3f);
2463 VectorScale(color4f, f, color4f);
2467 VectorClear(color4f);
2477 static void R_Shadow_RenderLighting_VisibleLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
2479 // used to display how many times a surface is lit for level design purposes
2480 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
2481 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
2485 static void R_Shadow_RenderLighting_Light_GLSL(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale, float specularscale)
2487 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2488 R_SetupShader_Surface(lightcolor, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT, texturenumsurfaces, texturesurfacelist, NULL);
2489 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2490 GL_DepthFunc(GL_EQUAL);
2492 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2493 GL_DepthFunc(GL_LEQUAL);
2496 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
2503 int newnumtriangles;
2507 int maxtriangles = 4096;
2508 static int newelements[4096*3];
2509 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, diffusecolor2, ambientcolor2);
2510 for (renders = 0;renders < 4;renders++)
2515 newnumtriangles = 0;
2517 // due to low fillrate on the cards this vertex lighting path is
2518 // designed for, we manually cull all triangles that do not
2519 // contain a lit vertex
2520 // this builds batches of triangles from multiple surfaces and
2521 // renders them at once
2522 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
2524 if (VectorLength2(rsurface.passcolor4f + e[0] * 4) + VectorLength2(rsurface.passcolor4f + e[1] * 4) + VectorLength2(rsurface.passcolor4f + e[2] * 4) >= 0.01)
2526 if (newnumtriangles)
2528 newfirstvertex = min(newfirstvertex, e[0]);
2529 newlastvertex = max(newlastvertex, e[0]);
2533 newfirstvertex = e[0];
2534 newlastvertex = e[0];
2536 newfirstvertex = min(newfirstvertex, e[1]);
2537 newlastvertex = max(newlastvertex, e[1]);
2538 newfirstvertex = min(newfirstvertex, e[2]);
2539 newlastvertex = max(newlastvertex, e[2]);
2545 if (newnumtriangles >= maxtriangles)
2547 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
2548 newnumtriangles = 0;
2554 if (newnumtriangles >= 1)
2556 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
2559 // if we couldn't find any lit triangles, exit early
2562 // now reduce the intensity for the next overbright pass
2563 // we have to clamp to 0 here incase the drivers have improper
2564 // handling of negative colors
2565 // (some old drivers even have improper handling of >1 color)
2567 for (i = 0, c = rsurface.passcolor4f + 4 * firstvertex;i < numvertices;i++, c += 4)
2569 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
2571 c[0] = max(0, c[0] - 1);
2572 c[1] = max(0, c[1] - 1);
2573 c[2] = max(0, c[2] - 1);
2585 static void R_Shadow_RenderLighting_Light_Vertex(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale)
2587 // OpenGL 1.1 path (anything)
2588 float ambientcolorbase[3], diffusecolorbase[3];
2589 float ambientcolorpants[3], diffusecolorpants[3];
2590 float ambientcolorshirt[3], diffusecolorshirt[3];
2591 const float *surfacecolor = rsurface.texture->dlightcolor;
2592 const float *surfacepants = rsurface.colormap_pantscolor;
2593 const float *surfaceshirt = rsurface.colormap_shirtcolor;
2594 rtexture_t *basetexture = rsurface.texture->basetexture;
2595 rtexture_t *pantstexture = rsurface.texture->pantstexture;
2596 rtexture_t *shirttexture = rsurface.texture->shirttexture;
2597 qboolean dopants = pantstexture && VectorLength2(surfacepants) >= (1.0f / 1048576.0f);
2598 qboolean doshirt = shirttexture && VectorLength2(surfaceshirt) >= (1.0f / 1048576.0f);
2599 ambientscale *= 2 * r_refdef.view.colorscale;
2600 diffusescale *= 2 * r_refdef.view.colorscale;
2601 ambientcolorbase[0] = lightcolor[0] * ambientscale * surfacecolor[0];ambientcolorbase[1] = lightcolor[1] * ambientscale * surfacecolor[1];ambientcolorbase[2] = lightcolor[2] * ambientscale * surfacecolor[2];
2602 diffusecolorbase[0] = lightcolor[0] * diffusescale * surfacecolor[0];diffusecolorbase[1] = lightcolor[1] * diffusescale * surfacecolor[1];diffusecolorbase[2] = lightcolor[2] * diffusescale * surfacecolor[2];
2603 ambientcolorpants[0] = ambientcolorbase[0] * surfacepants[0];ambientcolorpants[1] = ambientcolorbase[1] * surfacepants[1];ambientcolorpants[2] = ambientcolorbase[2] * surfacepants[2];
2604 diffusecolorpants[0] = diffusecolorbase[0] * surfacepants[0];diffusecolorpants[1] = diffusecolorbase[1] * surfacepants[1];diffusecolorpants[2] = diffusecolorbase[2] * surfacepants[2];
2605 ambientcolorshirt[0] = ambientcolorbase[0] * surfaceshirt[0];ambientcolorshirt[1] = ambientcolorbase[1] * surfaceshirt[1];ambientcolorshirt[2] = ambientcolorbase[2] * surfaceshirt[2];
2606 diffusecolorshirt[0] = diffusecolorbase[0] * surfaceshirt[0];diffusecolorshirt[1] = diffusecolorbase[1] * surfaceshirt[1];diffusecolorshirt[2] = diffusecolorbase[2] * surfaceshirt[2];
2607 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | (diffusescale > 0 ? BATCHNEED_ARRAY_NORMAL : 0) | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
2608 rsurface.passcolor4f = R_FrameData_Alloc((rsurface.batchfirstvertex + rsurface.batchnumvertices) * sizeof(float[4]));
2609 R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
2610 R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.passcolor4f, 0, 0);
2611 R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
2612 R_Mesh_TexBind(0, basetexture);
2613 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
2614 R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
2615 switch(r_shadow_rendermode)
2617 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2618 R_Mesh_TexBind(1, r_shadow_attenuation3dtexture);
2619 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
2620 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
2621 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
2623 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2624 R_Mesh_TexBind(2, r_shadow_attenuation2dtexture);
2625 R_Mesh_TexMatrix(2, &rsurface.entitytoattenuationz);
2626 R_Mesh_TexCombine(2, GL_MODULATE, GL_MODULATE, 1, 1);
2627 R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
2629 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2630 R_Mesh_TexBind(1, r_shadow_attenuation2dtexture);
2631 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
2632 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
2633 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
2635 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2640 //R_Mesh_TexBind(0, basetexture);
2641 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorbase, ambientcolorbase);
2644 R_Mesh_TexBind(0, pantstexture);
2645 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorpants, ambientcolorpants);
2649 R_Mesh_TexBind(0, shirttexture);
2650 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorshirt, ambientcolorshirt);
2654 extern cvar_t gl_lightmaps;
2655 void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
2657 float ambientscale, diffusescale, specularscale;
2659 float lightcolor[3];
2660 VectorCopy(rsurface.rtlight->currentcolor, lightcolor);
2661 ambientscale = rsurface.rtlight->ambientscale;
2662 diffusescale = rsurface.rtlight->diffusescale;
2663 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
2664 if (!r_shadow_usenormalmap.integer)
2666 ambientscale += 1.0f * diffusescale;
2670 if ((ambientscale + diffusescale) * VectorLength2(lightcolor) + specularscale * VectorLength2(lightcolor) < (1.0f / 1048576.0f))
2672 negated = (lightcolor[0] + lightcolor[1] + lightcolor[2] < 0) && vid.support.ext_blend_subtract;
2675 VectorNegate(lightcolor, lightcolor);
2676 switch(vid.renderpath)
2678 case RENDERPATH_GL11:
2679 case RENDERPATH_GL13:
2680 case RENDERPATH_GL20:
2681 case RENDERPATH_CGGL:
2682 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
2684 case RENDERPATH_D3D9:
2686 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_SUBTRACT);
2689 case RENDERPATH_D3D10:
2690 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2692 case RENDERPATH_D3D11:
2693 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2697 RSurf_SetupDepthAndCulling();
2698 switch (r_shadow_rendermode)
2700 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2701 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2702 R_Shadow_RenderLighting_VisibleLighting(texturenumsurfaces, texturesurfacelist);
2704 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2705 R_Shadow_RenderLighting_Light_GLSL(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale, specularscale);
2707 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2708 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2709 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2710 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2711 R_Shadow_RenderLighting_Light_Vertex(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale);
2714 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2719 switch(vid.renderpath)
2721 case RENDERPATH_GL11:
2722 case RENDERPATH_GL13:
2723 case RENDERPATH_GL20:
2724 case RENDERPATH_CGGL:
2725 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
2727 case RENDERPATH_D3D9:
2729 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_ADD);
2732 case RENDERPATH_D3D10:
2733 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2735 case RENDERPATH_D3D11:
2736 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2742 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)
2744 matrix4x4_t tempmatrix = *matrix;
2745 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
2747 // if this light has been compiled before, free the associated data
2748 R_RTLight_Uncompile(rtlight);
2750 // clear it completely to avoid any lingering data
2751 memset(rtlight, 0, sizeof(*rtlight));
2753 // copy the properties
2754 rtlight->matrix_lighttoworld = tempmatrix;
2755 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
2756 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
2757 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
2758 VectorCopy(color, rtlight->color);
2759 rtlight->cubemapname[0] = 0;
2760 if (cubemapname && cubemapname[0])
2761 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
2762 rtlight->shadow = shadow;
2763 rtlight->corona = corona;
2764 rtlight->style = style;
2765 rtlight->isstatic = isstatic;
2766 rtlight->coronasizescale = coronasizescale;
2767 rtlight->ambientscale = ambientscale;
2768 rtlight->diffusescale = diffusescale;
2769 rtlight->specularscale = specularscale;
2770 rtlight->flags = flags;
2772 // compute derived data
2773 //rtlight->cullradius = rtlight->radius;
2774 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2775 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2776 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2777 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2778 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2779 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2780 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2783 // compiles rtlight geometry
2784 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2785 void R_RTLight_Compile(rtlight_t *rtlight)
2788 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
2789 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
2790 entity_render_t *ent = r_refdef.scene.worldentity;
2791 dp_model_t *model = r_refdef.scene.worldmodel;
2792 unsigned char *data;
2795 // compile the light
2796 rtlight->compiled = true;
2797 rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
2798 rtlight->static_numleafs = 0;
2799 rtlight->static_numleafpvsbytes = 0;
2800 rtlight->static_leaflist = NULL;
2801 rtlight->static_leafpvs = NULL;
2802 rtlight->static_numsurfaces = 0;
2803 rtlight->static_surfacelist = NULL;
2804 rtlight->static_shadowmap_receivers = 0x3F;
2805 rtlight->static_shadowmap_casters = 0x3F;
2806 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2807 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2808 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2809 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2810 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2811 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2813 if (model && model->GetLightInfo)
2815 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
2816 r_shadow_compilingrtlight = rtlight;
2817 R_FrameData_SetMark();
2818 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);
2819 R_FrameData_ReturnToMark();
2820 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2821 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
2822 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
2823 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
2824 rtlight->static_numsurfaces = numsurfaces;
2825 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
2826 rtlight->static_numleafs = numleafs;
2827 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
2828 rtlight->static_numleafpvsbytes = numleafpvsbytes;
2829 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
2830 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
2831 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
2832 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
2833 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
2834 if (rtlight->static_numsurfaces)
2835 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
2836 if (rtlight->static_numleafs)
2837 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
2838 if (rtlight->static_numleafpvsbytes)
2839 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
2840 if (rtlight->static_numshadowtrispvsbytes)
2841 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
2842 if (rtlight->static_numlighttrispvsbytes)
2843 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
2844 R_FrameData_SetMark();
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 R_FrameData_ReturnToMark();
2857 // now we're done compiling the rtlight
2858 r_shadow_compilingrtlight = NULL;
2862 // use smallest available cullradius - box radius or light radius
2863 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2864 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2866 shadowzpasstris = 0;
2867 if (rtlight->static_meshchain_shadow_zpass)
2868 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
2869 shadowzpasstris += mesh->numtriangles;
2871 shadowzfailtris = 0;
2872 if (rtlight->static_meshchain_shadow_zfail)
2873 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
2874 shadowzfailtris += mesh->numtriangles;
2877 if (rtlight->static_numlighttrispvsbytes)
2878 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
2879 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
2883 if (rtlight->static_numlighttrispvsbytes)
2884 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
2885 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
2888 if (developer_extra.integer)
2889 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);
2892 void R_RTLight_Uncompile(rtlight_t *rtlight)
2894 if (rtlight->compiled)
2896 if (rtlight->static_meshchain_shadow_zpass)
2897 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
2898 rtlight->static_meshchain_shadow_zpass = NULL;
2899 if (rtlight->static_meshchain_shadow_zfail)
2900 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
2901 rtlight->static_meshchain_shadow_zfail = NULL;
2902 if (rtlight->static_meshchain_shadow_shadowmap)
2903 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
2904 rtlight->static_meshchain_shadow_shadowmap = NULL;
2905 // these allocations are grouped
2906 if (rtlight->static_surfacelist)
2907 Mem_Free(rtlight->static_surfacelist);
2908 rtlight->static_numleafs = 0;
2909 rtlight->static_numleafpvsbytes = 0;
2910 rtlight->static_leaflist = NULL;
2911 rtlight->static_leafpvs = NULL;
2912 rtlight->static_numsurfaces = 0;
2913 rtlight->static_surfacelist = NULL;
2914 rtlight->static_numshadowtrispvsbytes = 0;
2915 rtlight->static_shadowtrispvs = NULL;
2916 rtlight->static_numlighttrispvsbytes = 0;
2917 rtlight->static_lighttrispvs = NULL;
2918 rtlight->compiled = false;
2922 void R_Shadow_UncompileWorldLights(void)
2926 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
2927 for (lightindex = 0;lightindex < range;lightindex++)
2929 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2932 R_RTLight_Uncompile(&light->rtlight);
2936 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
2940 // reset the count of frustum planes
2941 // see rtlight->cached_frustumplanes definition for how much this array
2943 rtlight->cached_numfrustumplanes = 0;
2945 // haven't implemented a culling path for ortho rendering
2946 if (!r_refdef.view.useperspective)
2948 // check if the light is on screen and copy the 4 planes if it is
2949 for (i = 0;i < 4;i++)
2950 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
2953 for (i = 0;i < 4;i++)
2954 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
2959 // generate a deformed frustum that includes the light origin, this is
2960 // used to cull shadow casting surfaces that can not possibly cast a
2961 // shadow onto the visible light-receiving surfaces, which can be a
2964 // if the light origin is onscreen the result will be 4 planes exactly
2965 // if the light origin is offscreen on only one axis the result will
2966 // be exactly 5 planes (split-side case)
2967 // if the light origin is offscreen on two axes the result will be
2968 // exactly 4 planes (stretched corner case)
2969 for (i = 0;i < 4;i++)
2971 // quickly reject standard frustum planes that put the light
2972 // origin outside the frustum
2973 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
2976 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
2978 // if all the standard frustum planes were accepted, the light is onscreen
2979 // otherwise we need to generate some more planes below...
2980 if (rtlight->cached_numfrustumplanes < 4)
2982 // at least one of the stock frustum planes failed, so we need to
2983 // create one or two custom planes to enclose the light origin
2984 for (i = 0;i < 4;i++)
2986 // create a plane using the view origin and light origin, and a
2987 // single point from the frustum corner set
2988 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
2989 VectorNormalize(plane.normal);
2990 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
2991 // see if this plane is backwards and flip it if so
2992 for (j = 0;j < 4;j++)
2993 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
2997 VectorNegate(plane.normal, plane.normal);
2999 // flipped plane, test again to see if it is now valid
3000 for (j = 0;j < 4;j++)
3001 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3003 // if the plane is still not valid, then it is dividing the
3004 // frustum and has to be rejected
3008 // we have created a valid plane, compute extra info
3009 PlaneClassify(&plane);
3011 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3013 // if we've found 5 frustum planes then we have constructed a
3014 // proper split-side case and do not need to keep searching for
3015 // planes to enclose the light origin
3016 if (rtlight->cached_numfrustumplanes == 5)
3024 for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
3026 plane = rtlight->cached_frustumplanes[i];
3027 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));
3032 // now add the light-space box planes if the light box is rotated, as any
3033 // caster outside the oriented light box is irrelevant (even if it passed
3034 // the worldspace light box, which is axial)
3035 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3037 for (i = 0;i < 6;i++)
3041 v[i >> 1] = (i & 1) ? -1 : 1;
3042 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3043 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3044 plane.dist = VectorNormalizeLength(plane.normal);
3045 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3046 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3052 // add the world-space reduced box planes
3053 for (i = 0;i < 6;i++)
3055 VectorClear(plane.normal);
3056 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3057 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
3058 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3067 // reduce all plane distances to tightly fit the rtlight cull box, which
3069 VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3070 VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3071 VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3072 VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3073 VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3074 VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3075 VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3076 VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3077 oldnum = rtlight->cached_numfrustumplanes;
3078 rtlight->cached_numfrustumplanes = 0;
3079 for (j = 0;j < oldnum;j++)
3081 // find the nearest point on the box to this plane
3082 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
3083 for (i = 1;i < 8;i++)
3085 dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
3086 if (bestdist > dist)
3089 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);
3090 // if the nearest point is near or behind the plane, we want this
3091 // plane, otherwise the plane is useless as it won't cull anything
3092 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
3094 PlaneClassify(&rtlight->cached_frustumplanes[j]);
3095 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
3102 void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
3106 RSurf_ActiveWorldEntity();
3108 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3111 GL_CullFace(GL_NONE);
3112 mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3113 for (;mesh;mesh = mesh->next)
3115 if (!mesh->sidetotals[r_shadow_shadowmapside])
3117 r_refdef.stats.lights_shadowtriangles += mesh->sidetotals[r_shadow_shadowmapside];
3118 if (mesh->vertex3fbuffer)
3119 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vertex3fbuffer);
3121 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer);
3122 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);
3126 else if (r_refdef.scene.worldentity->model)
3127 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);
3129 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3132 void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3134 qboolean zpass = false;
3137 int surfacelistindex;
3138 msurface_t *surface;
3140 // if triangle neighbors are disabled, shadowvolumes are disabled
3141 if (r_refdef.scene.worldmodel->brush.shadowmesh ? !r_refdef.scene.worldmodel->brush.shadowmesh->neighbor3i : !r_refdef.scene.worldmodel->surfmesh.data_neighbor3i)
3144 RSurf_ActiveWorldEntity();
3146 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3149 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
3151 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
3152 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
3154 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
3155 for (;mesh;mesh = mesh->next)
3157 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
3158 if (mesh->vertex3fbuffer)
3159 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vertex3fbuffer);
3161 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer);
3162 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
3164 // increment stencil if frontface is infront of depthbuffer
3165 GL_CullFace(r_refdef.view.cullface_back);
3166 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
3167 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);
3168 // decrement stencil if backface is infront of depthbuffer
3169 GL_CullFace(r_refdef.view.cullface_front);
3170 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
3172 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
3174 // decrement stencil if backface is behind depthbuffer
3175 GL_CullFace(r_refdef.view.cullface_front);
3176 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
3177 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);
3178 // increment stencil if frontface is behind depthbuffer
3179 GL_CullFace(r_refdef.view.cullface_back);
3180 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
3182 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);
3186 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh)
3188 // use the shadow trispvs calculated earlier by GetLightInfo to cull world triangles on this dynamic light
3189 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
3190 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
3192 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
3193 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
3194 if (CHECKPVSBIT(trispvs, t))
3195 shadowmarklist[numshadowmark++] = t;
3197 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);
3199 else if (numsurfaces)
3201 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);
3204 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3207 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3209 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3210 vec_t relativeshadowradius;
3211 RSurf_ActiveModelEntity(ent, false, false, false);
3212 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3213 // we need to re-init the shader for each entity because the matrix changed
3214 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3215 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3216 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3217 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3218 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3219 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3220 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3221 switch (r_shadow_rendermode)
3223 case R_SHADOW_RENDERMODE_SHADOWMAP2D:
3224 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
3227 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3230 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3233 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3235 // set up properties for rendering light onto this entity
3236 RSurf_ActiveModelEntity(ent, true, true, false);
3237 GL_AlphaTest(false);
3238 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3239 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3240 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3241 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3244 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
3246 if (!r_refdef.scene.worldmodel->DrawLight)
3249 // set up properties for rendering light onto this entity
3250 RSurf_ActiveWorldEntity();
3251 GL_AlphaTest(false);
3252 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3253 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3254 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3255 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3257 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
3259 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3262 void R_Shadow_DrawEntityLight(entity_render_t *ent)
3264 dp_model_t *model = ent->model;
3265 if (!model->DrawLight)
3268 R_Shadow_SetupEntityLight(ent);
3270 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3272 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3275 void R_Shadow_PrepareLight(rtlight_t *rtlight)
3279 int numleafs, numsurfaces;
3280 int *leaflist, *surfacelist;
3281 unsigned char *leafpvs;
3282 unsigned char *shadowtrispvs;
3283 unsigned char *lighttrispvs;
3284 //unsigned char *surfacesides;
3285 int numlightentities;
3286 int numlightentities_noselfshadow;
3287 int numshadowentities;
3288 int numshadowentities_noselfshadow;
3289 static entity_render_t *lightentities[MAX_EDICTS];
3290 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3291 static entity_render_t *shadowentities[MAX_EDICTS];
3292 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3295 rtlight->draw = false;
3297 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3298 // skip lights that are basically invisible (color 0 0 0)
3299 nolight = VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f);
3301 // loading is done before visibility checks because loading should happen
3302 // all at once at the start of a level, not when it stalls gameplay.
3303 // (especially important to benchmarks)
3305 if (rtlight->isstatic && !nolight && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
3307 if (rtlight->compiled)
3308 R_RTLight_Uncompile(rtlight);
3309 R_RTLight_Compile(rtlight);
3313 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
3315 // look up the light style value at this time
3316 f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3317 VectorScale(rtlight->color, f, rtlight->currentcolor);
3319 if (rtlight->selected)
3321 f = 2 + sin(realtime * M_PI * 4.0);
3322 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3326 // if lightstyle is currently off, don't draw the light
3327 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3330 // skip processing on corona-only lights
3334 // if the light box is offscreen, skip it
3335 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3338 VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
3339 VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
3341 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3343 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3345 // compiled light, world available and can receive realtime lighting
3346 // retrieve leaf information
3347 numleafs = rtlight->static_numleafs;
3348 leaflist = rtlight->static_leaflist;
3349 leafpvs = rtlight->static_leafpvs;
3350 numsurfaces = rtlight->static_numsurfaces;
3351 surfacelist = rtlight->static_surfacelist;
3352 //surfacesides = NULL;
3353 shadowtrispvs = rtlight->static_shadowtrispvs;
3354 lighttrispvs = rtlight->static_lighttrispvs;
3356 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3358 // dynamic light, world available and can receive realtime lighting
3359 // calculate lit surfaces and leafs
3360 r_refdef.scene.worldmodel->GetLightInfo(r_refdef.scene.worldentity, rtlight->shadoworigin, rtlight->radius, rtlight->cached_cullmins, rtlight->cached_cullmaxs, r_shadow_buffer_leaflist, r_shadow_buffer_leafpvs, &numleafs, r_shadow_buffer_surfacelist, r_shadow_buffer_surfacepvs, &numsurfaces, r_shadow_buffer_shadowtrispvs, r_shadow_buffer_lighttrispvs, r_shadow_buffer_visitingleafpvs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes);
3361 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3362 leaflist = r_shadow_buffer_leaflist;
3363 leafpvs = r_shadow_buffer_leafpvs;
3364 surfacelist = r_shadow_buffer_surfacelist;
3365 //surfacesides = r_shadow_buffer_surfacesides;
3366 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3367 lighttrispvs = r_shadow_buffer_lighttrispvs;
3368 // if the reduced leaf bounds are offscreen, skip it
3369 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3380 //surfacesides = NULL;
3381 shadowtrispvs = NULL;
3382 lighttrispvs = NULL;
3384 // check if light is illuminating any visible leafs
3387 for (i = 0;i < numleafs;i++)
3388 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3394 // make a list of lit entities and shadow casting entities
3395 numlightentities = 0;
3396 numlightentities_noselfshadow = 0;
3397 numshadowentities = 0;
3398 numshadowentities_noselfshadow = 0;
3400 // add dynamic entities that are lit by the light
3401 for (i = 0;i < r_refdef.scene.numentities;i++)
3404 entity_render_t *ent = r_refdef.scene.entities[i];
3406 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3408 // skip the object entirely if it is not within the valid
3409 // shadow-casting region (which includes the lit region)
3410 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
3412 if (!(model = ent->model))
3414 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
3416 // this entity wants to receive light, is visible, and is
3417 // inside the light box
3418 // TODO: check if the surfaces in the model can receive light
3419 // so now check if it's in a leaf seen by the light
3420 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.BoxTouchingLeafPVS && !r_refdef.scene.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.scene.worldmodel, leafpvs, ent->mins, ent->maxs))
3422 if (ent->flags & RENDER_NOSELFSHADOW)
3423 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
3425 lightentities[numlightentities++] = ent;
3426 // since it is lit, it probably also casts a shadow...
3427 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3428 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3429 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3431 // note: exterior models without the RENDER_NOSELFSHADOW
3432 // flag still create a RENDER_NOSELFSHADOW shadow but
3433 // are lit normally, this means that they are
3434 // self-shadowing but do not shadow other
3435 // RENDER_NOSELFSHADOW entities such as the gun
3436 // (very weird, but keeps the player shadow off the gun)
3437 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3438 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3440 shadowentities[numshadowentities++] = ent;
3443 else if (ent->flags & RENDER_SHADOW)
3445 // this entity is not receiving light, but may still need to
3447 // TODO: check if the surfaces in the model can cast shadow
3448 // now check if it is in a leaf seen by the light
3449 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.BoxTouchingLeafPVS && !r_refdef.scene.worldmodel->brush.BoxTouchingLeafPVS(r_refdef.scene.worldmodel, leafpvs, ent->mins, ent->maxs))
3451 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3452 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3453 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3455 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3456 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3458 shadowentities[numshadowentities++] = ent;
3463 // return if there's nothing at all to light
3464 if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
3467 // count this light in the r_speeds
3468 r_refdef.stats.lights++;
3470 // flag it as worth drawing later
3471 rtlight->draw = true;
3473 // cache all the animated entities that cast a shadow but are not visible
3474 for (i = 0;i < numshadowentities;i++)
3475 if (!shadowentities[i]->animcache_vertex3f)
3476 R_AnimCache_GetEntity(shadowentities[i], false, false);
3477 for (i = 0;i < numshadowentities_noselfshadow;i++)
3478 if (!shadowentities_noselfshadow[i]->animcache_vertex3f)
3479 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
3481 // allocate some temporary memory for rendering this light later in the frame
3482 // reusable buffers need to be copied, static data can be used as-is
3483 rtlight->cached_numlightentities = numlightentities;
3484 rtlight->cached_numlightentities_noselfshadow = numlightentities_noselfshadow;
3485 rtlight->cached_numshadowentities = numshadowentities;
3486 rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
3487 rtlight->cached_numsurfaces = numsurfaces;
3488 rtlight->cached_lightentities = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
3489 rtlight->cached_lightentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
3490 rtlight->cached_shadowentities = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
3491 rtlight->cached_shadowentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
3492 if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
3494 int numshadowtrispvsbytes = (((r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles) + 7) >> 3);
3495 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
3496 rtlight->cached_shadowtrispvs = (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
3497 rtlight->cached_lighttrispvs = (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
3498 rtlight->cached_surfacelist = (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
3502 // compiled light data
3503 rtlight->cached_shadowtrispvs = shadowtrispvs;
3504 rtlight->cached_lighttrispvs = lighttrispvs;
3505 rtlight->cached_surfacelist = surfacelist;
3509 void R_Shadow_DrawLight(rtlight_t *rtlight)
3513 unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
3514 int numlightentities;
3515 int numlightentities_noselfshadow;
3516 int numshadowentities;
3517 int numshadowentities_noselfshadow;
3518 entity_render_t **lightentities;
3519 entity_render_t **lightentities_noselfshadow;
3520 entity_render_t **shadowentities;
3521 entity_render_t **shadowentities_noselfshadow;
3523 static unsigned char entitysides[MAX_EDICTS];
3524 static unsigned char entitysides_noselfshadow[MAX_EDICTS];
3525 vec3_t nearestpoint;
3527 qboolean castshadows;
3530 // check if we cached this light this frame (meaning it is worth drawing)
3534 numlightentities = rtlight->cached_numlightentities;
3535 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
3536 numshadowentities = rtlight->cached_numshadowentities;
3537 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
3538 numsurfaces = rtlight->cached_numsurfaces;
3539 lightentities = rtlight->cached_lightentities;
3540 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
3541 shadowentities = rtlight->cached_shadowentities;
3542 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
3543 shadowtrispvs = rtlight->cached_shadowtrispvs;
3544 lighttrispvs = rtlight->cached_lighttrispvs;
3545 surfacelist = rtlight->cached_surfacelist;
3547 // set up a scissor rectangle for this light
3548 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3551 // don't let sound skip if going slow
3552 if (r_refdef.scene.extraupdate)
3555 // make this the active rtlight for rendering purposes
3556 R_Shadow_RenderMode_ActiveLight(rtlight);
3558 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
3560 // optionally draw visible shape of the shadow volumes
3561 // for performance analysis by level designers
3562 R_Shadow_RenderMode_VisibleShadowVolumes();
3564 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
3565 for (i = 0;i < numshadowentities;i++)
3566 R_Shadow_DrawEntityShadow(shadowentities[i]);
3567 for (i = 0;i < numshadowentities_noselfshadow;i++)
3568 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3569 R_Shadow_RenderMode_VisibleLighting(false, false);
3572 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
3574 // optionally draw the illuminated areas
3575 // for performance analysis by level designers
3576 R_Shadow_RenderMode_VisibleLighting(false, false);
3578 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3579 for (i = 0;i < numlightentities;i++)
3580 R_Shadow_DrawEntityLight(lightentities[i]);
3581 for (i = 0;i < numlightentities_noselfshadow;i++)
3582 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3585 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
3587 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
3588 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
3589 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
3590 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
3592 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance/rtlight->radius));
3593 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
3594 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
3596 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
3602 int receivermask = 0;
3603 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
3604 Matrix4x4_Abs(&radiustolight);
3606 r_shadow_shadowmaplod = 0;
3607 for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
3608 if ((r_shadow_shadowmapmaxsize >> i) > lodlinear)
3609 r_shadow_shadowmaplod = i;
3611 size = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
3613 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
3615 surfacesides = NULL;
3618 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3620 castermask = rtlight->static_shadowmap_casters;
3621 receivermask = rtlight->static_shadowmap_receivers;
3625 surfacesides = r_shadow_buffer_surfacesides;
3626 for(i = 0;i < numsurfaces;i++)
3628 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
3629 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3630 castermask |= surfacesides[i];
3631 receivermask |= surfacesides[i];
3635 if (receivermask < 0x3F)
3637 for (i = 0;i < numlightentities;i++)
3638 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3639 if (receivermask < 0x3F)
3640 for(i = 0; i < numlightentities_noselfshadow;i++)
3641 receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3644 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
3648 for (i = 0;i < numshadowentities;i++)
3649 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3650 for (i = 0;i < numshadowentities_noselfshadow;i++)
3651 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3654 //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
3656 // render shadow casters into 6 sided depth texture
3657 for (side = 0;side < 6;side++) if (receivermask & (1 << side))
3659 R_Shadow_RenderMode_ShadowMap(side, receivermask, size);
3660 if (! (castermask & (1 << side))) continue;
3662 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
3663 for (i = 0;i < numshadowentities;i++) if (entitysides[i] & (1 << side))
3664 R_Shadow_DrawEntityShadow(shadowentities[i]);
3667 if (numlightentities_noselfshadow)
3669 // render lighting using the depth texture as shadowmap
3670 // draw lighting in the unmasked areas
3671 R_Shadow_RenderMode_Lighting(false, false, true);
3672 for (i = 0;i < numlightentities_noselfshadow;i++)
3673 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3676 // render shadow casters into 6 sided depth texture
3677 if (numshadowentities_noselfshadow)
3679 for (side = 0;side < 6;side++) if ((receivermask & castermask) & (1 << side))
3681 R_Shadow_RenderMode_ShadowMap(side, 0, size);
3682 for (i = 0;i < numshadowentities_noselfshadow;i++) if (entitysides_noselfshadow[i] & (1 << side))
3683 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3687 // render lighting using the depth texture as shadowmap
3688 // draw lighting in the unmasked areas
3689 R_Shadow_RenderMode_Lighting(false, false, true);
3690 // draw lighting in the unmasked areas
3692 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3693 for (i = 0;i < numlightentities;i++)
3694 R_Shadow_DrawEntityLight(lightentities[i]);
3696 else if (castshadows && vid.stencil)
3698 // draw stencil shadow volumes to mask off pixels that are in shadow
3699 // so that they won't receive lighting
3700 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
3701 R_Shadow_ClearStencil();
3704 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
3705 for (i = 0;i < numshadowentities;i++)
3706 R_Shadow_DrawEntityShadow(shadowentities[i]);
3708 // draw lighting in the unmasked areas
3709 R_Shadow_RenderMode_Lighting(true, false, false);
3710 for (i = 0;i < numlightentities_noselfshadow;i++)
3711 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3713 for (i = 0;i < numshadowentities_noselfshadow;i++)
3714 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3716 // draw lighting in the unmasked areas
3717 R_Shadow_RenderMode_Lighting(true, false, false);
3719 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3720 for (i = 0;i < numlightentities;i++)
3721 R_Shadow_DrawEntityLight(lightentities[i]);
3725 // draw lighting in the unmasked areas
3726 R_Shadow_RenderMode_Lighting(false, false, false);
3728 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3729 for (i = 0;i < numlightentities;i++)
3730 R_Shadow_DrawEntityLight(lightentities[i]);
3731 for (i = 0;i < numlightentities_noselfshadow;i++)
3732 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3735 if (r_shadow_usingdeferredprepass)
3737 // when rendering deferred lighting, we simply rasterize the box
3738 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
3739 R_Shadow_RenderMode_DrawDeferredLight(false, true);
3740 else if (castshadows && vid.stencil)
3741 R_Shadow_RenderMode_DrawDeferredLight(true, false);
3743 R_Shadow_RenderMode_DrawDeferredLight(false, false);
3747 static void R_Shadow_FreeDeferred(void)
3749 R_Mesh_DestroyFramebufferObject(r_shadow_prepassgeometryfbo);
3750 r_shadow_prepassgeometryfbo = 0;
3752 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingfbo);
3753 r_shadow_prepasslightingfbo = 0;
3755 if (r_shadow_prepassgeometrydepthtexture)
3756 R_FreeTexture(r_shadow_prepassgeometrydepthtexture);
3757 r_shadow_prepassgeometrydepthtexture = NULL;
3759 if (r_shadow_prepassgeometrydepthcolortexture)
3760 R_FreeTexture(r_shadow_prepassgeometrydepthcolortexture);
3761 r_shadow_prepassgeometrydepthcolortexture = NULL;
3763 if (r_shadow_prepassgeometrynormalmaptexture)
3764 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
3765 r_shadow_prepassgeometrynormalmaptexture = NULL;
3767 if (r_shadow_prepasslightingdiffusetexture)
3768 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
3769 r_shadow_prepasslightingdiffusetexture = NULL;
3771 if (r_shadow_prepasslightingspeculartexture)
3772 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
3773 r_shadow_prepasslightingspeculartexture = NULL;
3776 void R_Shadow_DrawPrepass(void)
3784 entity_render_t *ent;
3785 float clearcolor[4];
3787 GL_AlphaTest(false);
3788 R_Mesh_ResetTextureState();
3790 GL_ColorMask(1,1,1,1);
3791 GL_BlendFunc(GL_ONE, GL_ZERO);
3794 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, r_shadow_prepassgeometrydepthcolortexture, NULL, NULL);
3795 Vector4Set(clearcolor, 0.5f,0.5f,0.5f,1.0f);
3796 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
3797 if (r_timereport_active)
3798 R_TimeReport("prepasscleargeom");
3800 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
3801 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
3802 if (r_timereport_active)
3803 R_TimeReport("prepassworld");
3805 for (i = 0;i < r_refdef.scene.numentities;i++)
3807 if (!r_refdef.viewcache.entityvisible[i])
3809 ent = r_refdef.scene.entities[i];
3810 if (ent->model && ent->model->DrawPrepass != NULL)
3811 ent->model->DrawPrepass(ent);
3814 if (r_timereport_active)
3815 R_TimeReport("prepassmodels");
3817 GL_DepthMask(false);
3818 GL_ColorMask(1,1,1,1);
3821 R_Mesh_SetRenderTargets(r_shadow_prepasslightingfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
3822 Vector4Set(clearcolor, 0, 0, 0, 0);
3823 GL_Clear(GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
3824 if (r_timereport_active)
3825 R_TimeReport("prepassclearlit");
3827 R_Shadow_RenderMode_Begin();
3829 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3830 if (r_shadow_debuglight.integer >= 0)
3832 lightindex = r_shadow_debuglight.integer;
3833 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3834 if (light && (light->flags & flag) && light->rtlight.draw)
3835 R_Shadow_DrawLight(&light->rtlight);
3839 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3840 for (lightindex = 0;lightindex < range;lightindex++)
3842 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3843 if (light && (light->flags & flag) && light->rtlight.draw)
3844 R_Shadow_DrawLight(&light->rtlight);
3847 if (r_refdef.scene.rtdlight)
3848 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
3849 if (r_refdef.scene.lights[lnum]->draw)
3850 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
3852 R_Mesh_ResetRenderTargets();
3854 R_Shadow_RenderMode_End();
3856 if (r_timereport_active)
3857 R_TimeReport("prepasslights");
3860 void R_Shadow_DrawLightSprites(void);
3861 void R_Shadow_PrepareLights(void)
3871 if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4) ||
3872 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
3873 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20) ||
3874 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
3875 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
3876 r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
3877 R_Shadow_FreeShadowMaps();
3879 r_shadow_usingshadowmaportho = false;
3881 switch (vid.renderpath)
3883 case RENDERPATH_GL20:
3884 case RENDERPATH_CGGL:
3885 case RENDERPATH_D3D9:
3886 case RENDERPATH_D3D10:
3887 case RENDERPATH_D3D11:
3888 if (!r_shadow_deferred.integer || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_STENCIL || !vid.support.ext_framebuffer_object || vid.maxdrawbuffers < 2)
3890 r_shadow_usingdeferredprepass = false;
3891 if (r_shadow_prepass_width)
3892 R_Shadow_FreeDeferred();
3893 r_shadow_prepass_width = r_shadow_prepass_height = 0;
3897 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
3899 R_Shadow_FreeDeferred();
3901 r_shadow_usingdeferredprepass = true;
3902 r_shadow_prepass_width = vid.width;
3903 r_shadow_prepass_height = vid.height;
3904 r_shadow_prepassgeometrydepthtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "prepassgeometrydepthmap", vid.width, vid.height, 24, false);
3905 switch (vid.renderpath)
3907 case RENDERPATH_D3D9:
3908 r_shadow_prepassgeometrydepthcolortexture = R_LoadTexture2D(r_shadow_texturepool, "prepassgeometrydepthcolormap", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, -1, NULL);
3913 r_shadow_prepassgeometrynormalmaptexture = R_LoadTexture2D(r_shadow_texturepool, "prepassgeometrynormalmap", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, -1, NULL);
3914 r_shadow_prepasslightingdiffusetexture = R_LoadTexture2D(r_shadow_texturepool, "prepasslightingdiffuse", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, -1, NULL);
3915 r_shadow_prepasslightingspeculartexture = R_LoadTexture2D(r_shadow_texturepool, "prepasslightingspecular", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, -1, NULL);
3917 // set up the geometry pass fbo (depth + normalmap)
3918 r_shadow_prepassgeometryfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
3919 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, r_shadow_prepassgeometrydepthcolortexture, NULL, NULL);
3920 // render depth into one texture and normalmap into the other
3921 if (qglDrawBuffersARB)
3923 qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);CHECKGLERROR
3924 qglReadBuffer(GL_NONE);CHECKGLERROR
3925 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
3926 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
3928 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
3929 Cvar_SetValueQuick(&r_shadow_deferred, 0);
3930 r_shadow_usingdeferredprepass = false;
3934 // set up the lighting pass fbo (diffuse + specular)
3935 r_shadow_prepasslightingfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
3936 R_Mesh_SetRenderTargets(r_shadow_prepasslightingfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
3937 // render diffuse into one texture and specular into another,
3938 // with depth and normalmap bound as textures,
3939 // with depth bound as attachment as well
3940 if (qglDrawBuffersARB)
3942 qglDrawBuffersARB(2, r_shadow_prepasslightingdrawbuffers);CHECKGLERROR
3943 qglReadBuffer(GL_NONE);CHECKGLERROR
3944 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
3945 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
3947 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
3948 Cvar_SetValueQuick(&r_shadow_deferred, 0);
3949 r_shadow_usingdeferredprepass = false;
3954 case RENDERPATH_GL13:
3955 case RENDERPATH_GL11:
3956 r_shadow_usingdeferredprepass = false;
3960 R_Shadow_EnlargeLeafSurfaceTrisBuffer(r_refdef.scene.worldmodel->brush.num_leafs, r_refdef.scene.worldmodel->num_surfaces, r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles, r_refdef.scene.worldmodel->surfmesh.num_triangles);
3962 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3963 if (r_shadow_debuglight.integer >= 0)
3965 lightindex = r_shadow_debuglight.integer;
3966 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3967 if (light && (light->flags & flag))
3968 R_Shadow_PrepareLight(&light->rtlight);
3972 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3973 for (lightindex = 0;lightindex < range;lightindex++)
3975 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3976 if (light && (light->flags & flag))
3977 R_Shadow_PrepareLight(&light->rtlight);
3980 if (r_refdef.scene.rtdlight)
3982 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
3983 R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
3985 else if(gl_flashblend.integer)
3987 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
3989 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
3990 f = (rtlight->style >= 0 ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3991 VectorScale(rtlight->color, f, rtlight->currentcolor);
3995 if (r_editlights.integer)
3996 R_Shadow_DrawLightSprites();
3999 void R_Shadow_DrawLights(void)
4007 R_Shadow_RenderMode_Begin();
4009 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4010 if (r_shadow_debuglight.integer >= 0)
4012 lightindex = r_shadow_debuglight.integer;
4013 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4014 if (light && (light->flags & flag))
4015 R_Shadow_DrawLight(&light->rtlight);
4019 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4020 for (lightindex = 0;lightindex < range;lightindex++)
4022 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4023 if (light && (light->flags & flag))
4024 R_Shadow_DrawLight(&light->rtlight);
4027 if (r_refdef.scene.rtdlight)
4028 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4029 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4031 R_Shadow_RenderMode_End();
4034 extern const float r_screenvertex3f[12];
4035 extern void R_SetupView(qboolean allowwaterclippingplane);
4036 extern void R_ResetViewRendering3D(void);
4037 extern void R_ResetViewRendering2D(void);
4038 extern cvar_t r_shadows;
4039 extern cvar_t r_shadows_darken;
4040 extern cvar_t r_shadows_drawafterrtlighting;
4041 extern cvar_t r_shadows_castfrombmodels;
4042 extern cvar_t r_shadows_throwdistance;
4043 extern cvar_t r_shadows_throwdirection;
4044 extern cvar_t r_shadows_focus;
4045 extern cvar_t r_shadows_shadowmapscale;
4047 void R_Shadow_PrepareModelShadows(void)
4050 float scale, size, radius, dot1, dot2;
4051 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
4052 entity_render_t *ent;
4054 if (!r_refdef.scene.numentities)
4057 switch (r_shadow_shadowmode)
4059 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4060 if (r_shadows.integer >= 2)
4063 case R_SHADOW_SHADOWMODE_STENCIL:
4064 for (i = 0;i < r_refdef.scene.numentities;i++)
4066 ent = r_refdef.scene.entities[i];
4067 if (!ent->animcache_vertex3f && ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4068 R_AnimCache_GetEntity(ent, false, false);
4075 size = 2*r_shadow_shadowmapmaxsize;
4076 scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
4077 radius = 0.5f * size / scale;
4079 Math_atov(r_shadows_throwdirection.string, shadowdir);
4080 VectorNormalize(shadowdir);
4081 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4082 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4083 if (fabs(dot1) <= fabs(dot2))
4084 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4086 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4087 VectorNormalize(shadowforward);
4088 CrossProduct(shadowdir, shadowforward, shadowright);
4089 Math_atov(r_shadows_focus.string, shadowfocus);
4090 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4091 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4092 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4093 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4094 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4096 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4098 shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4099 shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4100 shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4101 shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4102 shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4103 shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4105 for (i = 0;i < r_refdef.scene.numentities;i++)
4107 ent = r_refdef.scene.entities[i];
4108 if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
4110 // cast shadows from anything of the map (submodels are optional)
4111 if (!ent->animcache_vertex3f && ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4112 R_AnimCache_GetEntity(ent, false, false);
4116 void R_DrawModelShadowMaps(void)
4119 float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
4120 entity_render_t *ent;
4121 vec3_t relativelightorigin;
4122 vec3_t relativelightdirection, relativeforward, relativeright;
4123 vec3_t relativeshadowmins, relativeshadowmaxs;
4124 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
4126 matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
4127 r_viewport_t viewport;
4129 float clearcolor[4];
4131 if (!r_refdef.scene.numentities)
4134 switch (r_shadow_shadowmode)
4136 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4142 R_ResetViewRendering3D();
4143 R_Shadow_RenderMode_Begin();
4144 R_Shadow_RenderMode_ActiveLight(NULL);
4146 switch (r_shadow_shadowmode)
4148 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4149 if (!r_shadow_shadowmap2dtexture)
4150 R_Shadow_MakeShadowMap(0, r_shadow_shadowmapmaxsize);
4151 fbo = r_shadow_fbo2d;
4152 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
4153 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
4154 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
4160 size = 2*r_shadow_shadowmapmaxsize;
4161 scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
4162 radius = 0.5f / scale;
4163 nearclip = -r_shadows_throwdistance.value;
4164 farclip = r_shadows_throwdistance.value;
4165 bias = r_shadow_shadowmapping_bias.value * r_shadow_shadowmapping_nearclip.value / (2 * r_shadows_throwdistance.value) * (1024.0f / size);
4167 r_shadow_shadowmap_parameters[0] = size;
4168 r_shadow_shadowmap_parameters[1] = size;
4169 r_shadow_shadowmap_parameters[2] = 1.0;
4170 r_shadow_shadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
4172 Math_atov(r_shadows_throwdirection.string, shadowdir);
4173 VectorNormalize(shadowdir);
4174 Math_atov(r_shadows_focus.string, shadowfocus);
4175 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4176 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4177 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4178 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4179 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4180 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4181 if (fabs(dot1) <= fabs(dot2))
4182 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4184 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4185 VectorNormalize(shadowforward);
4186 VectorM(scale, shadowforward, &m[0]);
4187 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4189 m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
4190 CrossProduct(shadowdir, shadowforward, shadowright);
4191 VectorM(scale, shadowright, &m[4]);
4192 m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
4193 VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
4194 m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
4195 Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
4196 Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
4197 R_Viewport_InitOrtho(&viewport, &cameramatrix, 0, 0, size, size, 0, 0, 1, 1, 0, -1, NULL);
4199 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4201 R_Mesh_SetRenderTargets(fbo, r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
4202 R_SetupShader_DepthOrShadow();
4203 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
4206 R_SetViewport(&viewport);
4207 GL_Scissor(viewport.x, viewport.y, min(viewport.width + r_shadow_shadowmapborder, 2*r_shadow_shadowmapmaxsize), viewport.height + r_shadow_shadowmapborder);
4208 Vector4Set(clearcolor, 1,1,1,1);
4209 // in D3D9 we have to render to a color texture shadowmap
4210 // in GL we render directly to a depth texture only
4211 if (r_shadow_shadowmap2dtexture)
4212 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4214 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4215 // render into a slightly restricted region so that the borders of the
4216 // shadowmap area fade away, rather than streaking across everything
4217 // outside the usable area
4218 GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
4222 R_Mesh_ResetRenderTargets();
4223 R_SetupShader_ShowDepth();
4224 GL_ColorMask(1,1,1,1);
4225 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4228 for (i = 0;i < r_refdef.scene.numentities;i++)
4230 ent = r_refdef.scene.entities[i];
4232 // cast shadows from anything of the map (submodels are optional)
4233 if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4235 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4236 Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
4237 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4238 Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
4239 Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
4240 relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4241 relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4242 relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4243 relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4244 relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4245 relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4246 RSurf_ActiveModelEntity(ent, false, false, false);
4247 ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
4248 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4255 unsigned char *rawpixels = Z_Malloc(viewport.width*viewport.height*4);
4257 qglReadPixels(viewport.x, viewport.y, viewport.width, viewport.height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, rawpixels);
4259 Image_WriteTGABGRA("r_shadows_2.tga", viewport.width, viewport.height, rawpixels);
4260 Cvar_SetValueQuick(&r_test, 0);
4265 R_Shadow_RenderMode_End();
4267 Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
4268 Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
4269 Matrix4x4_CreateScale3(&scalematrix, size, -size, 1);
4270 Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
4271 Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
4272 Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
4274 switch (vid.renderpath)
4276 case RENDERPATH_GL11:
4277 case RENDERPATH_GL13:
4278 case RENDERPATH_GL20:
4279 case RENDERPATH_CGGL:
4281 case RENDERPATH_D3D9:
4282 case RENDERPATH_D3D10:
4283 case RENDERPATH_D3D11:
4284 #ifdef OPENGL_ORIENTATION
4285 r_shadow_shadowmapmatrix.m[0][0] *= -1.0f;
4286 r_shadow_shadowmapmatrix.m[0][1] *= -1.0f;
4287 r_shadow_shadowmapmatrix.m[0][2] *= -1.0f;
4288 r_shadow_shadowmapmatrix.m[0][3] *= -1.0f;
4290 r_shadow_shadowmapmatrix.m[0][0] *= -1.0f;
4291 r_shadow_shadowmapmatrix.m[1][0] *= -1.0f;
4292 r_shadow_shadowmapmatrix.m[2][0] *= -1.0f;
4293 r_shadow_shadowmapmatrix.m[3][0] *= -1.0f;
4298 r_shadow_usingshadowmaportho = true;
4299 switch (r_shadow_shadowmode)
4301 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4302 r_shadow_usingshadowmap2d = true;
4309 void R_DrawModelShadows(void)
4312 float relativethrowdistance;
4313 entity_render_t *ent;
4314 vec3_t relativelightorigin;
4315 vec3_t relativelightdirection;
4316 vec3_t relativeshadowmins, relativeshadowmaxs;
4317 vec3_t tmp, shadowdir;
4319 if (!r_refdef.scene.numentities || !vid.stencil || (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL && r_shadows.integer != 1))
4322 R_ResetViewRendering3D();
4323 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4324 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4325 R_Shadow_RenderMode_Begin();
4326 R_Shadow_RenderMode_ActiveLight(NULL);
4327 r_shadow_lightscissor[0] = r_refdef.view.x;
4328 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
4329 r_shadow_lightscissor[2] = r_refdef.view.width;
4330 r_shadow_lightscissor[3] = r_refdef.view.height;
4331 R_Shadow_RenderMode_StencilShadowVolumes(false);
4334 if (r_shadows.integer == 2)
4336 Math_atov(r_shadows_throwdirection.string, shadowdir);
4337 VectorNormalize(shadowdir);
4340 R_Shadow_ClearStencil();
4342 for (i = 0;i < r_refdef.scene.numentities;i++)
4344 ent = r_refdef.scene.entities[i];
4346 // cast shadows from anything of the map (submodels are optional)
4347 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4349 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4350 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
4351 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
4352 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
4353 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4356 if(ent->entitynumber != 0)
4358 if(ent->entitynumber >= MAX_EDICTS) // csqc entity
4360 // FIXME handle this
4361 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4365 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
4366 int entnum, entnum2, recursion;
4367 entnum = entnum2 = ent->entitynumber;
4368 for(recursion = 32; recursion > 0; --recursion)
4370 entnum2 = cl.entities[entnum].state_current.tagentity;
4371 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
4376 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
4378 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
4379 // transform into modelspace of OUR entity
4380 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
4381 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
4384 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4388 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4391 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
4392 RSurf_ActiveModelEntity(ent, false, false, false);
4393 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4394 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4398 // not really the right mode, but this will disable any silly stencil features
4399 R_Shadow_RenderMode_End();
4401 // set up ortho view for rendering this pass
4402 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4403 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4404 //GL_ScissorTest(true);
4405 //R_EntityMatrix(&identitymatrix);
4406 //R_Mesh_ResetTextureState();
4407 R_ResetViewRendering2D();
4409 // set up a darkening blend on shadowed areas
4410 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4411 //GL_DepthRange(0, 1);
4412 //GL_DepthTest(false);
4413 //GL_DepthMask(false);
4414 //GL_PolygonOffset(0, 0);CHECKGLERROR
4415 GL_Color(0, 0, 0, r_shadows_darken.value);
4416 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4417 //GL_DepthFunc(GL_ALWAYS);
4418 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_NOTEQUAL, 128, 255);
4420 // apply the blend to the shadowed areas
4421 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, NULL);
4422 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
4423 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4425 // restore the viewport
4426 R_SetViewport(&r_refdef.view.viewport);
4428 // restore other state to normal
4429 //R_Shadow_RenderMode_End();
4432 void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4435 vec3_t centerorigin;
4437 // if it's too close, skip it
4438 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
4440 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4443 if (usequery && r_numqueries + 2 <= r_maxqueries)
4445 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4446 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4447 // 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
4448 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4450 switch(vid.renderpath)
4452 case RENDERPATH_GL20:
4453 case RENDERPATH_GL13:
4454 case RENDERPATH_GL11:
4455 case RENDERPATH_CGGL:
4457 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use GL_DepthFunc instead
4458 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
4459 GL_DepthFunc(GL_ALWAYS);
4460 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4461 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL);
4462 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4463 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4464 GL_DepthFunc(GL_LEQUAL);
4465 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
4466 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4467 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL);
4468 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4469 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4472 case RENDERPATH_D3D9:
4473 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4475 case RENDERPATH_D3D10:
4476 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4478 case RENDERPATH_D3D11:
4479 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4483 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4486 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
4488 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4491 GLint allpixels = 0, visiblepixels = 0;
4492 // now we have to check the query result
4493 if (rtlight->corona_queryindex_visiblepixels)
4495 switch(vid.renderpath)
4497 case RENDERPATH_GL20:
4498 case RENDERPATH_GL13:
4499 case RENDERPATH_GL11:
4500 case RENDERPATH_CGGL:
4502 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
4503 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
4506 case RENDERPATH_D3D9:
4507 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4509 case RENDERPATH_D3D10:
4510 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4512 case RENDERPATH_D3D11:
4513 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4516 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
4517 if (visiblepixels < 1 || allpixels < 1)
4519 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
4520 cscale *= rtlight->corona_visibility;
4524 // FIXME: these traces should scan all render entities instead of cl.world
4525 if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
4528 VectorScale(rtlight->currentcolor, cscale, color);
4529 if (VectorLength(color) > (1.0f / 256.0f))
4532 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
4535 VectorNegate(color, color);
4536 switch(vid.renderpath)
4538 case RENDERPATH_GL11:
4539 case RENDERPATH_GL13:
4540 case RENDERPATH_GL20:
4541 case RENDERPATH_CGGL:
4542 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
4544 case RENDERPATH_D3D9:
4546 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_SUBTRACT);
4549 case RENDERPATH_D3D10:
4550 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4552 case RENDERPATH_D3D11:
4553 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4557 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4558 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);
4559 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4562 switch(vid.renderpath)
4564 case RENDERPATH_GL11:
4565 case RENDERPATH_GL13:
4566 case RENDERPATH_GL20:
4567 case RENDERPATH_CGGL:
4568 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
4570 case RENDERPATH_D3D9:
4572 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_ADD);
4575 case RENDERPATH_D3D10:
4576 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4578 case RENDERPATH_D3D11:
4579 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4586 void R_Shadow_DrawCoronas(void)
4589 qboolean usequery = false;
4594 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4596 if (r_waterstate.renderingscene)
4598 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4599 R_EntityMatrix(&identitymatrix);
4601 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4603 // check occlusion of coronas
4604 // use GL_ARB_occlusion_query if available
4605 // otherwise use raytraces
4607 switch (vid.renderpath)
4609 case RENDERPATH_GL11:
4610 case RENDERPATH_GL13:
4611 case RENDERPATH_GL20:
4612 case RENDERPATH_CGGL:
4613 usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
4616 GL_ColorMask(0,0,0,0);
4617 if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
4618 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
4621 r_maxqueries = (range + r_refdef.scene.numlights) * 4;
4622 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
4624 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
4627 RSurf_ActiveWorldEntity();
4628 GL_BlendFunc(GL_ONE, GL_ZERO);
4629 GL_CullFace(GL_NONE);
4630 GL_DepthMask(false);
4631 GL_DepthRange(0, 1);
4632 GL_PolygonOffset(0, 0);
4634 R_Mesh_ResetTextureState();
4635 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
4638 case RENDERPATH_D3D9:
4640 //Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4642 case RENDERPATH_D3D10:
4643 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4645 case RENDERPATH_D3D11:
4646 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4649 for (lightindex = 0;lightindex < range;lightindex++)
4651 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4654 rtlight = &light->rtlight;
4655 rtlight->corona_visibility = 0;
4656 rtlight->corona_queryindex_visiblepixels = 0;
4657 rtlight->corona_queryindex_allpixels = 0;
4658 if (!(rtlight->flags & flag))
4660 if (rtlight->corona <= 0)
4662 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4664 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4666 for (i = 0;i < r_refdef.scene.numlights;i++)
4668 rtlight = r_refdef.scene.lights[i];
4669 rtlight->corona_visibility = 0;
4670 rtlight->corona_queryindex_visiblepixels = 0;
4671 rtlight->corona_queryindex_allpixels = 0;
4672 if (!(rtlight->flags & flag))
4674 if (rtlight->corona <= 0)
4676 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4679 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4681 // now draw the coronas using the query data for intensity info
4682 for (lightindex = 0;lightindex < range;lightindex++)
4684 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4687 rtlight = &light->rtlight;
4688 if (rtlight->corona_visibility <= 0)
4690 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4692 for (i = 0;i < r_refdef.scene.numlights;i++)
4694 rtlight = r_refdef.scene.lights[i];
4695 if (rtlight->corona_visibility <= 0)
4697 if (gl_flashblend.integer)
4698 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4700 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4706 dlight_t *R_Shadow_NewWorldLight(void)
4708 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4711 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)
4714 // validate parameters
4715 if (style < 0 || style >= MAX_LIGHTSTYLES)
4717 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
4723 // copy to light properties
4724 VectorCopy(origin, light->origin);
4725 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4726 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4727 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4729 light->color[0] = max(color[0], 0);
4730 light->color[1] = max(color[1], 0);
4731 light->color[2] = max(color[2], 0);
4733 light->color[0] = color[0];
4734 light->color[1] = color[1];
4735 light->color[2] = color[2];
4736 light->radius = max(radius, 0);
4737 light->style = style;
4738 light->shadow = shadowenable;
4739 light->corona = corona;
4740 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4741 light->coronasizescale = coronasizescale;
4742 light->ambientscale = ambientscale;
4743 light->diffusescale = diffusescale;
4744 light->specularscale = specularscale;
4745 light->flags = flags;
4747 // update renderable light data
4748 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4749 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);
4752 void R_Shadow_FreeWorldLight(dlight_t *light)
4754 if (r_shadow_selectedlight == light)
4755 r_shadow_selectedlight = NULL;
4756 R_RTLight_Uncompile(&light->rtlight);
4757 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4760 void R_Shadow_ClearWorldLights(void)
4764 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4765 for (lightindex = 0;lightindex < range;lightindex++)
4767 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4769 R_Shadow_FreeWorldLight(light);
4771 r_shadow_selectedlight = NULL;
4774 void R_Shadow_SelectLight(dlight_t *light)
4776 if (r_shadow_selectedlight)
4777 r_shadow_selectedlight->selected = false;
4778 r_shadow_selectedlight = light;
4779 if (r_shadow_selectedlight)
4780 r_shadow_selectedlight->selected = true;
4783 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4785 // this is never batched (there can be only one)
4787 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
4788 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4789 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4792 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4797 skinframe_t *skinframe;
4800 // this is never batched (due to the ent parameter changing every time)
4801 // so numsurfaces == 1 and surfacelist[0] == lightnumber
4802 const dlight_t *light = (dlight_t *)ent;
4805 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
4808 VectorScale(light->color, intensity, spritecolor);
4809 if (VectorLength(spritecolor) < 0.1732f)
4810 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
4811 if (VectorLength(spritecolor) > 1.0f)
4812 VectorNormalize(spritecolor);
4814 // draw light sprite
4815 if (light->cubemapname[0] && !light->shadow)
4816 skinframe = r_editlights_sprcubemapnoshadowlight;
4817 else if (light->cubemapname[0])
4818 skinframe = r_editlights_sprcubemaplight;
4819 else if (!light->shadow)
4820 skinframe = r_editlights_sprnoshadowlight;
4822 skinframe = r_editlights_sprlight;
4824 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);
4825 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4827 // draw selection sprite if light is selected
4828 if (light->selected)
4830 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4831 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4832 // VorteX todo: add normalmode/realtime mode light overlay sprites?
4836 void R_Shadow_DrawLightSprites(void)
4840 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4841 for (lightindex = 0;lightindex < range;lightindex++)
4843 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4845 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
4847 if (!r_editlights_lockcursor)
4848 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
4851 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
4856 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
4857 if (lightindex >= range)
4859 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4862 rtlight = &light->rtlight;
4863 //if (!(rtlight->flags & flag))
4865 VectorCopy(rtlight->shadoworigin, origin);
4866 *radius = rtlight->radius;
4867 VectorCopy(rtlight->color, color);
4871 void R_Shadow_SelectLightInView(void)
4873 float bestrating, rating, temp[3];
4877 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4881 if (r_editlights_lockcursor)
4883 for (lightindex = 0;lightindex < range;lightindex++)
4885 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4888 VectorSubtract(light->origin, r_refdef.view.origin, temp);
4889 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
4892 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
4893 if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1.0f)
4895 bestrating = rating;
4900 R_Shadow_SelectLight(best);
4903 void R_Shadow_LoadWorldLights(void)
4905 int n, a, style, shadow, flags;
4906 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
4907 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
4908 if (cl.worldmodel == NULL)
4910 Con_Print("No map loaded.\n");
4913 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
4914 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4924 for (;COM_Parse(t, true) && strcmp(
4925 if (COM_Parse(t, true))
4927 if (com_token[0] == '!')
4930 origin[0] = atof(com_token+1);
4933 origin[0] = atof(com_token);
4938 while (*s && *s != '\n' && *s != '\r')
4944 // check for modifier flags
4951 #if _MSC_VER >= 1400
4952 #define sscanf sscanf_s
4954 cubemapname[sizeof(cubemapname)-1] = 0;
4955 #if MAX_QPATH != 128
4956 #error update this code if MAX_QPATH changes
4958 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
4959 #if _MSC_VER >= 1400
4960 , sizeof(cubemapname)
4962 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
4965 flags = LIGHTFLAG_REALTIMEMODE;
4973 coronasizescale = 0.25f;
4975 VectorClear(angles);
4978 if (a < 9 || !strcmp(cubemapname, "\"\""))
4980 // remove quotes on cubemapname
4981 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
4984 namelen = strlen(cubemapname) - 2;
4985 memmove(cubemapname, cubemapname + 1, namelen);
4986 cubemapname[namelen] = '\0';
4990 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);
4993 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5001 Con_Printf("invalid rtlights file \"%s\"\n", name);
5002 Mem_Free(lightsstring);
5006 void R_Shadow_SaveWorldLights(void)
5010 size_t bufchars, bufmaxchars;
5012 char name[MAX_QPATH];
5013 char line[MAX_INPUTLINE];
5014 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
5015 // I hate lines which are 3 times my screen size :( --blub
5018 if (cl.worldmodel == NULL)
5020 Con_Print("No map loaded.\n");
5023 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
5024 bufchars = bufmaxchars = 0;
5026 for (lightindex = 0;lightindex < range;lightindex++)
5028 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5031 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
5032 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);
5033 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
5034 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]);
5036 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);
5037 if (bufchars + strlen(line) > bufmaxchars)
5039 bufmaxchars = bufchars + strlen(line) + 2048;
5041 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
5045 memcpy(buf, oldbuf, bufchars);
5051 memcpy(buf + bufchars, line, strlen(line));
5052 bufchars += strlen(line);
5056 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
5061 void R_Shadow_LoadLightsFile(void)
5064 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
5065 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
5066 if (cl.worldmodel == NULL)
5068 Con_Print("No map loaded.\n");
5071 dpsnprintf(name, sizeof(name), "%s.lights", cl.worldnamenoextension);
5072 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5080 while (*s && *s != '\n' && *s != '\r')
5086 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);
5090 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);
5093 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
5094 radius = bound(15, radius, 4096);
5095 VectorScale(color, (2.0f / (8388608.0f)), color);
5096 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5104 Con_Printf("invalid lights file \"%s\"\n", name);
5105 Mem_Free(lightsstring);
5109 // tyrlite/hmap2 light types in the delay field
5110 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
5112 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
5124 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
5125 char key[256], value[MAX_INPUTLINE];
5127 if (cl.worldmodel == NULL)
5129 Con_Print("No map loaded.\n");
5132 // try to load a .ent file first
5133 dpsnprintf(key, sizeof(key), "%s.ent", cl.worldnamenoextension);
5134 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
5135 // and if that is not found, fall back to the bsp file entity string
5137 data = cl.worldmodel->brush.entities;
5140 for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
5142 type = LIGHTTYPE_MINUSX;
5143 origin[0] = origin[1] = origin[2] = 0;
5144 originhack[0] = originhack[1] = originhack[2] = 0;
5145 angles[0] = angles[1] = angles[2] = 0;
5146 color[0] = color[1] = color[2] = 1;
5147 light[0] = light[1] = light[2] = 1;light[3] = 300;
5148 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
5158 if (!COM_ParseToken_Simple(&data, false, false))
5160 if (com_token[0] == '}')
5161 break; // end of entity
5162 if (com_token[0] == '_')
5163 strlcpy(key, com_token + 1, sizeof(key));
5165 strlcpy(key, com_token, sizeof(key));
5166 while (key[strlen(key)-1] == ' ') // remove trailing spaces
5167 key[strlen(key)-1] = 0;
5168 if (!COM_ParseToken_Simple(&data, false, false))
5170 strlcpy(value, com_token, sizeof(value));
5172 // now that we have the key pair worked out...
5173 if (!strcmp("light", key))
5175 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5179 light[0] = vec[0] * (1.0f / 256.0f);
5180 light[1] = vec[0] * (1.0f / 256.0f);
5181 light[2] = vec[0] * (1.0f / 256.0f);
5187 light[0] = vec[0] * (1.0f / 255.0f);
5188 light[1] = vec[1] * (1.0f / 255.0f);
5189 light[2] = vec[2] * (1.0f / 255.0f);
5193 else if (!strcmp("delay", key))
5195 else if (!strcmp("origin", key))
5196 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5197 else if (!strcmp("angle", key))
5198 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5199 else if (!strcmp("angles", key))
5200 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5201 else if (!strcmp("color", key))
5202 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5203 else if (!strcmp("wait", key))
5204 fadescale = atof(value);
5205 else if (!strcmp("classname", key))
5207 if (!strncmp(value, "light", 5))
5210 if (!strcmp(value, "light_fluoro"))
5215 overridecolor[0] = 1;
5216 overridecolor[1] = 1;
5217 overridecolor[2] = 1;
5219 if (!strcmp(value, "light_fluorospark"))
5224 overridecolor[0] = 1;
5225 overridecolor[1] = 1;
5226 overridecolor[2] = 1;
5228 if (!strcmp(value, "light_globe"))
5233 overridecolor[0] = 1;
5234 overridecolor[1] = 0.8;
5235 overridecolor[2] = 0.4;
5237 if (!strcmp(value, "light_flame_large_yellow"))
5242 overridecolor[0] = 1;
5243 overridecolor[1] = 0.5;
5244 overridecolor[2] = 0.1;
5246 if (!strcmp(value, "light_flame_small_yellow"))
5251 overridecolor[0] = 1;
5252 overridecolor[1] = 0.5;
5253 overridecolor[2] = 0.1;
5255 if (!strcmp(value, "light_torch_small_white"))
5260 overridecolor[0] = 1;
5261 overridecolor[1] = 0.5;
5262 overridecolor[2] = 0.1;
5264 if (!strcmp(value, "light_torch_small_walltorch"))
5269 overridecolor[0] = 1;
5270 overridecolor[1] = 0.5;
5271 overridecolor[2] = 0.1;
5275 else if (!strcmp("style", key))
5276 style = atoi(value);
5277 else if (!strcmp("skin", key))
5278 skin = (int)atof(value);
5279 else if (!strcmp("pflags", key))
5280 pflags = (int)atof(value);
5281 //else if (!strcmp("effects", key))
5282 // effects = (int)atof(value);
5283 else if (cl.worldmodel->type == mod_brushq3)
5285 if (!strcmp("scale", key))
5286 lightscale = atof(value);
5287 if (!strcmp("fade", key))
5288 fadescale = atof(value);
5293 if (lightscale <= 0)
5297 if (color[0] == color[1] && color[0] == color[2])
5299 color[0] *= overridecolor[0];
5300 color[1] *= overridecolor[1];
5301 color[2] *= overridecolor[2];
5303 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5304 color[0] = color[0] * light[0];
5305 color[1] = color[1] * light[1];
5306 color[2] = color[2] * light[2];
5309 case LIGHTTYPE_MINUSX:
5311 case LIGHTTYPE_RECIPX:
5313 VectorScale(color, (1.0f / 16.0f), color);
5315 case LIGHTTYPE_RECIPXX:
5317 VectorScale(color, (1.0f / 16.0f), color);
5320 case LIGHTTYPE_NONE:
5324 case LIGHTTYPE_MINUSXX:
5327 VectorAdd(origin, originhack, origin);
5329 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);
5332 Mem_Free(entfiledata);
5336 void R_Shadow_SetCursorLocationForView(void)
5339 vec3_t dest, endpos;
5341 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5342 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
5343 if (trace.fraction < 1)
5345 dist = trace.fraction * r_editlights_cursordistance.value;
5346 push = r_editlights_cursorpushback.value;
5350 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5351 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5355 VectorClear( endpos );
5357 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5358 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5359 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5362 void R_Shadow_UpdateWorldLightSelection(void)
5364 if (r_editlights.integer)
5366 R_Shadow_SetCursorLocationForView();
5367 R_Shadow_SelectLightInView();
5370 R_Shadow_SelectLight(NULL);
5373 void R_Shadow_EditLights_Clear_f(void)
5375 R_Shadow_ClearWorldLights();
5378 void R_Shadow_EditLights_Reload_f(void)
5382 strlcpy(r_shadow_mapname, cl.worldname, sizeof(r_shadow_mapname));
5383 R_Shadow_ClearWorldLights();
5384 R_Shadow_LoadWorldLights();
5385 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5387 R_Shadow_LoadLightsFile();
5388 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5389 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5393 void R_Shadow_EditLights_Save_f(void)
5397 R_Shadow_SaveWorldLights();
5400 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
5402 R_Shadow_ClearWorldLights();
5403 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5406 void R_Shadow_EditLights_ImportLightsFile_f(void)
5408 R_Shadow_ClearWorldLights();
5409 R_Shadow_LoadLightsFile();
5412 void R_Shadow_EditLights_Spawn_f(void)
5415 if (!r_editlights.integer)
5417 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5420 if (Cmd_Argc() != 1)
5422 Con_Print("r_editlights_spawn does not take parameters\n");
5425 color[0] = color[1] = color[2] = 1;
5426 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5429 void R_Shadow_EditLights_Edit_f(void)
5431 vec3_t origin, angles, color;
5432 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5433 int style, shadows, flags, normalmode, realtimemode;
5434 char cubemapname[MAX_INPUTLINE];
5435 if (!r_editlights.integer)
5437 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5440 if (!r_shadow_selectedlight)
5442 Con_Print("No selected light.\n");
5445 VectorCopy(r_shadow_selectedlight->origin, origin);
5446 VectorCopy(r_shadow_selectedlight->angles, angles);
5447 VectorCopy(r_shadow_selectedlight->color, color);
5448 radius = r_shadow_selectedlight->radius;
5449 style = r_shadow_selectedlight->style;
5450 if (r_shadow_selectedlight->cubemapname)
5451 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5454 shadows = r_shadow_selectedlight->shadow;
5455 corona = r_shadow_selectedlight->corona;
5456 coronasizescale = r_shadow_selectedlight->coronasizescale;
5457 ambientscale = r_shadow_selectedlight->ambientscale;
5458 diffusescale = r_shadow_selectedlight->diffusescale;
5459 specularscale = r_shadow_selectedlight->specularscale;
5460 flags = r_shadow_selectedlight->flags;
5461 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5462 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5463 if (!strcmp(Cmd_Argv(1), "origin"))
5465 if (Cmd_Argc() != 5)
5467 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5470 origin[0] = atof(Cmd_Argv(2));
5471 origin[1] = atof(Cmd_Argv(3));
5472 origin[2] = atof(Cmd_Argv(4));
5474 else if (!strcmp(Cmd_Argv(1), "originx"))
5476 if (Cmd_Argc() != 3)
5478 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5481 origin[0] = atof(Cmd_Argv(2));
5483 else if (!strcmp(Cmd_Argv(1), "originy"))
5485 if (Cmd_Argc() != 3)
5487 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5490 origin[1] = atof(Cmd_Argv(2));
5492 else if (!strcmp(Cmd_Argv(1), "originz"))
5494 if (Cmd_Argc() != 3)
5496 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5499 origin[2] = atof(Cmd_Argv(2));
5501 else if (!strcmp(Cmd_Argv(1), "move"))
5503 if (Cmd_Argc() != 5)
5505 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5508 origin[0] += atof(Cmd_Argv(2));
5509 origin[1] += atof(Cmd_Argv(3));
5510 origin[2] += atof(Cmd_Argv(4));
5512 else if (!strcmp(Cmd_Argv(1), "movex"))
5514 if (Cmd_Argc() != 3)
5516 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5519 origin[0] += atof(Cmd_Argv(2));
5521 else if (!strcmp(Cmd_Argv(1), "movey"))
5523 if (Cmd_Argc() != 3)
5525 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5528 origin[1] += atof(Cmd_Argv(2));
5530 else if (!strcmp(Cmd_Argv(1), "movez"))
5532 if (Cmd_Argc() != 3)
5534 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5537 origin[2] += atof(Cmd_Argv(2));
5539 else if (!strcmp(Cmd_Argv(1), "angles"))
5541 if (Cmd_Argc() != 5)
5543 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5546 angles[0] = atof(Cmd_Argv(2));
5547 angles[1] = atof(Cmd_Argv(3));
5548 angles[2] = atof(Cmd_Argv(4));
5550 else if (!strcmp(Cmd_Argv(1), "anglesx"))
5552 if (Cmd_Argc() != 3)
5554 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5557 angles[0] = atof(Cmd_Argv(2));
5559 else if (!strcmp(Cmd_Argv(1), "anglesy"))
5561 if (Cmd_Argc() != 3)
5563 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5566 angles[1] = atof(Cmd_Argv(2));
5568 else if (!strcmp(Cmd_Argv(1), "anglesz"))
5570 if (Cmd_Argc() != 3)
5572 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5575 angles[2] = atof(Cmd_Argv(2));
5577 else if (!strcmp(Cmd_Argv(1), "color"))
5579 if (Cmd_Argc() != 5)
5581 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
5584 color[0] = atof(Cmd_Argv(2));
5585 color[1] = atof(Cmd_Argv(3));
5586 color[2] = atof(Cmd_Argv(4));
5588 else if (!strcmp(Cmd_Argv(1), "radius"))
5590 if (Cmd_Argc() != 3)
5592 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5595 radius = atof(Cmd_Argv(2));
5597 else if (!strcmp(Cmd_Argv(1), "colorscale"))
5599 if (Cmd_Argc() == 3)
5601 double scale = atof(Cmd_Argv(2));
5608 if (Cmd_Argc() != 5)
5610 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
5613 color[0] *= atof(Cmd_Argv(2));
5614 color[1] *= atof(Cmd_Argv(3));
5615 color[2] *= atof(Cmd_Argv(4));
5618 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
5620 if (Cmd_Argc() != 3)
5622 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5625 radius *= atof(Cmd_Argv(2));
5627 else if (!strcmp(Cmd_Argv(1), "style"))
5629 if (Cmd_Argc() != 3)
5631 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5634 style = atoi(Cmd_Argv(2));
5636 else if (!strcmp(Cmd_Argv(1), "cubemap"))
5640 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5643 if (Cmd_Argc() == 3)
5644 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
5648 else if (!strcmp(Cmd_Argv(1), "shadows"))
5650 if (Cmd_Argc() != 3)
5652 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5655 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5657 else if (!strcmp(Cmd_Argv(1), "corona"))
5659 if (Cmd_Argc() != 3)
5661 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5664 corona = atof(Cmd_Argv(2));
5666 else if (!strcmp(Cmd_Argv(1), "coronasize"))
5668 if (Cmd_Argc() != 3)
5670 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5673 coronasizescale = atof(Cmd_Argv(2));
5675 else if (!strcmp(Cmd_Argv(1), "ambient"))
5677 if (Cmd_Argc() != 3)
5679 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5682 ambientscale = atof(Cmd_Argv(2));
5684 else if (!strcmp(Cmd_Argv(1), "diffuse"))
5686 if (Cmd_Argc() != 3)
5688 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5691 diffusescale = atof(Cmd_Argv(2));
5693 else if (!strcmp(Cmd_Argv(1), "specular"))
5695 if (Cmd_Argc() != 3)
5697 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5700 specularscale = atof(Cmd_Argv(2));
5702 else if (!strcmp(Cmd_Argv(1), "normalmode"))
5704 if (Cmd_Argc() != 3)
5706 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5709 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5711 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
5713 if (Cmd_Argc() != 3)
5715 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5718 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5722 Con_Print("usage: r_editlights_edit [property] [value]\n");
5723 Con_Print("Selected light's properties:\n");
5724 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5725 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5726 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5727 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
5728 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
5729 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
5730 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5731 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
5732 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
5733 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
5734 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
5735 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
5736 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5737 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5740 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5741 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5744 void R_Shadow_EditLights_EditAll_f(void)
5747 dlight_t *light, *oldselected;
5750 if (!r_editlights.integer)
5752 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5756 oldselected = r_shadow_selectedlight;
5757 // EditLights doesn't seem to have a "remove" command or something so:
5758 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5759 for (lightindex = 0;lightindex < range;lightindex++)
5761 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5764 R_Shadow_SelectLight(light);
5765 R_Shadow_EditLights_Edit_f();
5767 // return to old selected (to not mess editing once selection is locked)
5768 R_Shadow_SelectLight(oldselected);
5771 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
5773 int lightnumber, lightcount;
5774 size_t lightindex, range;
5778 if (!r_editlights.integer)
5780 x = vid_conwidth.value - 240;
5782 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
5785 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5786 for (lightindex = 0;lightindex < range;lightindex++)
5788 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5791 if (light == r_shadow_selectedlight)
5792 lightnumber = lightindex;
5795 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;
5796 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;
5798 if (r_shadow_selectedlight == NULL)
5800 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;
5801 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;
5802 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;
5803 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;
5804 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;
5805 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;
5806 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;
5807 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;
5808 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;
5809 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;
5810 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;
5811 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;
5812 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;
5813 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;
5814 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;
5817 void R_Shadow_EditLights_ToggleShadow_f(void)
5819 if (!r_editlights.integer)
5821 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5824 if (!r_shadow_selectedlight)
5826 Con_Print("No selected light.\n");
5829 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);
5832 void R_Shadow_EditLights_ToggleCorona_f(void)
5834 if (!r_editlights.integer)
5836 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5839 if (!r_shadow_selectedlight)
5841 Con_Print("No selected light.\n");
5844 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);
5847 void R_Shadow_EditLights_Remove_f(void)
5849 if (!r_editlights.integer)
5851 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
5854 if (!r_shadow_selectedlight)
5856 Con_Print("No selected light.\n");
5859 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
5860 r_shadow_selectedlight = NULL;
5863 void R_Shadow_EditLights_Help_f(void)
5866 "Documentation on r_editlights system:\n"
5868 "r_editlights : enable/disable editing mode\n"
5869 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
5870 "r_editlights_cursorpushback : push back cursor this far from surface\n"
5871 "r_editlights_cursorpushoff : push cursor off surface this far\n"
5872 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
5873 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
5875 "r_editlights_help : this help\n"
5876 "r_editlights_clear : remove all lights\n"
5877 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
5878 "r_editlights_lock : lock selection to current light, if already locked - unlock\n"
5879 "r_editlights_save : save to .rtlights file\n"
5880 "r_editlights_spawn : create a light with default settings\n"
5881 "r_editlights_edit command : edit selected light - more documentation below\n"
5882 "r_editlights_remove : remove selected light\n"
5883 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
5884 "r_editlights_importlightentitiesfrommap : reload light entities\n"
5885 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
5887 "origin x y z : set light location\n"
5888 "originx x: set x component of light location\n"
5889 "originy y: set y component of light location\n"
5890 "originz z: set z component of light location\n"
5891 "move x y z : adjust light location\n"
5892 "movex x: adjust x component of light location\n"
5893 "movey y: adjust y component of light location\n"
5894 "movez z: adjust z component of light location\n"
5895 "angles x y z : set light angles\n"
5896 "anglesx x: set x component of light angles\n"
5897 "anglesy y: set y component of light angles\n"
5898 "anglesz z: set z component of light angles\n"
5899 "color r g b : set color of light (can be brighter than 1 1 1)\n"
5900 "radius radius : set radius (size) of light\n"
5901 "colorscale grey : multiply color of light (1 does nothing)\n"
5902 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
5903 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
5904 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
5905 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
5906 "cubemap basename : set filter cubemap of light (not yet supported)\n"
5907 "shadows 1/0 : turn on/off shadows\n"
5908 "corona n : set corona intensity\n"
5909 "coronasize n : set corona size (0-1)\n"
5910 "ambient n : set ambient intensity (0-1)\n"
5911 "diffuse n : set diffuse intensity (0-1)\n"
5912 "specular n : set specular intensity (0-1)\n"
5913 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
5914 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
5915 "<nothing> : print light properties to console\n"
5919 void R_Shadow_EditLights_CopyInfo_f(void)
5921 if (!r_editlights.integer)
5923 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
5926 if (!r_shadow_selectedlight)
5928 Con_Print("No selected light.\n");
5931 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
5932 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
5933 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
5934 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
5935 if (r_shadow_selectedlight->cubemapname)
5936 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
5938 r_shadow_bufferlight.cubemapname[0] = 0;
5939 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
5940 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
5941 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
5942 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
5943 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
5944 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
5945 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
5948 void R_Shadow_EditLights_PasteInfo_f(void)
5950 if (!r_editlights.integer)
5952 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
5955 if (!r_shadow_selectedlight)
5957 Con_Print("No selected light.\n");
5960 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);
5963 void R_Shadow_EditLights_Lock_f(void)
5965 if (!r_editlights.integer)
5967 Con_Print("Cannot lock on light when not in editing mode. Set r_editlights to 1.\n");
5970 if (r_editlights_lockcursor)
5972 r_editlights_lockcursor = false;
5975 if (!r_shadow_selectedlight)
5977 Con_Print("No selected light to lock on.\n");
5980 r_editlights_lockcursor = true;
5983 void R_Shadow_EditLights_Init(void)
5985 Cvar_RegisterVariable(&r_editlights);
5986 Cvar_RegisterVariable(&r_editlights_cursordistance);
5987 Cvar_RegisterVariable(&r_editlights_cursorpushback);
5988 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
5989 Cvar_RegisterVariable(&r_editlights_cursorgrid);
5990 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
5991 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
5992 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
5993 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)");
5994 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
5995 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
5996 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
5997 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)");
5998 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
5999 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
6000 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
6001 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
6002 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
6003 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
6004 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)");
6005 Cmd_AddCommand("r_editlights_lock", R_Shadow_EditLights_Lock_f, "lock selection to current light, if already locked - unlock");
6011 =============================================================================
6015 =============================================================================
6018 void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, const int flags)
6020 int i, numlights, flag;
6021 float f, relativepoint[3], dist, dist2, lightradius2;
6025 VectorClear(diffusecolor);
6026 VectorClear(diffusenormal);
6028 if (flags & LP_LIGHTMAP)
6030 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
6032 ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_refdef.scene.ambient;
6033 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
6036 VectorSet(ambientcolor, 1, 1, 1);
6038 if (flags & LP_RTWORLD)
6040 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
6041 numlights = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
6042 for (i = 0; i < numlights; i++)
6044 dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
6047 light = &dlight->rtlight;
6048 if (!(light->flags & flag))
6051 lightradius2 = light->radius * light->radius;
6052 VectorSubtract(light->shadoworigin, p, relativepoint);
6053 dist2 = VectorLength2(relativepoint);
6054 if (dist2 >= lightradius2)
6056 dist = sqrt(dist2) / light->radius;
6057 f = dist < 1 ? (r_shadow_lightintensityscale.value * ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist))) : 0;
6060 // todo: add to both ambient and diffuse
6061 if (!light->shadow || CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
6062 VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);
6065 if (flags & LP_DYNLIGHT)
6068 for (i = 0;i < r_refdef.scene.numlights;i++)
6070 light = r_refdef.scene.lights[i];
6072 lightradius2 = light->radius * light->radius;
6073 VectorSubtract(light->shadoworigin, p, relativepoint);
6074 dist2 = VectorLength2(relativepoint);
6075 if (dist2 >= lightradius2)
6077 dist = sqrt(dist2) / light->radius;
6078 f = dist < 1 ? (r_shadow_lightintensityscale.value * ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist))) : 0;
6081 // todo: add to both ambient and diffuse
6082 if (!light->shadow || CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
6083 VectorMA(ambientcolor, f, light->color, ambientcolor);