3 Terminology: Stencil Shadow Volume (sometimes called Stencil Shadows)
4 An extrusion of the lit faces, beginning at the original geometry and ending
5 further from the light source than the original geometry (presumably at least
6 as far as the light's radius, if the light has a radius at all), capped at
7 both front and back to avoid any problems (extrusion from dark faces also
8 works but has a different set of problems)
10 This is normally rendered using Carmack's Reverse technique, in which
11 backfaces behind zbuffer (zfail) increment the stencil, and frontfaces behind
12 zbuffer (zfail) decrement the stencil, the result is a stencil value of zero
13 where shadows did not intersect the visible geometry, suitable as a stencil
14 mask for rendering lighting everywhere but shadow.
16 In our case to hopefully avoid the Creative Labs patent, we draw the backfaces
17 as decrement and the frontfaces as increment, and we redefine the DepthFunc to
18 GL_LESS (the patent uses GL_GEQUAL) which causes zfail when behind surfaces
19 and zpass when infront (the patent draws where zpass with a GL_GEQUAL test),
20 additionally we clear stencil to 128 to avoid the need for the unclamped
21 incr/decr extension (not related to patent).
24 This algorithm may be covered by Creative's patent (US Patent #6384822),
25 however that patent is quite specific about increment on backfaces and
26 decrement on frontfaces where zpass with GL_GEQUAL depth test, which is
27 opposite this implementation and partially opposite Carmack's Reverse paper
28 (which uses GL_LESS, but increments on backfaces and decrements on frontfaces).
32 Terminology: Stencil Light Volume (sometimes called Light Volumes)
33 Similar to a Stencil Shadow Volume, but inverted; rather than containing the
34 areas in shadow it contains the areas in light, this can only be built
35 quickly for certain limited cases (such as portal visibility from a point),
36 but is quite useful for some effects (sunlight coming from sky polygons is
37 one possible example, translucent occluders is another example).
41 Terminology: Optimized Stencil Shadow Volume
42 A Stencil Shadow Volume that has been processed sufficiently to ensure it has
43 no duplicate coverage of areas (no need to shadow an area twice), often this
44 greatly improves performance but is an operation too costly to use on moving
45 lights (however completely optimal Stencil Light Volumes can be constructed
50 Terminology: Per Pixel Lighting (sometimes abbreviated PPL)
51 Per pixel evaluation of lighting equations, at a bare minimum this involves
52 DOT3 shading of diffuse lighting (per pixel dotproduct of negated incidence
53 vector and surface normal, using a texture of the surface bumps, called a
54 NormalMap) if supported by hardware; in our case there is support for cards
55 which are incapable of DOT3, the quality is quite poor however. Additionally
56 it is desirable to have specular evaluation per pixel, per vertex
57 normalization of specular halfangle vectors causes noticable distortion but
58 is unavoidable on hardware without GL_ARB_fragment_program or
59 GL_ARB_fragment_shader.
63 Terminology: Normalization CubeMap
64 A cubemap containing normalized dot3-encoded (vectors of length 1 or less
65 encoded as RGB colors) for any possible direction, this technique allows per
66 pixel calculation of incidence vector for per pixel lighting purposes, which
67 would not otherwise be possible per pixel without GL_ARB_fragment_program or
68 GL_ARB_fragment_shader.
72 Terminology: 2D+1D Attenuation Texturing
73 A very crude approximation of light attenuation with distance which results
74 in cylindrical light shapes which fade vertically as a streak (some games
75 such as Doom3 allow this to be rotated to be less noticable in specific
76 cases), the technique is simply modulating lighting by two 2D textures (which
77 can be the same) on different axes of projection (XY and Z, typically), this
78 is the second best technique available without 3D Attenuation Texturing,
79 GL_ARB_fragment_program or GL_ARB_fragment_shader technology.
83 Terminology: 2D+1D Inverse Attenuation Texturing
84 A clever method described in papers on the Abducted engine, this has a squared
85 distance texture (bright on the outside, black in the middle), which is used
86 twice using GL_ADD blending, the result of this is used in an inverse modulate
87 (GL_ONE_MINUS_DST_ALPHA, GL_ZERO) to implement the equation
88 lighting*=(1-((X*X+Y*Y)+(Z*Z))) which is spherical (unlike 2D+1D attenuation
93 Terminology: 3D Attenuation Texturing
94 A slightly crude approximation of light attenuation with distance, its flaws
95 are limited radius and resolution (performance tradeoffs).
99 Terminology: 3D Attenuation-Normalization Texturing
100 A 3D Attenuation Texture merged with a Normalization CubeMap, by making the
101 vectors shorter the lighting becomes darker, a very effective optimization of
102 diffuse lighting if 3D Attenuation Textures are already used.
106 Terminology: Light Cubemap Filtering
107 A technique for modeling non-uniform light distribution according to
108 direction, for example a lantern may use a cubemap to describe the light
109 emission pattern of the cage around the lantern (as well as soot buildup
110 discoloring the light in certain areas), often also used for softened grate
111 shadows and light shining through a stained glass window (done crudely by
112 texturing the lighting with a cubemap), another good example would be a disco
113 light. This technique is used heavily in many games (Doom3 does not support
118 Terminology: Light Projection Filtering
119 A technique for modeling shadowing of light passing through translucent
120 surfaces, allowing stained glass windows and other effects to be done more
121 elegantly than possible with Light Cubemap Filtering by applying an occluder
122 texture to the lighting combined with a stencil light volume to limit the lit
123 area, this technique is used by Doom3 for spotlights and flashlights, among
124 other things, this can also be used more generally to render light passing
125 through multiple translucent occluders in a scene (using a light volume to
126 describe the area beyond the occluder, and thus mask off rendering of all
131 Terminology: Doom3 Lighting
132 A combination of Stencil Shadow Volume, Per Pixel Lighting, Normalization
133 CubeMap, 2D+1D Attenuation Texturing, and Light Projection Filtering, as
134 demonstrated by the game Doom3.
137 #include "quakedef.h"
138 #include "r_shadow.h"
139 #include "cl_collision.h"
145 extern LPDIRECT3DDEVICE9 vid_d3d9dev;
148 extern void R_Shadow_EditLights_Init(void);
150 typedef enum r_shadow_rendermode_e
152 R_SHADOW_RENDERMODE_NONE,
153 R_SHADOW_RENDERMODE_ZPASS_STENCIL,
154 R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL,
155 R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE,
156 R_SHADOW_RENDERMODE_ZFAIL_STENCIL,
157 R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL,
158 R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE,
159 R_SHADOW_RENDERMODE_LIGHT_VERTEX,
160 R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN,
161 R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN,
162 R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN,
163 R_SHADOW_RENDERMODE_LIGHT_GLSL,
164 R_SHADOW_RENDERMODE_VISIBLEVOLUMES,
165 R_SHADOW_RENDERMODE_VISIBLELIGHTING,
166 R_SHADOW_RENDERMODE_SHADOWMAP2D
168 r_shadow_rendermode_t;
170 typedef enum r_shadow_shadowmode_e
172 R_SHADOW_SHADOWMODE_STENCIL,
173 R_SHADOW_SHADOWMODE_SHADOWMAP2D
175 r_shadow_shadowmode_t;
177 r_shadow_rendermode_t r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
178 r_shadow_rendermode_t r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_NONE;
179 r_shadow_rendermode_t r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_NONE;
180 r_shadow_rendermode_t r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_NONE;
181 qboolean r_shadow_usingshadowmap2d;
182 qboolean r_shadow_usingshadowmaportho;
183 int r_shadow_shadowmapside;
184 float r_shadow_shadowmap_texturescale[2];
185 float r_shadow_shadowmap_parameters[4];
187 int r_shadow_drawbuffer;
188 int r_shadow_readbuffer;
190 int r_shadow_cullface_front, r_shadow_cullface_back;
191 GLuint r_shadow_fbo2d;
192 r_shadow_shadowmode_t r_shadow_shadowmode;
193 int r_shadow_shadowmapfilterquality;
194 int r_shadow_shadowmapdepthbits;
195 int r_shadow_shadowmapmaxsize;
196 qboolean r_shadow_shadowmapvsdct;
197 qboolean r_shadow_shadowmapsampler;
198 int r_shadow_shadowmappcf;
199 int r_shadow_shadowmapborder;
200 matrix4x4_t r_shadow_shadowmapmatrix;
201 int r_shadow_lightscissor[4];
202 qboolean r_shadow_usingdeferredprepass;
204 int maxshadowtriangles;
207 int maxshadowvertices;
208 float *shadowvertex3f;
218 unsigned char *shadowsides;
219 int *shadowsideslist;
226 int r_shadow_buffer_numleafpvsbytes;
227 unsigned char *r_shadow_buffer_visitingleafpvs;
228 unsigned char *r_shadow_buffer_leafpvs;
229 int *r_shadow_buffer_leaflist;
231 int r_shadow_buffer_numsurfacepvsbytes;
232 unsigned char *r_shadow_buffer_surfacepvs;
233 int *r_shadow_buffer_surfacelist;
234 unsigned char *r_shadow_buffer_surfacesides;
236 int r_shadow_buffer_numshadowtrispvsbytes;
237 unsigned char *r_shadow_buffer_shadowtrispvs;
238 int r_shadow_buffer_numlighttrispvsbytes;
239 unsigned char *r_shadow_buffer_lighttrispvs;
241 rtexturepool_t *r_shadow_texturepool;
242 rtexture_t *r_shadow_attenuationgradienttexture;
243 rtexture_t *r_shadow_attenuation2dtexture;
244 rtexture_t *r_shadow_attenuation3dtexture;
245 skinframe_t *r_shadow_lightcorona;
246 rtexture_t *r_shadow_shadowmap2dtexture;
247 rtexture_t *r_shadow_shadowmap2dcolortexture;
248 rtexture_t *r_shadow_shadowmapvsdcttexture;
249 int r_shadow_shadowmapsize; // changes for each light based on distance
250 int r_shadow_shadowmaplod; // changes for each light based on distance
252 GLuint r_shadow_prepassgeometryfbo;
253 GLuint r_shadow_prepasslightingfbo;
254 int r_shadow_prepass_width;
255 int r_shadow_prepass_height;
256 rtexture_t *r_shadow_prepassgeometrydepthtexture;
257 rtexture_t *r_shadow_prepassgeometrydepthcolortexture;
258 rtexture_t *r_shadow_prepassgeometrynormalmaptexture;
259 rtexture_t *r_shadow_prepasslightingdiffusetexture;
260 rtexture_t *r_shadow_prepasslightingspeculartexture;
262 // lights are reloaded when this changes
263 char r_shadow_mapname[MAX_QPATH];
265 // used only for light filters (cubemaps)
266 rtexturepool_t *r_shadow_filters_texturepool;
268 static const GLenum r_shadow_prepasslightingdrawbuffers[2] = {GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT};
270 cvar_t r_shadow_bumpscale_basetexture = {0, "r_shadow_bumpscale_basetexture", "0", "generate fake bumpmaps from diffuse textures at this bumpyness, try 4 to match tenebrae, higher values increase depth, requires r_restart to take effect"};
271 cvar_t r_shadow_bumpscale_bumpmap = {0, "r_shadow_bumpscale_bumpmap", "4", "what magnitude to interpret _bump.tga textures as, higher values increase depth, requires r_restart to take effect"};
272 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
273 cvar_t r_shadow_deferred = {CVAR_SAVE, "r_shadow_deferred", "0", "uses image-based lighting instead of geometry-based lighting, the method used renders a depth image and a normalmap image, renders lights into separate diffuse and specular images, and then combines this into the normal rendering, requires r_shadow_shadowmapping"};
274 cvar_t r_shadow_deferred_8bitrange = {CVAR_SAVE, "r_shadow_deferred_8bitrange", "2", "dynamic range of image-based lighting when using 32bit color (does not apply to fp)"};
275 //cvar_t r_shadow_deferred_fp = {CVAR_SAVE, "r_shadow_deferred_fp", "0", "use 16bit (1) or 32bit (2) floating point for accumulation of image-based lighting"};
276 cvar_t r_shadow_usebihculling = {0, "r_shadow_usebihculling", "1", "use BIH (Bounding Interval Hierarchy) for culling lit surfaces instead of BSP (Binary Space Partitioning)"};
277 cvar_t r_shadow_usenormalmap = {CVAR_SAVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"};
278 cvar_t r_shadow_gloss = {CVAR_SAVE, "r_shadow_gloss", "1", "0 disables gloss (specularity) rendering, 1 uses gloss if textures are found, 2 forces a flat metallic specular effect on everything without textures (similar to tenebrae)"};
279 cvar_t r_shadow_gloss2intensity = {0, "r_shadow_gloss2intensity", "0.125", "how bright the forced flat gloss should look if r_shadow_gloss is 2"};
280 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
281 cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
282 cvar_t r_shadow_gloss2exponent = {0, "r_shadow_gloss2exponent", "32", "same as r_shadow_glossexponent but for forced gloss (gloss 2) surfaces"};
283 cvar_t r_shadow_glossexact = {0, "r_shadow_glossexact", "0", "use exact reflection math for gloss (slightly slower, but should look a tad better)"};
284 cvar_t r_shadow_lightattenuationdividebias = {0, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"};
285 cvar_t r_shadow_lightattenuationlinearscale = {0, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"};
286 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
287 cvar_t r_shadow_lightradiusscale = {0, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
288 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "0", "how far to cast shadows"};
289 cvar_t r_shadow_frontsidecasting = {0, "r_shadow_frontsidecasting", "1", "whether to cast shadows from illuminated triangles (front side of model) or unlit triangles (back side of model)"};
290 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
291 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
292 cvar_t r_shadow_realtime_dlight_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
293 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
294 cvar_t r_shadow_realtime_world = {CVAR_SAVE, "r_shadow_realtime_world", "0", "enables rendering of full world lighting (whether loaded from the map, or a .rtlights file, or a .ent file, or a .lights file produced by hlight)"};
295 cvar_t r_shadow_realtime_world_lightmaps = {CVAR_SAVE, "r_shadow_realtime_world_lightmaps", "0", "brightness to render lightmaps when using full world lighting, try 0.5 for a tenebrae-like appearance"};
296 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
297 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
298 cvar_t r_shadow_realtime_world_compileshadow = {0, "r_shadow_realtime_world_compileshadow", "1", "enables compilation of shadows from world lights for higher performance rendering"};
299 cvar_t r_shadow_realtime_world_compilesvbsp = {0, "r_shadow_realtime_world_compilesvbsp", "1", "enables svbsp optimization during compilation (slower than compileportalculling but more exact)"};
300 cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "0", "enables portal-based culling optimization during compilation (overrides compilesvbsp)"};
301 cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1", "use scissor optimization of light rendering (restricts rendering to the portion of the screen affected by the light)"};
302 cvar_t r_shadow_shadowmapping = {CVAR_SAVE, "r_shadow_shadowmapping", "0", "enables use of shadowmapping (depth texture sampling) instead of stencil shadow volumes, requires gl_fbo 1"};
303 cvar_t r_shadow_shadowmapping_filterquality = {CVAR_SAVE, "r_shadow_shadowmapping_filterquality", "-1", "shadowmap filter modes: -1 = auto-select, 0 = no filtering, 1 = bilinear, 2 = bilinear 2x2 blur (fast), 3 = 3x3 blur (moderate), 4 = 4x4 blur (slow)"};
304 cvar_t r_shadow_shadowmapping_depthbits = {CVAR_SAVE, "r_shadow_shadowmapping_depthbits", "24", "requested minimum shadowmap texture depth bits"};
305 cvar_t r_shadow_shadowmapping_vsdct = {CVAR_SAVE, "r_shadow_shadowmapping_vsdct", "1", "enables use of virtual shadow depth cube texture"};
306 cvar_t r_shadow_shadowmapping_minsize = {CVAR_SAVE, "r_shadow_shadowmapping_minsize", "32", "shadowmap size limit"};
307 cvar_t r_shadow_shadowmapping_maxsize = {CVAR_SAVE, "r_shadow_shadowmapping_maxsize", "512", "shadowmap size limit"};
308 cvar_t r_shadow_shadowmapping_precision = {CVAR_SAVE, "r_shadow_shadowmapping_precision", "1", "makes shadowmaps have a maximum resolution of this number of pixels per light source radius unit such that, for example, at precision 0.5 a light with radius 200 will have a maximum resolution of 100 pixels"};
309 //cvar_t r_shadow_shadowmapping_lod_bias = {CVAR_SAVE, "r_shadow_shadowmapping_lod_bias", "16", "shadowmap size bias"};
310 //cvar_t r_shadow_shadowmapping_lod_scale = {CVAR_SAVE, "r_shadow_shadowmapping_lod_scale", "128", "shadowmap size scaling parameter"};
311 cvar_t r_shadow_shadowmapping_bordersize = {CVAR_SAVE, "r_shadow_shadowmapping_bordersize", "4", "shadowmap size bias for filtering"};
312 cvar_t r_shadow_shadowmapping_nearclip = {CVAR_SAVE, "r_shadow_shadowmapping_nearclip", "1", "shadowmap nearclip in world units"};
313 cvar_t r_shadow_shadowmapping_bias = {CVAR_SAVE, "r_shadow_shadowmapping_bias", "0.03", "shadowmap bias parameter (this is multiplied by nearclip * 1024 / lodsize)"};
314 cvar_t r_shadow_shadowmapping_polygonfactor = {CVAR_SAVE, "r_shadow_shadowmapping_polygonfactor", "2", "slope-dependent shadowmapping bias"};
315 cvar_t r_shadow_shadowmapping_polygonoffset = {CVAR_SAVE, "r_shadow_shadowmapping_polygonoffset", "0", "constant shadowmapping bias"};
316 cvar_t r_shadow_sortsurfaces = {0, "r_shadow_sortsurfaces", "1", "improve performance by sorting illuminated surfaces by texture"};
317 cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
318 cvar_t r_shadow_polygonoffset = {0, "r_shadow_polygonoffset", "1", "how much to push shadow volumes into the distance when rendering, to reduce chances of zfighting artifacts (should not be less than 0)"};
319 cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "1", "use 3D voxel textures for spherical attenuation rather than cylindrical (does not affect OpenGL 2.0 render path)"};
320 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "1", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
321 cvar_t r_coronas_occlusionsizescale = {CVAR_SAVE, "r_coronas_occlusionsizescale", "0.1", "size of light source for corona occlusion checksm the proportion of hidden pixels controls corona intensity"};
322 cvar_t r_coronas_occlusionquery = {CVAR_SAVE, "r_coronas_occlusionquery", "1", "use GL_ARB_occlusion_query extension if supported (fades coronas according to visibility)"};
323 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
324 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
325 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
326 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
327 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
328 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
329 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
330 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
331 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
333 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
334 #define ATTENTABLESIZE 256
335 // 1D gradient, 2D circle and 3D sphere attenuation textures
336 #define ATTEN1DSIZE 32
337 #define ATTEN2DSIZE 64
338 #define ATTEN3DSIZE 32
340 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
341 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
342 static float r_shadow_attentable[ATTENTABLESIZE+1];
344 rtlight_t *r_shadow_compilingrtlight;
345 static memexpandablearray_t r_shadow_worldlightsarray;
346 dlight_t *r_shadow_selectedlight;
347 dlight_t r_shadow_bufferlight;
348 vec3_t r_editlights_cursorlocation;
349 qboolean r_editlights_lockcursor;
351 extern int con_vislines;
353 void R_Shadow_UncompileWorldLights(void);
354 void R_Shadow_ClearWorldLights(void);
355 void R_Shadow_SaveWorldLights(void);
356 void R_Shadow_LoadWorldLights(void);
357 void R_Shadow_LoadLightsFile(void);
358 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
359 void R_Shadow_EditLights_Reload_f(void);
360 void R_Shadow_ValidateCvars(void);
361 static void R_Shadow_MakeTextures(void);
363 #define EDLIGHTSPRSIZE 8
364 skinframe_t *r_editlights_sprcursor;
365 skinframe_t *r_editlights_sprlight;
366 skinframe_t *r_editlights_sprnoshadowlight;
367 skinframe_t *r_editlights_sprcubemaplight;
368 skinframe_t *r_editlights_sprcubemapnoshadowlight;
369 skinframe_t *r_editlights_sprselection;
371 void R_Shadow_SetShadowMode(void)
373 r_shadow_shadowmapmaxsize = bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4);
374 r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20;
375 r_shadow_shadowmapfilterquality = r_shadow_shadowmapping_filterquality.integer;
376 r_shadow_shadowmapdepthbits = r_shadow_shadowmapping_depthbits.integer;
377 r_shadow_shadowmapborder = bound(0, r_shadow_shadowmapping_bordersize.integer, 16);
378 r_shadow_shadowmaplod = -1;
379 r_shadow_shadowmapsize = 0;
380 r_shadow_shadowmapsampler = false;
381 r_shadow_shadowmappcf = 0;
382 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
383 if ((r_shadow_shadowmapping.integer || r_shadow_deferred.integer) && vid.support.ext_framebuffer_object)
385 switch(vid.renderpath)
387 case RENDERPATH_GL20:
388 if(r_shadow_shadowmapfilterquality < 0)
390 if(vid.support.amd_texture_texture4 || vid.support.arb_texture_gather)
391 r_shadow_shadowmappcf = 1;
392 else if(strstr(gl_vendor, "NVIDIA") || strstr(gl_renderer, "Radeon HD"))
394 r_shadow_shadowmapsampler = vid.support.arb_shadow;
395 r_shadow_shadowmappcf = 1;
397 else if(strstr(gl_vendor, "ATI"))
398 r_shadow_shadowmappcf = 1;
400 r_shadow_shadowmapsampler = vid.support.arb_shadow;
404 switch (r_shadow_shadowmapfilterquality)
407 r_shadow_shadowmapsampler = vid.support.arb_shadow;
410 r_shadow_shadowmapsampler = vid.support.arb_shadow;
411 r_shadow_shadowmappcf = 1;
414 r_shadow_shadowmappcf = 1;
417 r_shadow_shadowmappcf = 2;
421 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
422 // Cg has very little choice in depth texture sampling
424 r_shadow_shadowmapsampler = false;
426 case RENDERPATH_CGGL:
427 case RENDERPATH_D3D9:
428 case RENDERPATH_D3D10:
429 case RENDERPATH_D3D11:
430 r_shadow_shadowmapsampler = false;
431 r_shadow_shadowmappcf = 1;
432 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
434 case RENDERPATH_GL13:
436 case RENDERPATH_GL11:
442 qboolean R_Shadow_ShadowMappingEnabled(void)
444 switch (r_shadow_shadowmode)
446 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
453 void R_Shadow_FreeShadowMaps(void)
455 R_Shadow_SetShadowMode();
457 R_Mesh_DestroyFramebufferObject(r_shadow_fbo2d);
461 if (r_shadow_shadowmap2dtexture)
462 R_FreeTexture(r_shadow_shadowmap2dtexture);
463 r_shadow_shadowmap2dtexture = NULL;
465 if (r_shadow_shadowmap2dcolortexture)
466 R_FreeTexture(r_shadow_shadowmap2dcolortexture);
467 r_shadow_shadowmap2dcolortexture = NULL;
469 if (r_shadow_shadowmapvsdcttexture)
470 R_FreeTexture(r_shadow_shadowmapvsdcttexture);
471 r_shadow_shadowmapvsdcttexture = NULL;
474 void r_shadow_start(void)
476 // allocate vertex processing arrays
477 r_shadow_attenuationgradienttexture = NULL;
478 r_shadow_attenuation2dtexture = NULL;
479 r_shadow_attenuation3dtexture = NULL;
480 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
481 r_shadow_shadowmap2dtexture = NULL;
482 r_shadow_shadowmap2dcolortexture = NULL;
483 r_shadow_shadowmapvsdcttexture = NULL;
484 r_shadow_shadowmapmaxsize = 0;
485 r_shadow_shadowmapsize = 0;
486 r_shadow_shadowmaplod = 0;
487 r_shadow_shadowmapfilterquality = -1;
488 r_shadow_shadowmapdepthbits = 0;
489 r_shadow_shadowmapvsdct = false;
490 r_shadow_shadowmapsampler = false;
491 r_shadow_shadowmappcf = 0;
494 R_Shadow_FreeShadowMaps();
496 r_shadow_texturepool = NULL;
497 r_shadow_filters_texturepool = NULL;
498 R_Shadow_ValidateCvars();
499 R_Shadow_MakeTextures();
500 maxshadowtriangles = 0;
501 shadowelements = NULL;
502 maxshadowvertices = 0;
503 shadowvertex3f = NULL;
511 shadowmarklist = NULL;
516 shadowsideslist = NULL;
517 r_shadow_buffer_numleafpvsbytes = 0;
518 r_shadow_buffer_visitingleafpvs = NULL;
519 r_shadow_buffer_leafpvs = NULL;
520 r_shadow_buffer_leaflist = NULL;
521 r_shadow_buffer_numsurfacepvsbytes = 0;
522 r_shadow_buffer_surfacepvs = NULL;
523 r_shadow_buffer_surfacelist = NULL;
524 r_shadow_buffer_surfacesides = NULL;
525 r_shadow_buffer_numshadowtrispvsbytes = 0;
526 r_shadow_buffer_shadowtrispvs = NULL;
527 r_shadow_buffer_numlighttrispvsbytes = 0;
528 r_shadow_buffer_lighttrispvs = NULL;
530 r_shadow_usingdeferredprepass = false;
531 r_shadow_prepass_width = r_shadow_prepass_height = 0;
534 static void R_Shadow_FreeDeferred(void);
535 void r_shadow_shutdown(void)
538 R_Shadow_UncompileWorldLights();
540 R_Shadow_FreeShadowMaps();
542 r_shadow_usingdeferredprepass = false;
543 if (r_shadow_prepass_width)
544 R_Shadow_FreeDeferred();
545 r_shadow_prepass_width = r_shadow_prepass_height = 0;
548 r_shadow_attenuationgradienttexture = NULL;
549 r_shadow_attenuation2dtexture = NULL;
550 r_shadow_attenuation3dtexture = NULL;
551 R_FreeTexturePool(&r_shadow_texturepool);
552 R_FreeTexturePool(&r_shadow_filters_texturepool);
553 maxshadowtriangles = 0;
555 Mem_Free(shadowelements);
556 shadowelements = NULL;
558 Mem_Free(shadowvertex3f);
559 shadowvertex3f = NULL;
562 Mem_Free(vertexupdate);
565 Mem_Free(vertexremap);
571 Mem_Free(shadowmark);
574 Mem_Free(shadowmarklist);
575 shadowmarklist = NULL;
580 Mem_Free(shadowsides);
583 Mem_Free(shadowsideslist);
584 shadowsideslist = NULL;
585 r_shadow_buffer_numleafpvsbytes = 0;
586 if (r_shadow_buffer_visitingleafpvs)
587 Mem_Free(r_shadow_buffer_visitingleafpvs);
588 r_shadow_buffer_visitingleafpvs = NULL;
589 if (r_shadow_buffer_leafpvs)
590 Mem_Free(r_shadow_buffer_leafpvs);
591 r_shadow_buffer_leafpvs = NULL;
592 if (r_shadow_buffer_leaflist)
593 Mem_Free(r_shadow_buffer_leaflist);
594 r_shadow_buffer_leaflist = NULL;
595 r_shadow_buffer_numsurfacepvsbytes = 0;
596 if (r_shadow_buffer_surfacepvs)
597 Mem_Free(r_shadow_buffer_surfacepvs);
598 r_shadow_buffer_surfacepvs = NULL;
599 if (r_shadow_buffer_surfacelist)
600 Mem_Free(r_shadow_buffer_surfacelist);
601 r_shadow_buffer_surfacelist = NULL;
602 if (r_shadow_buffer_surfacesides)
603 Mem_Free(r_shadow_buffer_surfacesides);
604 r_shadow_buffer_surfacesides = NULL;
605 r_shadow_buffer_numshadowtrispvsbytes = 0;
606 if (r_shadow_buffer_shadowtrispvs)
607 Mem_Free(r_shadow_buffer_shadowtrispvs);
608 r_shadow_buffer_numlighttrispvsbytes = 0;
609 if (r_shadow_buffer_lighttrispvs)
610 Mem_Free(r_shadow_buffer_lighttrispvs);
613 void r_shadow_newmap(void)
615 if (r_shadow_lightcorona) R_SkinFrame_MarkUsed(r_shadow_lightcorona);
616 if (r_editlights_sprcursor) R_SkinFrame_MarkUsed(r_editlights_sprcursor);
617 if (r_editlights_sprlight) R_SkinFrame_MarkUsed(r_editlights_sprlight);
618 if (r_editlights_sprnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprnoshadowlight);
619 if (r_editlights_sprcubemaplight) R_SkinFrame_MarkUsed(r_editlights_sprcubemaplight);
620 if (r_editlights_sprcubemapnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprcubemapnoshadowlight);
621 if (r_editlights_sprselection) R_SkinFrame_MarkUsed(r_editlights_sprselection);
622 if (strncmp(cl.worldname, r_shadow_mapname, sizeof(r_shadow_mapname)))
623 R_Shadow_EditLights_Reload_f();
626 void R_Shadow_Init(void)
628 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
629 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
630 Cvar_RegisterVariable(&r_shadow_usebihculling);
631 Cvar_RegisterVariable(&r_shadow_usenormalmap);
632 Cvar_RegisterVariable(&r_shadow_debuglight);
633 Cvar_RegisterVariable(&r_shadow_deferred);
634 Cvar_RegisterVariable(&r_shadow_deferred_8bitrange);
635 // Cvar_RegisterVariable(&r_shadow_deferred_fp);
636 Cvar_RegisterVariable(&r_shadow_gloss);
637 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
638 Cvar_RegisterVariable(&r_shadow_glossintensity);
639 Cvar_RegisterVariable(&r_shadow_glossexponent);
640 Cvar_RegisterVariable(&r_shadow_gloss2exponent);
641 Cvar_RegisterVariable(&r_shadow_glossexact);
642 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
643 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
644 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
645 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
646 Cvar_RegisterVariable(&r_shadow_projectdistance);
647 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
648 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
649 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
650 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
651 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
652 Cvar_RegisterVariable(&r_shadow_realtime_world);
653 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
654 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
655 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
656 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
657 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
658 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
659 Cvar_RegisterVariable(&r_shadow_scissor);
660 Cvar_RegisterVariable(&r_shadow_shadowmapping);
661 Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
662 Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
663 Cvar_RegisterVariable(&r_shadow_shadowmapping_depthbits);
664 Cvar_RegisterVariable(&r_shadow_shadowmapping_precision);
665 Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
666 Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
667 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
668 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
669 Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
670 Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
671 Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
672 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonfactor);
673 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonoffset);
674 Cvar_RegisterVariable(&r_shadow_sortsurfaces);
675 Cvar_RegisterVariable(&r_shadow_polygonfactor);
676 Cvar_RegisterVariable(&r_shadow_polygonoffset);
677 Cvar_RegisterVariable(&r_shadow_texture3d);
678 Cvar_RegisterVariable(&r_coronas);
679 Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
680 Cvar_RegisterVariable(&r_coronas_occlusionquery);
681 Cvar_RegisterVariable(&gl_flashblend);
682 Cvar_RegisterVariable(&gl_ext_separatestencil);
683 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
684 if (gamemode == GAME_TENEBRAE)
686 Cvar_SetValue("r_shadow_gloss", 2);
687 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
689 R_Shadow_EditLights_Init();
690 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
691 maxshadowtriangles = 0;
692 shadowelements = NULL;
693 maxshadowvertices = 0;
694 shadowvertex3f = NULL;
702 shadowmarklist = NULL;
707 shadowsideslist = NULL;
708 r_shadow_buffer_numleafpvsbytes = 0;
709 r_shadow_buffer_visitingleafpvs = NULL;
710 r_shadow_buffer_leafpvs = NULL;
711 r_shadow_buffer_leaflist = NULL;
712 r_shadow_buffer_numsurfacepvsbytes = 0;
713 r_shadow_buffer_surfacepvs = NULL;
714 r_shadow_buffer_surfacelist = NULL;
715 r_shadow_buffer_surfacesides = NULL;
716 r_shadow_buffer_shadowtrispvs = NULL;
717 r_shadow_buffer_lighttrispvs = NULL;
718 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap, NULL, NULL);
721 matrix4x4_t matrix_attenuationxyz =
724 {0.5, 0.0, 0.0, 0.5},
725 {0.0, 0.5, 0.0, 0.5},
726 {0.0, 0.0, 0.5, 0.5},
731 matrix4x4_t matrix_attenuationz =
734 {0.0, 0.0, 0.5, 0.5},
735 {0.0, 0.0, 0.0, 0.5},
736 {0.0, 0.0, 0.0, 0.5},
741 void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles, int vertscale, int triscale)
743 numvertices = ((numvertices + 255) & ~255) * vertscale;
744 numtriangles = ((numtriangles + 255) & ~255) * triscale;
745 // make sure shadowelements is big enough for this volume
746 if (maxshadowtriangles < numtriangles)
748 maxshadowtriangles = numtriangles;
750 Mem_Free(shadowelements);
751 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[3]));
753 // make sure shadowvertex3f is big enough for this volume
754 if (maxshadowvertices < numvertices)
756 maxshadowvertices = numvertices;
758 Mem_Free(shadowvertex3f);
759 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[3]));
763 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
765 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
766 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
767 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
768 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
769 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
771 if (r_shadow_buffer_visitingleafpvs)
772 Mem_Free(r_shadow_buffer_visitingleafpvs);
773 if (r_shadow_buffer_leafpvs)
774 Mem_Free(r_shadow_buffer_leafpvs);
775 if (r_shadow_buffer_leaflist)
776 Mem_Free(r_shadow_buffer_leaflist);
777 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
778 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
779 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
780 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
782 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
784 if (r_shadow_buffer_surfacepvs)
785 Mem_Free(r_shadow_buffer_surfacepvs);
786 if (r_shadow_buffer_surfacelist)
787 Mem_Free(r_shadow_buffer_surfacelist);
788 if (r_shadow_buffer_surfacesides)
789 Mem_Free(r_shadow_buffer_surfacesides);
790 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
791 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
792 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
793 r_shadow_buffer_surfacesides = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
795 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
797 if (r_shadow_buffer_shadowtrispvs)
798 Mem_Free(r_shadow_buffer_shadowtrispvs);
799 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
800 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
802 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
804 if (r_shadow_buffer_lighttrispvs)
805 Mem_Free(r_shadow_buffer_lighttrispvs);
806 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
807 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
811 void R_Shadow_PrepareShadowMark(int numtris)
813 // make sure shadowmark is big enough for this volume
814 if (maxshadowmark < numtris)
816 maxshadowmark = numtris;
818 Mem_Free(shadowmark);
820 Mem_Free(shadowmarklist);
821 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
822 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
826 // if shadowmarkcount wrapped we clear the array and adjust accordingly
827 if (shadowmarkcount == 0)
830 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
835 void R_Shadow_PrepareShadowSides(int numtris)
837 if (maxshadowsides < numtris)
839 maxshadowsides = numtris;
841 Mem_Free(shadowsides);
843 Mem_Free(shadowsideslist);
844 shadowsides = (unsigned char *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsides));
845 shadowsideslist = (int *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsideslist));
850 static int R_Shadow_ConstructShadowVolume_ZFail(int innumvertices, int innumtris, const int *inelement3i, const int *inneighbor3i, const float *invertex3f, int *outnumvertices, int *outelement3i, float *outvertex3f, const float *projectorigin, const float *projectdirection, float projectdistance, int numshadowmarktris, const int *shadowmarktris)
853 int outtriangles = 0, outvertices = 0;
856 float ratio, direction[3], projectvector[3];
858 if (projectdirection)
859 VectorScale(projectdirection, projectdistance, projectvector);
861 VectorClear(projectvector);
863 // create the vertices
864 if (projectdirection)
866 for (i = 0;i < numshadowmarktris;i++)
868 element = inelement3i + shadowmarktris[i] * 3;
869 for (j = 0;j < 3;j++)
871 if (vertexupdate[element[j]] != vertexupdatenum)
873 vertexupdate[element[j]] = vertexupdatenum;
874 vertexremap[element[j]] = outvertices;
875 vertex = invertex3f + element[j] * 3;
876 // project one copy of the vertex according to projectvector
877 VectorCopy(vertex, outvertex3f);
878 VectorAdd(vertex, projectvector, (outvertex3f + 3));
887 for (i = 0;i < numshadowmarktris;i++)
889 element = inelement3i + shadowmarktris[i] * 3;
890 for (j = 0;j < 3;j++)
892 if (vertexupdate[element[j]] != vertexupdatenum)
894 vertexupdate[element[j]] = vertexupdatenum;
895 vertexremap[element[j]] = outvertices;
896 vertex = invertex3f + element[j] * 3;
897 // project one copy of the vertex to the sphere radius of the light
898 // (FIXME: would projecting it to the light box be better?)
899 VectorSubtract(vertex, projectorigin, direction);
900 ratio = projectdistance / VectorLength(direction);
901 VectorCopy(vertex, outvertex3f);
902 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
910 if (r_shadow_frontsidecasting.integer)
912 for (i = 0;i < numshadowmarktris;i++)
914 int remappedelement[3];
916 const int *neighbortriangle;
918 markindex = shadowmarktris[i] * 3;
919 element = inelement3i + markindex;
920 neighbortriangle = inneighbor3i + markindex;
921 // output the front and back triangles
922 outelement3i[0] = vertexremap[element[0]];
923 outelement3i[1] = vertexremap[element[1]];
924 outelement3i[2] = vertexremap[element[2]];
925 outelement3i[3] = vertexremap[element[2]] + 1;
926 outelement3i[4] = vertexremap[element[1]] + 1;
927 outelement3i[5] = vertexremap[element[0]] + 1;
931 // output the sides (facing outward from this triangle)
932 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
934 remappedelement[0] = vertexremap[element[0]];
935 remappedelement[1] = vertexremap[element[1]];
936 outelement3i[0] = remappedelement[1];
937 outelement3i[1] = remappedelement[0];
938 outelement3i[2] = remappedelement[0] + 1;
939 outelement3i[3] = remappedelement[1];
940 outelement3i[4] = remappedelement[0] + 1;
941 outelement3i[5] = remappedelement[1] + 1;
946 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
948 remappedelement[1] = vertexremap[element[1]];
949 remappedelement[2] = vertexremap[element[2]];
950 outelement3i[0] = remappedelement[2];
951 outelement3i[1] = remappedelement[1];
952 outelement3i[2] = remappedelement[1] + 1;
953 outelement3i[3] = remappedelement[2];
954 outelement3i[4] = remappedelement[1] + 1;
955 outelement3i[5] = remappedelement[2] + 1;
960 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
962 remappedelement[0] = vertexremap[element[0]];
963 remappedelement[2] = vertexremap[element[2]];
964 outelement3i[0] = remappedelement[0];
965 outelement3i[1] = remappedelement[2];
966 outelement3i[2] = remappedelement[2] + 1;
967 outelement3i[3] = remappedelement[0];
968 outelement3i[4] = remappedelement[2] + 1;
969 outelement3i[5] = remappedelement[0] + 1;
978 for (i = 0;i < numshadowmarktris;i++)
980 int remappedelement[3];
982 const int *neighbortriangle;
984 markindex = shadowmarktris[i] * 3;
985 element = inelement3i + markindex;
986 neighbortriangle = inneighbor3i + markindex;
987 // output the front and back triangles
988 outelement3i[0] = vertexremap[element[2]];
989 outelement3i[1] = vertexremap[element[1]];
990 outelement3i[2] = vertexremap[element[0]];
991 outelement3i[3] = vertexremap[element[0]] + 1;
992 outelement3i[4] = vertexremap[element[1]] + 1;
993 outelement3i[5] = vertexremap[element[2]] + 1;
997 // output the sides (facing outward from this triangle)
998 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
1000 remappedelement[0] = vertexremap[element[0]];
1001 remappedelement[1] = vertexremap[element[1]];
1002 outelement3i[0] = remappedelement[0];
1003 outelement3i[1] = remappedelement[1];
1004 outelement3i[2] = remappedelement[1] + 1;
1005 outelement3i[3] = remappedelement[0];
1006 outelement3i[4] = remappedelement[1] + 1;
1007 outelement3i[5] = remappedelement[0] + 1;
1012 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1014 remappedelement[1] = vertexremap[element[1]];
1015 remappedelement[2] = vertexremap[element[2]];
1016 outelement3i[0] = remappedelement[1];
1017 outelement3i[1] = remappedelement[2];
1018 outelement3i[2] = remappedelement[2] + 1;
1019 outelement3i[3] = remappedelement[1];
1020 outelement3i[4] = remappedelement[2] + 1;
1021 outelement3i[5] = remappedelement[1] + 1;
1026 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1028 remappedelement[0] = vertexremap[element[0]];
1029 remappedelement[2] = vertexremap[element[2]];
1030 outelement3i[0] = remappedelement[2];
1031 outelement3i[1] = remappedelement[0];
1032 outelement3i[2] = remappedelement[0] + 1;
1033 outelement3i[3] = remappedelement[2];
1034 outelement3i[4] = remappedelement[0] + 1;
1035 outelement3i[5] = remappedelement[2] + 1;
1043 *outnumvertices = outvertices;
1044 return outtriangles;
1047 static int R_Shadow_ConstructShadowVolume_ZPass(int innumvertices, int innumtris, const int *inelement3i, const int *inneighbor3i, const float *invertex3f, int *outnumvertices, int *outelement3i, float *outvertex3f, const float *projectorigin, const float *projectdirection, float projectdistance, int numshadowmarktris, const int *shadowmarktris)
1050 int outtriangles = 0, outvertices = 0;
1052 const float *vertex;
1053 float ratio, direction[3], projectvector[3];
1056 if (projectdirection)
1057 VectorScale(projectdirection, projectdistance, projectvector);
1059 VectorClear(projectvector);
1061 for (i = 0;i < numshadowmarktris;i++)
1063 int remappedelement[3];
1065 const int *neighbortriangle;
1067 markindex = shadowmarktris[i] * 3;
1068 neighbortriangle = inneighbor3i + markindex;
1069 side[0] = shadowmark[neighbortriangle[0]] == shadowmarkcount;
1070 side[1] = shadowmark[neighbortriangle[1]] == shadowmarkcount;
1071 side[2] = shadowmark[neighbortriangle[2]] == shadowmarkcount;
1072 if (side[0] + side[1] + side[2] == 0)
1076 element = inelement3i + markindex;
1078 // create the vertices
1079 for (j = 0;j < 3;j++)
1081 if (side[j] + side[j+1] == 0)
1084 if (vertexupdate[k] != vertexupdatenum)
1086 vertexupdate[k] = vertexupdatenum;
1087 vertexremap[k] = outvertices;
1088 vertex = invertex3f + k * 3;
1089 VectorCopy(vertex, outvertex3f);
1090 if (projectdirection)
1092 // project one copy of the vertex according to projectvector
1093 VectorAdd(vertex, projectvector, (outvertex3f + 3));
1097 // project one copy of the vertex to the sphere radius of the light
1098 // (FIXME: would projecting it to the light box be better?)
1099 VectorSubtract(vertex, projectorigin, direction);
1100 ratio = projectdistance / VectorLength(direction);
1101 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1108 // output the sides (facing outward from this triangle)
1111 remappedelement[0] = vertexremap[element[0]];
1112 remappedelement[1] = vertexremap[element[1]];
1113 outelement3i[0] = remappedelement[1];
1114 outelement3i[1] = remappedelement[0];
1115 outelement3i[2] = remappedelement[0] + 1;
1116 outelement3i[3] = remappedelement[1];
1117 outelement3i[4] = remappedelement[0] + 1;
1118 outelement3i[5] = remappedelement[1] + 1;
1125 remappedelement[1] = vertexremap[element[1]];
1126 remappedelement[2] = vertexremap[element[2]];
1127 outelement3i[0] = remappedelement[2];
1128 outelement3i[1] = remappedelement[1];
1129 outelement3i[2] = remappedelement[1] + 1;
1130 outelement3i[3] = remappedelement[2];
1131 outelement3i[4] = remappedelement[1] + 1;
1132 outelement3i[5] = remappedelement[2] + 1;
1139 remappedelement[0] = vertexremap[element[0]];
1140 remappedelement[2] = vertexremap[element[2]];
1141 outelement3i[0] = remappedelement[0];
1142 outelement3i[1] = remappedelement[2];
1143 outelement3i[2] = remappedelement[2] + 1;
1144 outelement3i[3] = remappedelement[0];
1145 outelement3i[4] = remappedelement[2] + 1;
1146 outelement3i[5] = remappedelement[0] + 1;
1153 *outnumvertices = outvertices;
1154 return outtriangles;
1157 void R_Shadow_MarkVolumeFromBox(int firsttriangle, int numtris, const float *invertex3f, const int *elements, const vec3_t projectorigin, const vec3_t projectdirection, const vec3_t lightmins, const vec3_t lightmaxs, const vec3_t surfacemins, const vec3_t surfacemaxs)
1163 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1165 tend = firsttriangle + numtris;
1166 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1168 // surface box entirely inside light box, no box cull
1169 if (projectdirection)
1171 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1173 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
1174 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1175 shadowmarklist[numshadowmark++] = t;
1180 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1181 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
1182 shadowmarklist[numshadowmark++] = t;
1187 // surface box not entirely inside light box, cull each triangle
1188 if (projectdirection)
1190 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1192 v[0] = invertex3f + e[0] * 3;
1193 v[1] = invertex3f + e[1] * 3;
1194 v[2] = invertex3f + e[2] * 3;
1195 TriangleNormal(v[0], v[1], v[2], normal);
1196 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1197 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1198 shadowmarklist[numshadowmark++] = t;
1203 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1205 v[0] = invertex3f + e[0] * 3;
1206 v[1] = invertex3f + e[1] * 3;
1207 v[2] = invertex3f + e[2] * 3;
1208 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1209 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1210 shadowmarklist[numshadowmark++] = t;
1216 qboolean R_Shadow_UseZPass(vec3_t mins, vec3_t maxs)
1221 if (r_shadow_compilingrtlight || !r_shadow_frontsidecasting.integer || !r_shadow_usezpassifpossible.integer)
1223 // check if the shadow volume intersects the near plane
1225 // a ray between the eye and light origin may intersect the caster,
1226 // indicating that the shadow may touch the eye location, however we must
1227 // test the near plane (a polygon), not merely the eye location, so it is
1228 // easiest to enlarge the caster bounding shape slightly for this.
1234 void R_Shadow_VolumeFromList(int numverts, int numtris, const float *invertex3f, const int *elements, const int *neighbors, const vec3_t projectorigin, const vec3_t projectdirection, float projectdistance, int nummarktris, const int *marktris, vec3_t trismins, vec3_t trismaxs)
1236 int i, tris, outverts;
1237 if (projectdistance < 0.1)
1239 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
1242 if (!numverts || !nummarktris)
1244 // make sure shadowelements is big enough for this volume
1245 if (maxshadowtriangles < nummarktris*8 || maxshadowvertices < numverts*2)
1246 R_Shadow_ResizeShadowArrays(numverts, nummarktris, 2, 8);
1248 if (maxvertexupdate < numverts)
1250 maxvertexupdate = numverts;
1252 Mem_Free(vertexupdate);
1254 Mem_Free(vertexremap);
1255 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1256 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1257 vertexupdatenum = 0;
1260 if (vertexupdatenum == 0)
1262 vertexupdatenum = 1;
1263 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
1264 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
1267 for (i = 0;i < nummarktris;i++)
1268 shadowmark[marktris[i]] = shadowmarkcount;
1270 if (r_shadow_compilingrtlight)
1272 // if we're compiling an rtlight, capture the mesh
1273 //tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1274 //Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zpass, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1275 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1276 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zfail, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1278 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
1280 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1281 R_Mesh_PrepareVertices_Position_Arrays(outverts, shadowvertex3f);
1282 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1286 // decide which type of shadow to generate and set stencil mode
1287 R_Shadow_RenderMode_StencilShadowVolumes(R_Shadow_UseZPass(trismins, trismaxs));
1288 // generate the sides or a solid volume, depending on type
1289 if (r_shadow_rendermode >= R_SHADOW_RENDERMODE_ZPASS_STENCIL && r_shadow_rendermode <= R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE)
1290 tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1292 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1293 r_refdef.stats.lights_dynamicshadowtriangles += tris;
1294 r_refdef.stats.lights_shadowtriangles += tris;
1295 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
1297 // increment stencil if frontface is infront of depthbuffer
1298 GL_CullFace(r_refdef.view.cullface_front);
1299 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
1300 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1301 // decrement stencil if backface is infront of depthbuffer
1302 GL_CullFace(r_refdef.view.cullface_back);
1303 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
1305 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
1307 // decrement stencil if backface is behind depthbuffer
1308 GL_CullFace(r_refdef.view.cullface_front);
1309 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
1310 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1311 // increment stencil if frontface is behind depthbuffer
1312 GL_CullFace(r_refdef.view.cullface_back);
1313 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
1315 R_Mesh_PrepareVertices_Position_Arrays(outverts, shadowvertex3f);
1316 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1320 int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias)
1322 // p1, p2, p3 are in the cubemap's local coordinate system
1323 // bias = border/(size - border)
1326 float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1327 dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2),
1328 dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3);
1329 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1331 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1332 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1333 | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1334 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1336 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1337 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1338 | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1340 dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1341 dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2),
1342 dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3);
1343 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1345 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1346 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1347 | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1348 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1350 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1351 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1352 | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1354 dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1355 dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2),
1356 dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3);
1357 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1359 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1360 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1361 | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1362 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1364 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1365 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1366 | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1371 int R_Shadow_CalcBBoxSideMask(const vec3_t mins, const vec3_t maxs, const matrix4x4_t *worldtolight, const matrix4x4_t *radiustolight, float bias)
1373 vec3_t center, radius, lightcenter, lightradius, pmin, pmax;
1374 float dp1, dn1, ap1, an1, dp2, dn2, ap2, an2;
1377 VectorSubtract(maxs, mins, radius);
1378 VectorScale(radius, 0.5f, radius);
1379 VectorAdd(mins, radius, center);
1380 Matrix4x4_Transform(worldtolight, center, lightcenter);
1381 Matrix4x4_Transform3x3(radiustolight, radius, lightradius);
1382 VectorSubtract(lightcenter, lightradius, pmin);
1383 VectorAdd(lightcenter, lightradius, pmax);
1385 dp1 = pmax[0] + pmax[1], dn1 = pmax[0] - pmin[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1386 dp2 = pmin[0] + pmin[1], dn2 = pmin[0] - pmax[1], ap2 = fabs(dp2), an2 = fabs(dn2);
1387 if(ap1 > bias*an1 && ap2 > bias*an2)
1389 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1390 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1391 if(an1 > bias*ap1 && an2 > bias*ap2)
1393 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1394 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1396 dp1 = pmax[1] + pmax[2], dn1 = pmax[1] - pmin[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1397 dp2 = pmin[1] + pmin[2], dn2 = pmin[1] - pmax[2], ap2 = fabs(dp2), an2 = fabs(dn2);
1398 if(ap1 > bias*an1 && ap2 > bias*an2)
1400 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1401 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1402 if(an1 > bias*ap1 && an2 > bias*ap2)
1404 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1405 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1407 dp1 = pmax[2] + pmax[0], dn1 = pmax[2] - pmin[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1408 dp2 = pmin[2] + pmin[0], dn2 = pmin[2] - pmax[0], ap2 = fabs(dp2), an2 = fabs(dn2);
1409 if(ap1 > bias*an1 && ap2 > bias*an2)
1411 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1412 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1413 if(an1 > bias*ap1 && an2 > bias*ap2)
1415 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1416 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1421 #define R_Shadow_CalcEntitySideMask(ent, worldtolight, radiustolight, bias) R_Shadow_CalcBBoxSideMask((ent)->mins, (ent)->maxs, worldtolight, radiustolight, bias)
1423 int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
1425 // p is in the cubemap's local coordinate system
1426 // bias = border/(size - border)
1427 float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn);
1428 float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn);
1429 float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn);
1431 if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
1432 if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
1433 if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
1434 if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
1435 if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
1436 if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
1440 int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
1444 int sides = 0x3F, masks[6] = { 3<<4, 3<<4, 3<<0, 3<<0, 3<<2, 3<<2 };
1445 float scale = (size - 2*border)/size, len;
1446 float bias = border / (float)(size - border), dp, dn, ap, an;
1447 // check if cone enclosing side would cross frustum plane
1448 scale = 2 / (scale*scale + 2);
1449 for (i = 0;i < 5;i++)
1451 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) > -0.03125)
1453 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[i].normal, n);
1454 len = scale*VectorLength2(n);
1455 if(n[0]*n[0] > len) sides &= n[0] < 0 ? ~(1<<0) : ~(2 << 0);
1456 if(n[1]*n[1] > len) sides &= n[1] < 0 ? ~(1<<2) : ~(2 << 2);
1457 if(n[2]*n[2] > len) sides &= n[2] < 0 ? ~(1<<4) : ~(2 << 4);
1459 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[4]) >= r_refdef.farclip - r_refdef.nearclip + 0.03125)
1461 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[4].normal, n);
1462 len = scale*VectorLength(n);
1463 if(n[0]*n[0] > len) sides &= n[0] >= 0 ? ~(1<<0) : ~(2 << 0);
1464 if(n[1]*n[1] > len) sides &= n[1] >= 0 ? ~(1<<2) : ~(2 << 2);
1465 if(n[2]*n[2] > len) sides &= n[2] >= 0 ? ~(1<<4) : ~(2 << 4);
1467 // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results
1468 // check if frustum corners/origin cross plane sides
1470 // infinite version, assumes frustum corners merely give direction and extend to infinite distance
1471 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.origin, p);
1472 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1473 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1474 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1475 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1476 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1477 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1478 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1479 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1480 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1481 for (i = 0;i < 4;i++)
1483 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.frustumcorner[i], n);
1484 VectorSubtract(n, p, n);
1485 dp = n[0] + n[1], dn = n[0] - n[1], ap = fabs(dp), an = fabs(dn);
1486 if(ap > 0) masks[0] |= dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2);
1487 if(an > 0) masks[1] |= dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2);
1488 dp = n[1] + n[2], dn = n[1] - n[2], ap = fabs(dp), an = fabs(dn);
1489 if(ap > 0) masks[2] |= dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4);
1490 if(an > 0) masks[3] |= dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4);
1491 dp = n[2] + n[0], dn = n[2] - n[0], ap = fabs(dp), an = fabs(dn);
1492 if(ap > 0) masks[4] |= dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0);
1493 if(an > 0) masks[5] |= dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0);
1496 // finite version, assumes corners are a finite distance from origin dependent on far plane
1497 for (i = 0;i < 5;i++)
1499 Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p);
1500 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1501 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1502 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1503 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1504 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1505 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1506 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1507 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1508 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1511 return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5];
1514 int R_Shadow_ChooseSidesFromBox(int firsttriangle, int numtris, const float *invertex3f, const int *elements, const matrix4x4_t *worldtolight, const vec3_t projectorigin, const vec3_t projectdirection, const vec3_t lightmins, const vec3_t lightmaxs, const vec3_t surfacemins, const vec3_t surfacemaxs, int *totals)
1522 int mask, surfacemask = 0;
1523 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1525 bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
1526 tend = firsttriangle + numtris;
1527 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1529 // surface box entirely inside light box, no box cull
1530 if (projectdirection)
1532 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1534 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1535 TriangleNormal(v[0], v[1], v[2], normal);
1536 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1538 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1539 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1540 surfacemask |= mask;
1543 totals[0] += mask&1, totals[1] += (mask>>1)&1, totals[2] += (mask>>2)&1, totals[3] += (mask>>3)&1, totals[4] += (mask>>4)&1, totals[5] += mask>>5;
1544 shadowsides[numshadowsides] = mask;
1545 shadowsideslist[numshadowsides++] = t;
1552 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1554 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1555 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]))
1557 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1558 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1559 surfacemask |= mask;
1562 totals[0] += mask&1, totals[1] += (mask>>1)&1, totals[2] += (mask>>2)&1, totals[3] += (mask>>3)&1, totals[4] += (mask>>4)&1, totals[5] += mask>>5;
1563 shadowsides[numshadowsides] = mask;
1564 shadowsideslist[numshadowsides++] = t;
1572 // surface box not entirely inside light box, cull each triangle
1573 if (projectdirection)
1575 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1577 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1578 TriangleNormal(v[0], v[1], v[2], normal);
1579 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1580 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1582 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1583 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1584 surfacemask |= mask;
1587 totals[0] += mask&1, totals[1] += (mask>>1)&1, totals[2] += (mask>>2)&1, totals[3] += (mask>>3)&1, totals[4] += (mask>>4)&1, totals[5] += mask>>5;
1588 shadowsides[numshadowsides] = mask;
1589 shadowsideslist[numshadowsides++] = t;
1596 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1598 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1599 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1600 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1602 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1603 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1604 surfacemask |= mask;
1607 totals[0] += mask&1, totals[1] += (mask>>1)&1, totals[2] += (mask>>2)&1, totals[3] += (mask>>3)&1, totals[4] += (mask>>4)&1, totals[5] += mask>>5;
1608 shadowsides[numshadowsides] = mask;
1609 shadowsideslist[numshadowsides++] = t;
1618 void R_Shadow_ShadowMapFromList(int numverts, int numtris, const float *vertex3f, const int *elements, int numsidetris, const int *sidetotals, const unsigned char *sides, const int *sidetris)
1620 int i, j, outtriangles = 0;
1621 int *outelement3i[6];
1622 if (!numverts || !numsidetris || !r_shadow_compilingrtlight)
1624 outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5];
1625 // make sure shadowelements is big enough for this mesh
1626 if (maxshadowtriangles < outtriangles)
1627 R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1);
1629 // compute the offset and size of the separate index lists for each cubemap side
1631 for (i = 0;i < 6;i++)
1633 outelement3i[i] = shadowelements + outtriangles * 3;
1634 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles;
1635 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i];
1636 outtriangles += sidetotals[i];
1639 // gather up the (sparse) triangles into separate index lists for each cubemap side
1640 for (i = 0;i < numsidetris;i++)
1642 const int *element = elements + sidetris[i] * 3;
1643 for (j = 0;j < 6;j++)
1645 if (sides[i] & (1 << j))
1647 outelement3i[j][0] = element[0];
1648 outelement3i[j][1] = element[1];
1649 outelement3i[j][2] = element[2];
1650 outelement3i[j] += 3;
1655 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, outtriangles, shadowelements);
1658 static void R_Shadow_MakeTextures_MakeCorona(void)
1662 unsigned char pixels[32][32][4];
1663 for (y = 0;y < 32;y++)
1665 dy = (y - 15.5f) * (1.0f / 16.0f);
1666 for (x = 0;x < 32;x++)
1668 dx = (x - 15.5f) * (1.0f / 16.0f);
1669 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1670 a = bound(0, a, 255);
1671 pixels[y][x][0] = a;
1672 pixels[y][x][1] = a;
1673 pixels[y][x][2] = a;
1674 pixels[y][x][3] = 255;
1677 r_shadow_lightcorona = R_SkinFrame_LoadInternalBGRA("lightcorona", TEXF_FORCELINEAR, &pixels[0][0][0], 32, 32);
1680 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1682 float dist = sqrt(x*x+y*y+z*z);
1683 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1684 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1685 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1688 static void R_Shadow_MakeTextures(void)
1691 float intensity, dist;
1693 R_Shadow_FreeShadowMaps();
1694 R_FreeTexturePool(&r_shadow_texturepool);
1695 r_shadow_texturepool = R_AllocTexturePool();
1696 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1697 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1698 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1699 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1700 for (x = 0;x <= ATTENTABLESIZE;x++)
1702 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1703 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1704 r_shadow_attentable[x] = bound(0, intensity, 1);
1706 // 1D gradient texture
1707 for (x = 0;x < ATTEN1DSIZE;x++)
1708 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1709 r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1710 // 2D circle texture
1711 for (y = 0;y < ATTEN2DSIZE;y++)
1712 for (x = 0;x < ATTEN2DSIZE;x++)
1713 data[y*ATTEN2DSIZE+x] = R_Shadow_MakeTextures_SamplePoint(((x + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375), ((y + 0.5f) * (2.0f / ATTEN2DSIZE) - 1.0f) * (1.0f / 0.9375), 0);
1714 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1715 // 3D sphere texture
1716 if (r_shadow_texture3d.integer && vid.support.ext_texture_3d)
1718 for (z = 0;z < ATTEN3DSIZE;z++)
1719 for (y = 0;y < ATTEN3DSIZE;y++)
1720 for (x = 0;x < ATTEN3DSIZE;x++)
1721 data[(z*ATTEN3DSIZE+y)*ATTEN3DSIZE+x] = R_Shadow_MakeTextures_SamplePoint(((x + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375), ((y + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375), ((z + 0.5f) * (2.0f / ATTEN3DSIZE) - 1.0f) * (1.0f / 0.9375));
1722 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1725 r_shadow_attenuation3dtexture = NULL;
1728 R_Shadow_MakeTextures_MakeCorona();
1730 // Editor light sprites
1731 r_editlights_sprcursor = R_SkinFrame_LoadInternal8bit("gfx/editlights/cursor", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1748 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1749 r_editlights_sprlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/light", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1766 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1767 r_editlights_sprnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/noshadow", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1784 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1785 r_editlights_sprcubemaplight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemaplight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1802 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1803 r_editlights_sprcubemapnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemapnoshadowlight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1820 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1821 r_editlights_sprselection = R_SkinFrame_LoadInternal8bit("gfx/editlights/selection", TEXF_ALPHA | TEXF_CLAMP, (unsigned char *)
1838 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1841 void R_Shadow_ValidateCvars(void)
1843 if (r_shadow_texture3d.integer && !vid.support.ext_texture_3d)
1844 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1845 if (gl_ext_separatestencil.integer && !vid.support.ati_separate_stencil)
1846 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
1847 if (gl_ext_stenciltwoside.integer && !vid.support.ext_stencil_two_side)
1848 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1851 //static const r_vertexposition_t resetvertexposition[3] = {{0, 0, 0}};
1853 void R_Shadow_RenderMode_Begin(void)
1859 R_Shadow_ValidateCvars();
1861 if (!r_shadow_attenuation2dtexture
1862 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1863 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1864 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1865 R_Shadow_MakeTextures();
1868 R_Mesh_ResetTextureState();
1869 // R_Mesh_PrepareVertices_Position(0, resetvertexposition, NULL);
1870 GL_BlendFunc(GL_ONE, GL_ZERO);
1871 GL_DepthRange(0, 1);
1872 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1874 GL_DepthMask(false);
1875 GL_Color(0, 0, 0, 1);
1876 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1878 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1880 if (gl_ext_separatestencil.integer && vid.support.ati_separate_stencil)
1882 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
1883 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
1885 else if (gl_ext_stenciltwoside.integer && vid.support.ext_stencil_two_side)
1887 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
1888 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
1892 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
1893 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
1896 switch(vid.renderpath)
1898 case RENDERPATH_GL20:
1899 case RENDERPATH_CGGL:
1900 case RENDERPATH_D3D9:
1901 case RENDERPATH_D3D10:
1902 case RENDERPATH_D3D11:
1903 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1905 case RENDERPATH_GL13:
1906 case RENDERPATH_GL11:
1907 if (r_textureunits.integer >= 2 && vid.texunits >= 2 && r_shadow_texture3d.integer && r_shadow_attenuation3dtexture)
1908 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN;
1909 else if (r_textureunits.integer >= 3 && vid.texunits >= 3)
1910 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN;
1911 else if (r_textureunits.integer >= 2 && vid.texunits >= 2)
1912 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN;
1914 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1920 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
1921 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
1922 r_shadow_drawbuffer = drawbuffer;
1923 r_shadow_readbuffer = readbuffer;
1925 r_shadow_cullface_front = r_refdef.view.cullface_front;
1926 r_shadow_cullface_back = r_refdef.view.cullface_back;
1929 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
1931 rsurface.rtlight = rtlight;
1934 void R_Shadow_RenderMode_Reset(void)
1936 R_Mesh_ResetRenderTargets();
1937 R_SetViewport(&r_refdef.view.viewport);
1938 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
1939 R_Mesh_ResetTextureState();
1940 // R_Mesh_PrepareVertices_Position(0, resetvertexposition, NULL);
1941 GL_DepthRange(0, 1);
1943 GL_DepthMask(false);
1944 GL_DepthFunc(GL_LEQUAL);
1945 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1946 r_refdef.view.cullface_front = r_shadow_cullface_front;
1947 r_refdef.view.cullface_back = r_shadow_cullface_back;
1948 GL_CullFace(r_refdef.view.cullface_back);
1949 GL_Color(1, 1, 1, 1);
1950 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
1951 GL_BlendFunc(GL_ONE, GL_ZERO);
1952 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
1953 r_shadow_usingshadowmap2d = false;
1954 r_shadow_usingshadowmaportho = false;
1955 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
1958 void R_Shadow_ClearStencil(void)
1960 GL_Clear(GL_STENCIL_BUFFER_BIT, NULL, 1.0f, 128);
1961 r_refdef.stats.lights_clears++;
1964 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
1966 r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
1967 if (r_shadow_rendermode == mode)
1969 R_Shadow_RenderMode_Reset();
1970 GL_DepthFunc(GL_LESS);
1971 GL_ColorMask(0, 0, 0, 0);
1972 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1973 GL_CullFace(GL_NONE);
1974 R_SetupShader_DepthOrShadow();
1975 r_shadow_rendermode = mode;
1980 case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
1981 case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
1982 R_SetStencilSeparate(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, GL_ALWAYS, 128, 255);
1984 case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
1985 case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
1986 R_SetStencilSeparate(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, GL_ALWAYS, 128, 255);
1991 static void R_Shadow_MakeVSDCT(void)
1993 // maps to a 2x3 texture rectangle with normalized coordinates
1998 // stores abs(dir.xy), offset.xy/2.5
1999 unsigned char data[4*6] =
2001 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
2002 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
2003 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
2004 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
2005 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
2006 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
2008 r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
2011 static void R_Shadow_MakeShadowMap(int side, int size)
2013 switch (r_shadow_shadowmode)
2015 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2016 if (r_shadow_shadowmap2dtexture) return;
2017 r_shadow_shadowmap2dtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "shadowmap", size*2, size*(vid.support.arb_texture_non_power_of_two ? 3 : 4), r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
2018 r_shadow_shadowmap2dcolortexture = NULL;
2019 switch(vid.renderpath)
2022 case RENDERPATH_D3D9:
2023 r_shadow_shadowmap2dcolortexture = R_LoadTexture2D(r_shadow_texturepool, "shadowmaprendertarget", size*2, size*(vid.support.arb_texture_non_power_of_two ? 3 : 4), NULL, TEXTYPE_BGRA, TEXF_RENDERTARGET | TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
2024 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
2028 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2dtexture, NULL, NULL, NULL, NULL);
2036 // render depth into the fbo, do not render color at all
2037 // validate the fbo now
2041 qglDrawBuffer(GL_NONE);CHECKGLERROR
2042 qglReadBuffer(GL_NONE);CHECKGLERROR
2043 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2044 if (status != GL_FRAMEBUFFER_COMPLETE_EXT && (r_shadow_shadowmapping.integer || r_shadow_deferred.integer))
2046 Con_Printf("R_Shadow_MakeShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2047 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2048 Cvar_SetValueQuick(&r_shadow_deferred, 0);
2053 void R_Shadow_RenderMode_ShadowMap(int side, int clear, int size)
2055 float nearclip, farclip, bias;
2056 r_viewport_t viewport;
2059 float clearcolor[4];
2060 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
2062 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
2063 r_shadow_shadowmap_parameters[1] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
2064 r_shadow_shadowmap_parameters[3] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
2065 r_shadow_shadowmapside = side;
2066 r_shadow_shadowmapsize = size;
2068 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2069 r_shadow_shadowmap_parameters[2] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2070 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
2071 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D) goto init_done;
2073 // complex unrolled cube approach (more flexible)
2074 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2075 R_Shadow_MakeVSDCT();
2076 if (!r_shadow_shadowmap2dtexture)
2077 R_Shadow_MakeShadowMap(side, r_shadow_shadowmapmaxsize);
2078 if (r_shadow_shadowmap2dtexture) fbo = r_shadow_fbo2d;
2079 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
2080 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
2081 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
2083 R_Mesh_ResetTextureState();
2084 R_Mesh_ResetRenderTargets();
2085 R_Shadow_RenderMode_Reset();
2088 R_Mesh_SetRenderTargets(fbo, r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
2089 R_SetupShader_DepthOrShadow();
2092 R_SetupShader_ShowDepth();
2093 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
2098 R_SetViewport(&viewport);
2099 flipped = (side & 1) ^ (side >> 2);
2100 r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
2101 r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
2102 switch(vid.renderpath)
2104 case RENDERPATH_GL11:
2105 case RENDERPATH_GL13:
2106 case RENDERPATH_GL20:
2107 case RENDERPATH_CGGL:
2108 GL_CullFace(r_refdef.view.cullface_back);
2109 // OpenGL lets us scissor larger than the viewport, so go ahead and clear all views at once
2110 if ((clear & ((2 << side) - 1)) == (1 << side)) // only clear if the side is the first in the mask
2112 // get tightest scissor rectangle that encloses all viewports in the clear mask
2113 int x1 = clear & 0x15 ? 0 : size;
2114 int x2 = clear & 0x2A ? 2 * size : size;
2115 int y1 = clear & 0x03 ? 0 : (clear & 0xC ? size : 2 * size);
2116 int y2 = clear & 0x30 ? 3 * size : (clear & 0xC ? 2 * size : size);
2117 GL_Scissor(x1, y1, x2 - x1, y2 - y1);
2118 GL_Clear(GL_DEPTH_BUFFER_BIT, NULL, 1.0f, 0);
2120 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2122 case RENDERPATH_D3D9:
2123 Vector4Set(clearcolor, 1,1,1,1);
2124 // completely different meaning than in OpenGL path
2125 r_shadow_shadowmap_parameters[1] = 0;
2126 r_shadow_shadowmap_parameters[3] = -bias;
2127 // we invert the cull mode because we flip the projection matrix
2128 // NOTE: this actually does nothing because the DrawShadowMap code sets it to doublesided...
2129 GL_CullFace(r_refdef.view.cullface_front);
2130 // D3D considers it an error to use a scissor larger than the viewport... clear just this view
2131 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2132 if (r_shadow_shadowmapsampler)
2134 GL_ColorMask(0,0,0,0);
2136 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
2140 GL_ColorMask(1,1,1,1);
2142 GL_Clear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
2145 case RENDERPATH_D3D10:
2146 case RENDERPATH_D3D11:
2147 // D3D considers it an error to use a scissor larger than the viewport... clear just this view
2148 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2149 GL_ColorMask(0,0,0,0);
2151 GL_Clear(GL_DEPTH_BUFFER_BIT, NULL, 1.0f, 0);
2156 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
2158 R_Mesh_ResetTextureState();
2159 R_Mesh_ResetRenderTargets();
2162 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2163 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2164 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2165 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2167 R_Shadow_RenderMode_Reset();
2168 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2170 GL_DepthFunc(GL_EQUAL);
2171 // do global setup needed for the chosen lighting mode
2172 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2173 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2174 r_shadow_usingshadowmap2d = shadowmapping;
2175 r_shadow_rendermode = r_shadow_lightingrendermode;
2176 // only draw light where this geometry was already rendered AND the
2177 // stencil is 128 (values other than this mean shadow)
2179 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2181 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
2184 static const unsigned short bboxelements[36] =
2194 static const float bboxpoints[8][3] =
2206 void R_Shadow_RenderMode_DrawDeferredLight(qboolean stenciltest, qboolean shadowmapping)
2209 float vertex3f[8*3];
2210 const matrix4x4_t *matrix = &rsurface.rtlight->matrix_lighttoworld;
2211 // do global setup needed for the chosen lighting mode
2212 R_Shadow_RenderMode_Reset();
2213 r_shadow_rendermode = r_shadow_lightingrendermode;
2214 R_EntityMatrix(&identitymatrix);
2215 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2216 // only draw light where this geometry was already rendered AND the
2217 // stencil is 128 (values other than this mean shadow)
2218 R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2219 R_Mesh_SetRenderTargets(r_shadow_prepasslightingfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
2221 r_shadow_usingshadowmap2d = shadowmapping;
2223 // render the lighting
2224 R_SetupShader_DeferredLight(rsurface.rtlight);
2225 for (i = 0;i < 8;i++)
2226 Matrix4x4_Transform(matrix, bboxpoints[i], vertex3f + i*3);
2227 GL_ColorMask(1,1,1,1);
2228 GL_DepthMask(false);
2229 GL_DepthRange(0, 1);
2230 GL_PolygonOffset(0, 0);
2232 GL_DepthFunc(GL_GREATER);
2233 GL_CullFace(r_refdef.view.cullface_back);
2234 R_Mesh_PrepareVertices_Position_Arrays(8, vertex3f);
2235 R_Mesh_Draw(0, 8, 0, 12, NULL, NULL, 0, bboxelements, NULL, 0);
2238 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
2240 R_Shadow_RenderMode_Reset();
2241 GL_BlendFunc(GL_ONE, GL_ONE);
2242 GL_DepthRange(0, 1);
2243 GL_DepthTest(r_showshadowvolumes.integer < 2);
2244 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
2245 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2246 GL_CullFace(GL_NONE);
2247 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
2250 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
2252 R_Shadow_RenderMode_Reset();
2253 GL_BlendFunc(GL_ONE, GL_ONE);
2254 GL_DepthRange(0, 1);
2255 GL_DepthTest(r_showlighting.integer < 2);
2256 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2258 GL_DepthFunc(GL_EQUAL);
2259 R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2260 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2263 void R_Shadow_RenderMode_End(void)
2265 R_Shadow_RenderMode_Reset();
2266 R_Shadow_RenderMode_ActiveLight(NULL);
2268 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2269 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2272 int bboxedges[12][2] =
2291 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2293 if (!r_shadow_scissor.integer)
2295 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2296 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2297 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2298 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2301 if(R_ScissorForBBox(mins, maxs, r_shadow_lightscissor))
2302 return true; // invisible
2303 if(r_shadow_lightscissor[0] != r_refdef.view.viewport.x
2304 || r_shadow_lightscissor[1] != r_refdef.view.viewport.y
2305 || r_shadow_lightscissor[2] != r_refdef.view.viewport.width
2306 || r_shadow_lightscissor[3] != r_refdef.view.viewport.height)
2307 r_refdef.stats.lights_scissored++;
2311 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, const float *diffusecolor, const float *ambientcolor)
2314 const float *vertex3f;
2315 const float *normal3f;
2317 float dist, dot, distintensity, shadeintensity, v[3], n[3];
2318 switch (r_shadow_rendermode)
2320 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2321 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2322 if (VectorLength2(diffusecolor) > 0)
2324 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, normal3f = rsurface.batchnormal3f + 3*firstvertex, color4f = rsurface.array_passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, normal3f += 3, color4f += 4)
2326 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2327 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2328 if ((dot = DotProduct(n, v)) < 0)
2330 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2331 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
2334 VectorCopy(ambientcolor, color4f);
2335 if (r_refdef.fogenabled)
2338 f = RSurf_FogVertex(vertex3f);
2339 VectorScale(color4f, f, color4f);
2346 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.array_passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
2348 VectorCopy(ambientcolor, color4f);
2349 if (r_refdef.fogenabled)
2352 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2353 f = RSurf_FogVertex(vertex3f);
2354 VectorScale(color4f + 4*i, f, color4f);
2360 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2361 if (VectorLength2(diffusecolor) > 0)
2363 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, normal3f = rsurface.batchnormal3f + 3*firstvertex, color4f = rsurface.array_passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, normal3f += 3, color4f += 4)
2365 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2366 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2368 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2369 if ((dot = DotProduct(n, v)) < 0)
2371 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2372 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2373 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2374 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2378 color4f[0] = ambientcolor[0] * distintensity;
2379 color4f[1] = ambientcolor[1] * distintensity;
2380 color4f[2] = ambientcolor[2] * distintensity;
2382 if (r_refdef.fogenabled)
2385 f = RSurf_FogVertex(vertex3f);
2386 VectorScale(color4f, f, color4f);
2390 VectorClear(color4f);
2396 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.array_passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
2398 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2399 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2401 color4f[0] = ambientcolor[0] * distintensity;
2402 color4f[1] = ambientcolor[1] * distintensity;
2403 color4f[2] = ambientcolor[2] * distintensity;
2404 if (r_refdef.fogenabled)
2407 f = RSurf_FogVertex(vertex3f);
2408 VectorScale(color4f, f, color4f);
2412 VectorClear(color4f);
2417 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2418 if (VectorLength2(diffusecolor) > 0)
2420 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, normal3f = rsurface.batchnormal3f + 3*firstvertex, color4f = rsurface.array_passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, normal3f += 3, color4f += 4)
2422 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2423 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2425 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2426 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2427 if ((dot = DotProduct(n, v)) < 0)
2429 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2430 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2431 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2432 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2436 color4f[0] = ambientcolor[0] * distintensity;
2437 color4f[1] = ambientcolor[1] * distintensity;
2438 color4f[2] = ambientcolor[2] * distintensity;
2440 if (r_refdef.fogenabled)
2443 f = RSurf_FogVertex(vertex3f);
2444 VectorScale(color4f, f, color4f);
2448 VectorClear(color4f);
2454 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.array_passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
2456 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2457 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2459 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2460 color4f[0] = ambientcolor[0] * distintensity;
2461 color4f[1] = ambientcolor[1] * distintensity;
2462 color4f[2] = ambientcolor[2] * distintensity;
2463 if (r_refdef.fogenabled)
2466 f = RSurf_FogVertex(vertex3f);
2467 VectorScale(color4f, f, color4f);
2471 VectorClear(color4f);
2481 static void R_Shadow_RenderLighting_VisibleLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
2483 // used to display how many times a surface is lit for level design purposes
2484 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
2485 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
2489 static void R_Shadow_RenderLighting_Light_GLSL(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale, float specularscale)
2491 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2492 R_SetupShader_Surface(lightcolor, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT, texturenumsurfaces, texturesurfacelist, NULL);
2493 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2494 GL_DepthFunc(GL_EQUAL);
2496 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2497 GL_DepthFunc(GL_LEQUAL);
2500 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
2507 int newnumtriangles;
2511 int maxtriangles = 4096;
2512 static int newelements[4096*3];
2513 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, diffusecolor2, ambientcolor2);
2514 for (renders = 0;renders < 4;renders++)
2519 newnumtriangles = 0;
2521 // due to low fillrate on the cards this vertex lighting path is
2522 // designed for, we manually cull all triangles that do not
2523 // contain a lit vertex
2524 // this builds batches of triangles from multiple surfaces and
2525 // renders them at once
2526 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
2528 if (VectorLength2(rsurface.array_passcolor4f + e[0] * 4) + VectorLength2(rsurface.array_passcolor4f + e[1] * 4) + VectorLength2(rsurface.array_passcolor4f + e[2] * 4) >= 0.01)
2530 if (newnumtriangles)
2532 newfirstvertex = min(newfirstvertex, e[0]);
2533 newlastvertex = max(newlastvertex, e[0]);
2537 newfirstvertex = e[0];
2538 newlastvertex = e[0];
2540 newfirstvertex = min(newfirstvertex, e[1]);
2541 newlastvertex = max(newlastvertex, e[1]);
2542 newfirstvertex = min(newfirstvertex, e[2]);
2543 newlastvertex = max(newlastvertex, e[2]);
2549 if (newnumtriangles >= maxtriangles)
2551 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
2552 newnumtriangles = 0;
2558 if (newnumtriangles >= 1)
2560 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
2563 // if we couldn't find any lit triangles, exit early
2566 // now reduce the intensity for the next overbright pass
2567 // we have to clamp to 0 here incase the drivers have improper
2568 // handling of negative colors
2569 // (some old drivers even have improper handling of >1 color)
2571 for (i = 0, c = rsurface.array_passcolor4f + 4 * firstvertex;i < numvertices;i++, c += 4)
2573 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
2575 c[0] = max(0, c[0] - 1);
2576 c[1] = max(0, c[1] - 1);
2577 c[2] = max(0, c[2] - 1);
2589 static void R_Shadow_RenderLighting_Light_Vertex(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale)
2591 // OpenGL 1.1 path (anything)
2592 float ambientcolorbase[3], diffusecolorbase[3];
2593 float ambientcolorpants[3], diffusecolorpants[3];
2594 float ambientcolorshirt[3], diffusecolorshirt[3];
2595 const float *surfacecolor = rsurface.texture->dlightcolor;
2596 const float *surfacepants = rsurface.colormap_pantscolor;
2597 const float *surfaceshirt = rsurface.colormap_shirtcolor;
2598 rtexture_t *basetexture = rsurface.texture->basetexture;
2599 rtexture_t *pantstexture = rsurface.texture->pantstexture;
2600 rtexture_t *shirttexture = rsurface.texture->shirttexture;
2601 qboolean dopants = pantstexture && VectorLength2(surfacepants) >= (1.0f / 1048576.0f);
2602 qboolean doshirt = shirttexture && VectorLength2(surfaceshirt) >= (1.0f / 1048576.0f);
2603 ambientscale *= 2 * r_refdef.view.colorscale;
2604 diffusescale *= 2 * r_refdef.view.colorscale;
2605 ambientcolorbase[0] = lightcolor[0] * ambientscale * surfacecolor[0];ambientcolorbase[1] = lightcolor[1] * ambientscale * surfacecolor[1];ambientcolorbase[2] = lightcolor[2] * ambientscale * surfacecolor[2];
2606 diffusecolorbase[0] = lightcolor[0] * diffusescale * surfacecolor[0];diffusecolorbase[1] = lightcolor[1] * diffusescale * surfacecolor[1];diffusecolorbase[2] = lightcolor[2] * diffusescale * surfacecolor[2];
2607 ambientcolorpants[0] = ambientcolorbase[0] * surfacepants[0];ambientcolorpants[1] = ambientcolorbase[1] * surfacepants[1];ambientcolorpants[2] = ambientcolorbase[2] * surfacepants[2];
2608 diffusecolorpants[0] = diffusecolorbase[0] * surfacepants[0];diffusecolorpants[1] = diffusecolorbase[1] * surfacepants[1];diffusecolorpants[2] = diffusecolorbase[2] * surfacepants[2];
2609 ambientcolorshirt[0] = ambientcolorbase[0] * surfaceshirt[0];ambientcolorshirt[1] = ambientcolorbase[1] * surfaceshirt[1];ambientcolorshirt[2] = ambientcolorbase[2] * surfaceshirt[2];
2610 diffusecolorshirt[0] = diffusecolorbase[0] * surfaceshirt[0];diffusecolorshirt[1] = diffusecolorbase[1] * surfaceshirt[1];diffusecolorshirt[2] = diffusecolorbase[2] * surfaceshirt[2];
2611 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | (diffusescale > 0 ? BATCHNEED_ARRAY_NORMAL : 0) | BATCHNEED_ARRAY_TEXCOORD, texturenumsurfaces, texturesurfacelist);
2612 R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
2613 R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.array_passcolor4f, 0, 0);
2614 R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
2615 R_Mesh_TexBind(0, basetexture);
2616 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
2617 R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
2618 switch(r_shadow_rendermode)
2620 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2621 R_Mesh_TexBind(1, r_shadow_attenuation3dtexture);
2622 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
2623 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
2624 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
2626 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2627 R_Mesh_TexBind(2, r_shadow_attenuation2dtexture);
2628 R_Mesh_TexMatrix(2, &rsurface.entitytoattenuationz);
2629 R_Mesh_TexCombine(2, GL_MODULATE, GL_MODULATE, 1, 1);
2630 R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
2632 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2633 R_Mesh_TexBind(1, r_shadow_attenuation2dtexture);
2634 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
2635 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
2636 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
2638 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2643 //R_Mesh_TexBind(0, basetexture);
2644 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorbase, ambientcolorbase);
2647 R_Mesh_TexBind(0, pantstexture);
2648 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorpants, ambientcolorpants);
2652 R_Mesh_TexBind(0, shirttexture);
2653 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorshirt, ambientcolorshirt);
2657 extern cvar_t gl_lightmaps;
2658 void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
2660 float ambientscale, diffusescale, specularscale;
2662 float lightcolor[3];
2663 VectorCopy(rsurface.rtlight->currentcolor, lightcolor);
2664 ambientscale = rsurface.rtlight->ambientscale;
2665 diffusescale = rsurface.rtlight->diffusescale;
2666 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
2667 if (!r_shadow_usenormalmap.integer)
2669 ambientscale += 1.0f * diffusescale;
2673 if ((ambientscale + diffusescale) * VectorLength2(lightcolor) + specularscale * VectorLength2(lightcolor) < (1.0f / 1048576.0f))
2675 negated = (lightcolor[0] + lightcolor[1] + lightcolor[2] < 0) && vid.support.ext_blend_subtract;
2678 VectorNegate(lightcolor, lightcolor);
2679 switch(vid.renderpath)
2681 case RENDERPATH_GL11:
2682 case RENDERPATH_GL13:
2683 case RENDERPATH_GL20:
2684 case RENDERPATH_CGGL:
2685 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
2687 case RENDERPATH_D3D9:
2689 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_SUBTRACT);
2692 case RENDERPATH_D3D10:
2693 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2695 case RENDERPATH_D3D11:
2696 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2700 RSurf_SetupDepthAndCulling();
2701 switch (r_shadow_rendermode)
2703 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2704 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2705 R_Shadow_RenderLighting_VisibleLighting(texturenumsurfaces, texturesurfacelist);
2707 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2708 R_Shadow_RenderLighting_Light_GLSL(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale, specularscale);
2710 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2711 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2712 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2713 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2714 R_Shadow_RenderLighting_Light_Vertex(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale);
2717 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2722 switch(vid.renderpath)
2724 case RENDERPATH_GL11:
2725 case RENDERPATH_GL13:
2726 case RENDERPATH_GL20:
2727 case RENDERPATH_CGGL:
2728 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
2730 case RENDERPATH_D3D9:
2732 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_ADD);
2735 case RENDERPATH_D3D10:
2736 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2738 case RENDERPATH_D3D11:
2739 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2745 void R_RTLight_Update(rtlight_t *rtlight, int isstatic, matrix4x4_t *matrix, vec3_t color, int style, const char *cubemapname, int shadow, vec_t corona, vec_t coronasizescale, vec_t ambientscale, vec_t diffusescale, vec_t specularscale, int flags)
2747 matrix4x4_t tempmatrix = *matrix;
2748 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
2750 // if this light has been compiled before, free the associated data
2751 R_RTLight_Uncompile(rtlight);
2753 // clear it completely to avoid any lingering data
2754 memset(rtlight, 0, sizeof(*rtlight));
2756 // copy the properties
2757 rtlight->matrix_lighttoworld = tempmatrix;
2758 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
2759 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
2760 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
2761 VectorCopy(color, rtlight->color);
2762 rtlight->cubemapname[0] = 0;
2763 if (cubemapname && cubemapname[0])
2764 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
2765 rtlight->shadow = shadow;
2766 rtlight->corona = corona;
2767 rtlight->style = style;
2768 rtlight->isstatic = isstatic;
2769 rtlight->coronasizescale = coronasizescale;
2770 rtlight->ambientscale = ambientscale;
2771 rtlight->diffusescale = diffusescale;
2772 rtlight->specularscale = specularscale;
2773 rtlight->flags = flags;
2775 // compute derived data
2776 //rtlight->cullradius = rtlight->radius;
2777 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2778 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2779 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2780 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2781 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2782 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2783 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2786 // compiles rtlight geometry
2787 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2788 void R_RTLight_Compile(rtlight_t *rtlight)
2791 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
2792 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
2793 entity_render_t *ent = r_refdef.scene.worldentity;
2794 dp_model_t *model = r_refdef.scene.worldmodel;
2795 unsigned char *data;
2798 // compile the light
2799 rtlight->compiled = true;
2800 rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
2801 rtlight->static_numleafs = 0;
2802 rtlight->static_numleafpvsbytes = 0;
2803 rtlight->static_leaflist = NULL;
2804 rtlight->static_leafpvs = NULL;
2805 rtlight->static_numsurfaces = 0;
2806 rtlight->static_surfacelist = NULL;
2807 rtlight->static_shadowmap_receivers = 0x3F;
2808 rtlight->static_shadowmap_casters = 0x3F;
2809 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2810 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2811 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2812 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2813 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2814 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2816 if (model && model->GetLightInfo)
2818 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
2819 r_shadow_compilingrtlight = rtlight;
2820 model->GetLightInfo(ent, rtlight->shadoworigin, rtlight->radius, rtlight->cullmins, rtlight->cullmaxs, r_shadow_buffer_leaflist, r_shadow_buffer_leafpvs, &numleafs, r_shadow_buffer_surfacelist, r_shadow_buffer_surfacepvs, &numsurfaces, r_shadow_buffer_shadowtrispvs, r_shadow_buffer_lighttrispvs, r_shadow_buffer_visitingleafpvs, 0, NULL);
2821 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2822 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
2823 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
2824 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
2825 rtlight->static_numsurfaces = numsurfaces;
2826 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
2827 rtlight->static_numleafs = numleafs;
2828 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
2829 rtlight->static_numleafpvsbytes = numleafpvsbytes;
2830 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
2831 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
2832 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
2833 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
2834 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
2835 if (rtlight->static_numsurfaces)
2836 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
2837 if (rtlight->static_numleafs)
2838 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
2839 if (rtlight->static_numleafpvsbytes)
2840 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
2841 if (rtlight->static_numshadowtrispvsbytes)
2842 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
2843 if (rtlight->static_numlighttrispvsbytes)
2844 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
2845 switch (rtlight->shadowmode)
2847 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2848 if (model->CompileShadowMap && rtlight->shadow)
2849 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2852 if (model->CompileShadowVolume && rtlight->shadow)
2853 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2856 // now we're done compiling the rtlight
2857 r_shadow_compilingrtlight = NULL;
2861 // use smallest available cullradius - box radius or light radius
2862 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2863 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2865 shadowzpasstris = 0;
2866 if (rtlight->static_meshchain_shadow_zpass)
2867 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
2868 shadowzpasstris += mesh->numtriangles;
2870 shadowzfailtris = 0;
2871 if (rtlight->static_meshchain_shadow_zfail)
2872 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
2873 shadowzfailtris += mesh->numtriangles;
2876 if (rtlight->static_numlighttrispvsbytes)
2877 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
2878 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
2882 if (rtlight->static_numlighttrispvsbytes)
2883 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
2884 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
2887 if (developer_extra.integer)
2888 Con_DPrintf("static light built: %f %f %f : %f %f %f box, %i light triangles, %i shadow triangles, %i zpass/%i zfail compiled shadow volume triangles\n", rtlight->cullmins[0], rtlight->cullmins[1], rtlight->cullmins[2], rtlight->cullmaxs[0], rtlight->cullmaxs[1], rtlight->cullmaxs[2], lighttris, shadowtris, shadowzpasstris, shadowzfailtris);
2891 void R_RTLight_Uncompile(rtlight_t *rtlight)
2893 if (rtlight->compiled)
2895 if (rtlight->static_meshchain_shadow_zpass)
2896 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
2897 rtlight->static_meshchain_shadow_zpass = NULL;
2898 if (rtlight->static_meshchain_shadow_zfail)
2899 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
2900 rtlight->static_meshchain_shadow_zfail = NULL;
2901 if (rtlight->static_meshchain_shadow_shadowmap)
2902 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
2903 rtlight->static_meshchain_shadow_shadowmap = NULL;
2904 // these allocations are grouped
2905 if (rtlight->static_surfacelist)
2906 Mem_Free(rtlight->static_surfacelist);
2907 rtlight->static_numleafs = 0;
2908 rtlight->static_numleafpvsbytes = 0;
2909 rtlight->static_leaflist = NULL;
2910 rtlight->static_leafpvs = NULL;
2911 rtlight->static_numsurfaces = 0;
2912 rtlight->static_surfacelist = NULL;
2913 rtlight->static_numshadowtrispvsbytes = 0;
2914 rtlight->static_shadowtrispvs = NULL;
2915 rtlight->static_numlighttrispvsbytes = 0;
2916 rtlight->static_lighttrispvs = NULL;
2917 rtlight->compiled = false;
2921 void R_Shadow_UncompileWorldLights(void)
2925 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
2926 for (lightindex = 0;lightindex < range;lightindex++)
2928 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2931 R_RTLight_Uncompile(&light->rtlight);
2935 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
2939 // reset the count of frustum planes
2940 // see rtlight->cached_frustumplanes definition for how much this array
2942 rtlight->cached_numfrustumplanes = 0;
2944 // haven't implemented a culling path for ortho rendering
2945 if (!r_refdef.view.useperspective)
2947 // check if the light is on screen and copy the 4 planes if it is
2948 for (i = 0;i < 4;i++)
2949 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
2952 for (i = 0;i < 4;i++)
2953 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
2958 // generate a deformed frustum that includes the light origin, this is
2959 // used to cull shadow casting surfaces that can not possibly cast a
2960 // shadow onto the visible light-receiving surfaces, which can be a
2963 // if the light origin is onscreen the result will be 4 planes exactly
2964 // if the light origin is offscreen on only one axis the result will
2965 // be exactly 5 planes (split-side case)
2966 // if the light origin is offscreen on two axes the result will be
2967 // exactly 4 planes (stretched corner case)
2968 for (i = 0;i < 4;i++)
2970 // quickly reject standard frustum planes that put the light
2971 // origin outside the frustum
2972 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
2975 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
2977 // if all the standard frustum planes were accepted, the light is onscreen
2978 // otherwise we need to generate some more planes below...
2979 if (rtlight->cached_numfrustumplanes < 4)
2981 // at least one of the stock frustum planes failed, so we need to
2982 // create one or two custom planes to enclose the light origin
2983 for (i = 0;i < 4;i++)
2985 // create a plane using the view origin and light origin, and a
2986 // single point from the frustum corner set
2987 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
2988 VectorNormalize(plane.normal);
2989 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
2990 // see if this plane is backwards and flip it if so
2991 for (j = 0;j < 4;j++)
2992 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
2996 VectorNegate(plane.normal, plane.normal);
2998 // flipped plane, test again to see if it is now valid
2999 for (j = 0;j < 4;j++)
3000 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3002 // if the plane is still not valid, then it is dividing the
3003 // frustum and has to be rejected
3007 // we have created a valid plane, compute extra info
3008 PlaneClassify(&plane);
3010 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3012 // if we've found 5 frustum planes then we have constructed a
3013 // proper split-side case and do not need to keep searching for
3014 // planes to enclose the light origin
3015 if (rtlight->cached_numfrustumplanes == 5)
3023 for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
3025 plane = rtlight->cached_frustumplanes[i];
3026 Con_Printf("light %p plane #%i %f %f %f : %f (%f %f %f %f %f)\n", rtlight, i, plane.normal[0], plane.normal[1], plane.normal[2], plane.dist, PlaneDiff(r_refdef.view.frustumcorner[0], &plane), PlaneDiff(r_refdef.view.frustumcorner[1], &plane), PlaneDiff(r_refdef.view.frustumcorner[2], &plane), PlaneDiff(r_refdef.view.frustumcorner[3], &plane), PlaneDiff(rtlight->shadoworigin, &plane));
3031 // now add the light-space box planes if the light box is rotated, as any
3032 // caster outside the oriented light box is irrelevant (even if it passed
3033 // the worldspace light box, which is axial)
3034 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3036 for (i = 0;i < 6;i++)
3040 v[i >> 1] = (i & 1) ? -1 : 1;
3041 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3042 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3043 plane.dist = VectorNormalizeLength(plane.normal);
3044 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3045 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3051 // add the world-space reduced box planes
3052 for (i = 0;i < 6;i++)
3054 VectorClear(plane.normal);
3055 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3056 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
3057 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3066 // reduce all plane distances to tightly fit the rtlight cull box, which
3068 VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3069 VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3070 VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3071 VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3072 VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3073 VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3074 VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3075 VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3076 oldnum = rtlight->cached_numfrustumplanes;
3077 rtlight->cached_numfrustumplanes = 0;
3078 for (j = 0;j < oldnum;j++)
3080 // find the nearest point on the box to this plane
3081 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
3082 for (i = 1;i < 8;i++)
3084 dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
3085 if (bestdist > dist)
3088 Con_Printf("light %p %splane #%i %f %f %f : %f < %f\n", rtlight, rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125 ? "^2" : "^1", j, rtlight->cached_frustumplanes[j].normal[0], rtlight->cached_frustumplanes[j].normal[1], rtlight->cached_frustumplanes[j].normal[2], rtlight->cached_frustumplanes[j].dist, bestdist);
3089 // if the nearest point is near or behind the plane, we want this
3090 // plane, otherwise the plane is useless as it won't cull anything
3091 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
3093 PlaneClassify(&rtlight->cached_frustumplanes[j]);
3094 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
3101 void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
3105 RSurf_ActiveWorldEntity();
3107 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3110 GL_CullFace(GL_NONE);
3111 mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3112 for (;mesh;mesh = mesh->next)
3114 if (!mesh->sidetotals[r_shadow_shadowmapside])
3116 r_refdef.stats.lights_shadowtriangles += mesh->sidetotals[r_shadow_shadowmapside];
3117 R_Mesh_PrepareVertices_Position(mesh->numverts, mesh->vertexposition, mesh->vertexpositionbuffer);
3118 R_Mesh_Draw(0, mesh->numverts, mesh->sideoffsets[r_shadow_shadowmapside], mesh->sidetotals[r_shadow_shadowmapside], mesh->element3i, mesh->element3i_indexbuffer, mesh->element3i_bufferoffset, mesh->element3s, mesh->element3s_indexbuffer, mesh->element3s_bufferoffset);
3122 else if (r_refdef.scene.worldentity->model)
3123 r_refdef.scene.worldmodel->DrawShadowMap(r_shadow_shadowmapside, r_refdef.scene.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, surfacesides, rsurface.rtlight->cached_cullmins, rsurface.rtlight->cached_cullmaxs);
3125 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3128 void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3130 qboolean zpass = false;
3133 int surfacelistindex;
3134 msurface_t *surface;
3136 RSurf_ActiveWorldEntity();
3138 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3141 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
3143 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
3144 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
3146 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
3147 for (;mesh;mesh = mesh->next)
3149 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
3150 R_Mesh_PrepareVertices_Position(mesh->numverts, mesh->vertexposition, mesh->vertexpositionbuffer);
3151 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
3153 // increment stencil if frontface is infront of depthbuffer
3154 GL_CullFace(r_refdef.view.cullface_back);
3155 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
3156 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);
3157 // decrement stencil if backface is infront of depthbuffer
3158 GL_CullFace(r_refdef.view.cullface_front);
3159 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
3161 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
3163 // decrement stencil if backface is behind depthbuffer
3164 GL_CullFace(r_refdef.view.cullface_front);
3165 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
3166 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);
3167 // increment stencil if frontface is behind depthbuffer
3168 GL_CullFace(r_refdef.view.cullface_back);
3169 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
3171 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);
3175 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh)
3177 // use the shadow trispvs calculated earlier by GetLightInfo to cull world triangles on this dynamic light
3178 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
3179 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
3181 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
3182 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
3183 if (CHECKPVSBIT(trispvs, t))
3184 shadowmarklist[numshadowmark++] = t;
3186 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);
3188 else if (numsurfaces)
3189 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);
3191 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3194 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3196 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3197 vec_t relativeshadowradius;
3198 RSurf_ActiveModelEntity(ent, false, false, false);
3199 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3200 // we need to re-init the shader for each entity because the matrix changed
3201 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3202 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3203 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3204 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3205 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3206 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3207 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3208 switch (r_shadow_rendermode)
3210 case R_SHADOW_RENDERMODE_SHADOWMAP2D:
3211 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
3214 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3217 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3220 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3222 // set up properties for rendering light onto this entity
3223 RSurf_ActiveModelEntity(ent, true, true, false);
3224 GL_AlphaTest(false);
3225 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3226 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3227 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3228 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3231 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
3233 if (!r_refdef.scene.worldmodel->DrawLight)
3236 // set up properties for rendering light onto this entity
3237 RSurf_ActiveWorldEntity();
3238 GL_AlphaTest(false);
3239 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3240 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3241 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3242 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3244 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
3246 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3249 void R_Shadow_DrawEntityLight(entity_render_t *ent)
3251 dp_model_t *model = ent->model;
3252 if (!model->DrawLight)
3255 R_Shadow_SetupEntityLight(ent);
3257 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3259 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3262 void R_Shadow_PrepareLight(rtlight_t *rtlight)
3266 int numleafs, numsurfaces;
3267 int *leaflist, *surfacelist;
3268 unsigned char *leafpvs;
3269 unsigned char *shadowtrispvs;
3270 unsigned char *lighttrispvs;
3271 //unsigned char *surfacesides;
3272 int numlightentities;
3273 int numlightentities_noselfshadow;
3274 int numshadowentities;
3275 int numshadowentities_noselfshadow;
3276 static entity_render_t *lightentities[MAX_EDICTS];
3277 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3278 static entity_render_t *shadowentities[MAX_EDICTS];
3279 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3282 rtlight->draw = false;
3284 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3285 // skip lights that are basically invisible (color 0 0 0)
3286 nolight = VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f);
3288 // loading is done before visibility checks because loading should happen
3289 // all at once at the start of a level, not when it stalls gameplay.
3290 // (especially important to benchmarks)
3292 if (rtlight->isstatic && !nolight && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
3294 if (rtlight->compiled)
3295 R_RTLight_Uncompile(rtlight);
3296 R_RTLight_Compile(rtlight);
3300 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
3302 // look up the light style value at this time
3303 f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3304 VectorScale(rtlight->color, f, rtlight->currentcolor);
3306 if (rtlight->selected)
3308 f = 2 + sin(realtime * M_PI * 4.0);
3309 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3313 // if lightstyle is currently off, don't draw the light
3314 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3317 // skip processing on corona-only lights
3321 // if the light box is offscreen, skip it
3322 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3325 VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
3326 VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
3328 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3330 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3332 // compiled light, world available and can receive realtime lighting
3333 // retrieve leaf information
3334 numleafs = rtlight->static_numleafs;
3335 leaflist = rtlight->static_leaflist;
3336 leafpvs = rtlight->static_leafpvs;
3337 numsurfaces = rtlight->static_numsurfaces;
3338 surfacelist = rtlight->static_surfacelist;
3339 //surfacesides = NULL;
3340 shadowtrispvs = rtlight->static_shadowtrispvs;
3341 lighttrispvs = rtlight->static_lighttrispvs;
3343 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3345 // dynamic light, world available and can receive realtime lighting
3346 // calculate lit surfaces and leafs
3347 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);
3348 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3349 leaflist = r_shadow_buffer_leaflist;
3350 leafpvs = r_shadow_buffer_leafpvs;
3351 surfacelist = r_shadow_buffer_surfacelist;
3352 //surfacesides = r_shadow_buffer_surfacesides;
3353 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3354 lighttrispvs = r_shadow_buffer_lighttrispvs;
3355 // if the reduced leaf bounds are offscreen, skip it
3356 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3367 //surfacesides = NULL;
3368 shadowtrispvs = NULL;
3369 lighttrispvs = NULL;
3371 // check if light is illuminating any visible leafs
3374 for (i = 0;i < numleafs;i++)
3375 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3381 // make a list of lit entities and shadow casting entities
3382 numlightentities = 0;
3383 numlightentities_noselfshadow = 0;
3384 numshadowentities = 0;
3385 numshadowentities_noselfshadow = 0;
3387 // add dynamic entities that are lit by the light
3388 for (i = 0;i < r_refdef.scene.numentities;i++)
3391 entity_render_t *ent = r_refdef.scene.entities[i];
3393 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3395 // skip the object entirely if it is not within the valid
3396 // shadow-casting region (which includes the lit region)
3397 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
3399 if (!(model = ent->model))
3401 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
3403 // this entity wants to receive light, is visible, and is
3404 // inside the light box
3405 // TODO: check if the surfaces in the model can receive light
3406 // so now check if it's in a leaf seen by the light
3407 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))
3409 if (ent->flags & RENDER_NOSELFSHADOW)
3410 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
3412 lightentities[numlightentities++] = ent;
3413 // since it is lit, it probably also casts a shadow...
3414 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3415 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3416 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3418 // note: exterior models without the RENDER_NOSELFSHADOW
3419 // flag still create a RENDER_NOSELFSHADOW shadow but
3420 // are lit normally, this means that they are
3421 // self-shadowing but do not shadow other
3422 // RENDER_NOSELFSHADOW entities such as the gun
3423 // (very weird, but keeps the player shadow off the gun)
3424 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3425 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3427 shadowentities[numshadowentities++] = ent;
3430 else if (ent->flags & RENDER_SHADOW)
3432 // this entity is not receiving light, but may still need to
3434 // TODO: check if the surfaces in the model can cast shadow
3435 // now check if it is in a leaf seen by the light
3436 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))
3438 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3439 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3440 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3442 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3443 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3445 shadowentities[numshadowentities++] = ent;
3450 // return if there's nothing at all to light
3451 if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
3454 // count this light in the r_speeds
3455 r_refdef.stats.lights++;
3457 // flag it as worth drawing later
3458 rtlight->draw = true;
3460 // cache all the animated entities that cast a shadow but are not visible
3461 for (i = 0;i < numshadowentities;i++)
3462 if (!shadowentities[i]->animcache_vertex3f)
3463 R_AnimCache_GetEntity(shadowentities[i], false, false);
3464 for (i = 0;i < numshadowentities_noselfshadow;i++)
3465 if (!shadowentities_noselfshadow[i]->animcache_vertex3f)
3466 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
3468 // allocate some temporary memory for rendering this light later in the frame
3469 // reusable buffers need to be copied, static data can be used as-is
3470 rtlight->cached_numlightentities = numlightentities;
3471 rtlight->cached_numlightentities_noselfshadow = numlightentities_noselfshadow;
3472 rtlight->cached_numshadowentities = numshadowentities;
3473 rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
3474 rtlight->cached_numsurfaces = numsurfaces;
3475 rtlight->cached_lightentities = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
3476 rtlight->cached_lightentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
3477 rtlight->cached_shadowentities = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
3478 rtlight->cached_shadowentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
3479 if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
3481 int numshadowtrispvsbytes = (((r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles) + 7) >> 3);
3482 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
3483 rtlight->cached_shadowtrispvs = (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
3484 rtlight->cached_lighttrispvs = (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
3485 rtlight->cached_surfacelist = (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
3489 // compiled light data
3490 rtlight->cached_shadowtrispvs = shadowtrispvs;
3491 rtlight->cached_lighttrispvs = lighttrispvs;
3492 rtlight->cached_surfacelist = surfacelist;
3496 void R_Shadow_DrawLight(rtlight_t *rtlight)
3500 unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
3501 int numlightentities;
3502 int numlightentities_noselfshadow;
3503 int numshadowentities;
3504 int numshadowentities_noselfshadow;
3505 entity_render_t **lightentities;
3506 entity_render_t **lightentities_noselfshadow;
3507 entity_render_t **shadowentities;
3508 entity_render_t **shadowentities_noselfshadow;
3510 static unsigned char entitysides[MAX_EDICTS];
3511 static unsigned char entitysides_noselfshadow[MAX_EDICTS];
3512 vec3_t nearestpoint;
3514 qboolean castshadows;
3517 // check if we cached this light this frame (meaning it is worth drawing)
3521 // if R_FrameData_Store ran out of space we skip anything dependent on it
3522 if (r_framedata_failed)
3525 numlightentities = rtlight->cached_numlightentities;
3526 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
3527 numshadowentities = rtlight->cached_numshadowentities;
3528 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
3529 numsurfaces = rtlight->cached_numsurfaces;
3530 lightentities = rtlight->cached_lightentities;
3531 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
3532 shadowentities = rtlight->cached_shadowentities;
3533 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
3534 shadowtrispvs = rtlight->cached_shadowtrispvs;
3535 lighttrispvs = rtlight->cached_lighttrispvs;
3536 surfacelist = rtlight->cached_surfacelist;
3538 // set up a scissor rectangle for this light
3539 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3542 // don't let sound skip if going slow
3543 if (r_refdef.scene.extraupdate)
3546 // make this the active rtlight for rendering purposes
3547 R_Shadow_RenderMode_ActiveLight(rtlight);
3549 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
3551 // optionally draw visible shape of the shadow volumes
3552 // for performance analysis by level designers
3553 R_Shadow_RenderMode_VisibleShadowVolumes();
3555 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
3556 for (i = 0;i < numshadowentities;i++)
3557 R_Shadow_DrawEntityShadow(shadowentities[i]);
3558 for (i = 0;i < numshadowentities_noselfshadow;i++)
3559 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3560 R_Shadow_RenderMode_VisibleLighting(false, false);
3563 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
3565 // optionally draw the illuminated areas
3566 // for performance analysis by level designers
3567 R_Shadow_RenderMode_VisibleLighting(false, false);
3569 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3570 for (i = 0;i < numlightentities;i++)
3571 R_Shadow_DrawEntityLight(lightentities[i]);
3572 for (i = 0;i < numlightentities_noselfshadow;i++)
3573 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3576 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
3578 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
3579 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
3580 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
3581 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
3583 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance/rtlight->radius));
3584 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
3585 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
3587 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
3593 int receivermask = 0;
3594 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
3595 Matrix4x4_Abs(&radiustolight);
3597 r_shadow_shadowmaplod = 0;
3598 for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
3599 if ((r_shadow_shadowmapmaxsize >> i) > lodlinear)
3600 r_shadow_shadowmaplod = i;
3602 size = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
3604 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
3606 surfacesides = NULL;
3609 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3611 castermask = rtlight->static_shadowmap_casters;
3612 receivermask = rtlight->static_shadowmap_receivers;
3616 surfacesides = r_shadow_buffer_surfacesides;
3617 for(i = 0;i < numsurfaces;i++)
3619 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
3620 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3621 castermask |= surfacesides[i];
3622 receivermask |= surfacesides[i];
3626 if (receivermask < 0x3F)
3628 for (i = 0;i < numlightentities;i++)
3629 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3630 if (receivermask < 0x3F)
3631 for(i = 0; i < numlightentities_noselfshadow;i++)
3632 receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3635 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
3639 for (i = 0;i < numshadowentities;i++)
3640 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3641 for (i = 0;i < numshadowentities_noselfshadow;i++)
3642 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3645 //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
3647 // render shadow casters into 6 sided depth texture
3648 for (side = 0;side < 6;side++) if (receivermask & (1 << side))
3650 R_Shadow_RenderMode_ShadowMap(side, receivermask, size);
3651 if (! (castermask & (1 << side))) continue;
3653 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
3654 for (i = 0;i < numshadowentities;i++) if (entitysides[i] & (1 << side))
3655 R_Shadow_DrawEntityShadow(shadowentities[i]);
3658 if (numlightentities_noselfshadow)
3660 // render lighting using the depth texture as shadowmap
3661 // draw lighting in the unmasked areas
3662 R_Shadow_RenderMode_Lighting(false, false, true);
3663 for (i = 0;i < numlightentities_noselfshadow;i++)
3664 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3667 // render shadow casters into 6 sided depth texture
3668 if (numshadowentities_noselfshadow)
3670 for (side = 0;side < 6;side++) if ((receivermask & castermask) & (1 << side))
3672 R_Shadow_RenderMode_ShadowMap(side, 0, size);
3673 for (i = 0;i < numshadowentities_noselfshadow;i++) if (entitysides_noselfshadow[i] & (1 << side))
3674 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3678 // render lighting using the depth texture as shadowmap
3679 // draw lighting in the unmasked areas
3680 R_Shadow_RenderMode_Lighting(false, false, true);
3681 // draw lighting in the unmasked areas
3683 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3684 for (i = 0;i < numlightentities;i++)
3685 R_Shadow_DrawEntityLight(lightentities[i]);
3687 else if (castshadows && vid.stencil)
3689 // draw stencil shadow volumes to mask off pixels that are in shadow
3690 // so that they won't receive lighting
3691 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
3692 R_Shadow_ClearStencil();
3695 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
3696 for (i = 0;i < numshadowentities;i++)
3697 R_Shadow_DrawEntityShadow(shadowentities[i]);
3699 // draw lighting in the unmasked areas
3700 R_Shadow_RenderMode_Lighting(true, false, false);
3701 for (i = 0;i < numlightentities_noselfshadow;i++)
3702 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3704 for (i = 0;i < numshadowentities_noselfshadow;i++)
3705 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3707 // draw lighting in the unmasked areas
3708 R_Shadow_RenderMode_Lighting(true, false, false);
3710 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3711 for (i = 0;i < numlightentities;i++)
3712 R_Shadow_DrawEntityLight(lightentities[i]);
3716 // draw lighting in the unmasked areas
3717 R_Shadow_RenderMode_Lighting(false, false, false);
3719 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3720 for (i = 0;i < numlightentities;i++)
3721 R_Shadow_DrawEntityLight(lightentities[i]);
3722 for (i = 0;i < numlightentities_noselfshadow;i++)
3723 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3726 if (r_shadow_usingdeferredprepass)
3728 // when rendering deferred lighting, we simply rasterize the box
3729 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
3730 R_Shadow_RenderMode_DrawDeferredLight(false, true);
3731 else if (castshadows && vid.stencil)
3732 R_Shadow_RenderMode_DrawDeferredLight(true, false);
3734 R_Shadow_RenderMode_DrawDeferredLight(false, false);
3738 static void R_Shadow_FreeDeferred(void)
3740 R_Mesh_DestroyFramebufferObject(r_shadow_prepassgeometryfbo);
3741 r_shadow_prepassgeometryfbo = 0;
3743 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingfbo);
3744 r_shadow_prepasslightingfbo = 0;
3746 if (r_shadow_prepassgeometrydepthtexture)
3747 R_FreeTexture(r_shadow_prepassgeometrydepthtexture);
3748 r_shadow_prepassgeometrydepthtexture = NULL;
3750 if (r_shadow_prepassgeometrydepthcolortexture)
3751 R_FreeTexture(r_shadow_prepassgeometrydepthcolortexture);
3752 r_shadow_prepassgeometrydepthcolortexture = NULL;
3754 if (r_shadow_prepassgeometrynormalmaptexture)
3755 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
3756 r_shadow_prepassgeometrynormalmaptexture = NULL;
3758 if (r_shadow_prepasslightingdiffusetexture)
3759 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
3760 r_shadow_prepasslightingdiffusetexture = NULL;
3762 if (r_shadow_prepasslightingspeculartexture)
3763 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
3764 r_shadow_prepasslightingspeculartexture = NULL;
3767 void R_Shadow_DrawPrepass(void)
3775 entity_render_t *ent;
3776 float clearcolor[4];
3778 GL_AlphaTest(false);
3779 R_Mesh_ResetTextureState();
3781 GL_ColorMask(1,1,1,1);
3782 GL_BlendFunc(GL_ONE, GL_ZERO);
3785 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, r_shadow_prepassgeometrydepthcolortexture, NULL, NULL);
3786 Vector4Set(clearcolor, 0.5f,0.5f,0.5f,1.0f);
3787 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
3788 if (r_timereport_active)
3789 R_TimeReport("prepasscleargeom");
3791 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
3792 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
3793 if (r_timereport_active)
3794 R_TimeReport("prepassworld");
3796 for (i = 0;i < r_refdef.scene.numentities;i++)
3798 if (!r_refdef.viewcache.entityvisible[i])
3800 ent = r_refdef.scene.entities[i];
3801 if (ent->model && ent->model->DrawPrepass != NULL)
3802 ent->model->DrawPrepass(ent);
3805 if (r_timereport_active)
3806 R_TimeReport("prepassmodels");
3808 GL_DepthMask(false);
3809 GL_ColorMask(1,1,1,1);
3812 R_Mesh_SetRenderTargets(r_shadow_prepasslightingfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
3813 Vector4Set(clearcolor, 0, 0, 0, 0);
3814 GL_Clear(GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
3815 if (r_timereport_active)
3816 R_TimeReport("prepassclearlit");
3818 R_Shadow_RenderMode_Begin();
3820 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3821 if (r_shadow_debuglight.integer >= 0)
3823 lightindex = r_shadow_debuglight.integer;
3824 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3825 if (light && (light->flags & flag) && light->rtlight.draw)
3826 R_Shadow_DrawLight(&light->rtlight);
3830 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3831 for (lightindex = 0;lightindex < range;lightindex++)
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);
3838 if (r_refdef.scene.rtdlight)
3839 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
3840 if (r_refdef.scene.lights[lnum]->draw)
3841 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
3843 R_Mesh_ResetRenderTargets();
3845 R_Shadow_RenderMode_End();
3847 if (r_timereport_active)
3848 R_TimeReport("prepasslights");
3851 void R_Shadow_DrawLightSprites(void);
3852 void R_Shadow_PrepareLights(void)
3862 if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4) ||
3863 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
3864 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20) ||
3865 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
3866 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
3867 r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
3868 R_Shadow_FreeShadowMaps();
3870 r_shadow_usingshadowmaportho = false;
3872 switch (vid.renderpath)
3874 case RENDERPATH_GL20:
3875 case RENDERPATH_CGGL:
3876 case RENDERPATH_D3D9:
3877 case RENDERPATH_D3D10:
3878 case RENDERPATH_D3D11:
3879 if (!r_shadow_deferred.integer || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_STENCIL || !vid.support.ext_framebuffer_object || vid.maxdrawbuffers < 2)
3881 r_shadow_usingdeferredprepass = false;
3882 if (r_shadow_prepass_width)
3883 R_Shadow_FreeDeferred();
3884 r_shadow_prepass_width = r_shadow_prepass_height = 0;
3888 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
3890 R_Shadow_FreeDeferred();
3892 r_shadow_usingdeferredprepass = true;
3893 r_shadow_prepass_width = vid.width;
3894 r_shadow_prepass_height = vid.height;
3895 r_shadow_prepassgeometrydepthtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "prepassgeometrydepthmap", vid.width, vid.height, 24, false);
3896 switch (vid.renderpath)
3898 case RENDERPATH_D3D9:
3899 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);
3904 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);
3905 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);
3906 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);
3908 // set up the geometry pass fbo (depth + normalmap)
3909 r_shadow_prepassgeometryfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
3910 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, r_shadow_prepassgeometrydepthcolortexture, NULL, NULL);
3911 // render depth into one texture and normalmap into the other
3912 if (qglDrawBuffersARB)
3914 qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);CHECKGLERROR
3915 qglReadBuffer(GL_NONE);CHECKGLERROR
3916 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
3917 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
3919 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
3920 Cvar_SetValueQuick(&r_shadow_deferred, 0);
3921 r_shadow_usingdeferredprepass = false;
3925 // set up the lighting pass fbo (diffuse + specular)
3926 r_shadow_prepasslightingfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
3927 R_Mesh_SetRenderTargets(r_shadow_prepasslightingfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
3928 // render diffuse into one texture and specular into another,
3929 // with depth and normalmap bound as textures,
3930 // with depth bound as attachment as well
3931 if (qglDrawBuffersARB)
3933 qglDrawBuffersARB(2, r_shadow_prepasslightingdrawbuffers);CHECKGLERROR
3934 qglReadBuffer(GL_NONE);CHECKGLERROR
3935 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
3936 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
3938 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
3939 Cvar_SetValueQuick(&r_shadow_deferred, 0);
3940 r_shadow_usingdeferredprepass = false;
3945 case RENDERPATH_GL13:
3946 case RENDERPATH_GL11:
3947 r_shadow_usingdeferredprepass = false;
3951 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);
3953 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3954 if (r_shadow_debuglight.integer >= 0)
3956 lightindex = r_shadow_debuglight.integer;
3957 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3958 if (light && (light->flags & flag))
3959 R_Shadow_PrepareLight(&light->rtlight);
3963 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3964 for (lightindex = 0;lightindex < range;lightindex++)
3966 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3967 if (light && (light->flags & flag))
3968 R_Shadow_PrepareLight(&light->rtlight);
3971 if (r_refdef.scene.rtdlight)
3973 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
3974 R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
3976 else if(gl_flashblend.integer)
3978 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
3980 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
3981 f = (rtlight->style >= 0 ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3982 VectorScale(rtlight->color, f, rtlight->currentcolor);
3986 if (r_editlights.integer)
3987 R_Shadow_DrawLightSprites();
3990 void R_Shadow_DrawLights(void)
3998 R_Shadow_RenderMode_Begin();
4000 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4001 if (r_shadow_debuglight.integer >= 0)
4003 lightindex = r_shadow_debuglight.integer;
4004 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4005 if (light && (light->flags & flag))
4006 R_Shadow_DrawLight(&light->rtlight);
4010 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4011 for (lightindex = 0;lightindex < range;lightindex++)
4013 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4014 if (light && (light->flags & flag))
4015 R_Shadow_DrawLight(&light->rtlight);
4018 if (r_refdef.scene.rtdlight)
4019 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4020 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4022 R_Shadow_RenderMode_End();
4025 extern const float r_screenvertex3f[12];
4026 extern void R_SetupView(qboolean allowwaterclippingplane);
4027 extern void R_ResetViewRendering3D(void);
4028 extern void R_ResetViewRendering2D(void);
4029 extern cvar_t r_shadows;
4030 extern cvar_t r_shadows_darken;
4031 extern cvar_t r_shadows_drawafterrtlighting;
4032 extern cvar_t r_shadows_castfrombmodels;
4033 extern cvar_t r_shadows_throwdistance;
4034 extern cvar_t r_shadows_throwdirection;
4035 extern cvar_t r_shadows_focus;
4036 extern cvar_t r_shadows_shadowmapscale;
4038 void R_Shadow_PrepareModelShadows(void)
4041 float scale, size, radius, dot1, dot2;
4042 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
4043 entity_render_t *ent;
4045 if (!r_refdef.scene.numentities)
4048 switch (r_shadow_shadowmode)
4050 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4051 if (r_shadows.integer >= 2)
4054 case R_SHADOW_SHADOWMODE_STENCIL:
4055 for (i = 0;i < r_refdef.scene.numentities;i++)
4057 ent = r_refdef.scene.entities[i];
4058 if (!ent->animcache_vertex3f && ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4059 R_AnimCache_GetEntity(ent, false, false);
4066 size = 2*r_shadow_shadowmapmaxsize;
4067 scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
4068 radius = 0.5f * size / scale;
4070 Math_atov(r_shadows_throwdirection.string, shadowdir);
4071 VectorNormalize(shadowdir);
4072 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4073 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4074 if (fabs(dot1) <= fabs(dot2))
4075 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4077 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4078 VectorNormalize(shadowforward);
4079 CrossProduct(shadowdir, shadowforward, shadowright);
4080 Math_atov(r_shadows_focus.string, shadowfocus);
4081 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4082 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4083 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4084 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4085 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4087 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4089 shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4090 shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4091 shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4092 shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4093 shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4094 shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4096 for (i = 0;i < r_refdef.scene.numentities;i++)
4098 ent = r_refdef.scene.entities[i];
4099 if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
4101 // cast shadows from anything of the map (submodels are optional)
4102 if (!ent->animcache_vertex3f && ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4103 R_AnimCache_GetEntity(ent, false, false);
4107 void R_DrawModelShadowMaps(void)
4110 float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
4111 entity_render_t *ent;
4112 vec3_t relativelightorigin;
4113 vec3_t relativelightdirection, relativeforward, relativeright;
4114 vec3_t relativeshadowmins, relativeshadowmaxs;
4115 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
4117 matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
4118 r_viewport_t viewport;
4120 float clearcolor[4];
4122 if (!r_refdef.scene.numentities)
4125 switch (r_shadow_shadowmode)
4127 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4133 R_ResetViewRendering3D();
4134 R_Shadow_RenderMode_Begin();
4135 R_Shadow_RenderMode_ActiveLight(NULL);
4137 switch (r_shadow_shadowmode)
4139 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4140 if (!r_shadow_shadowmap2dtexture)
4141 R_Shadow_MakeShadowMap(0, r_shadow_shadowmapmaxsize);
4142 fbo = r_shadow_fbo2d;
4143 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
4144 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
4145 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
4151 size = 2*r_shadow_shadowmapmaxsize;
4152 scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
4153 radius = 0.5f / scale;
4154 nearclip = -r_shadows_throwdistance.value;
4155 farclip = r_shadows_throwdistance.value;
4156 bias = r_shadow_shadowmapping_bias.value * r_shadow_shadowmapping_nearclip.value / (2 * r_shadows_throwdistance.value) * (1024.0f / size);
4158 r_shadow_shadowmap_parameters[0] = size;
4159 r_shadow_shadowmap_parameters[1] = size;
4160 r_shadow_shadowmap_parameters[2] = 1.0;
4161 r_shadow_shadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
4163 Math_atov(r_shadows_throwdirection.string, shadowdir);
4164 VectorNormalize(shadowdir);
4165 Math_atov(r_shadows_focus.string, shadowfocus);
4166 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4167 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4168 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4169 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4170 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4171 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4172 if (fabs(dot1) <= fabs(dot2))
4173 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4175 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4176 VectorNormalize(shadowforward);
4177 VectorM(scale, shadowforward, &m[0]);
4178 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4180 m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
4181 CrossProduct(shadowdir, shadowforward, shadowright);
4182 VectorM(scale, shadowright, &m[4]);
4183 m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
4184 VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
4185 m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
4186 Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
4187 Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
4188 R_Viewport_InitOrtho(&viewport, &cameramatrix, 0, 0, size, size, 0, 0, 1, 1, 0, -1, NULL);
4190 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4192 R_Mesh_SetRenderTargets(fbo, r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
4193 R_SetupShader_DepthOrShadow();
4194 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
4197 R_SetViewport(&viewport);
4198 GL_Scissor(viewport.x, viewport.y, min(viewport.width + r_shadow_shadowmapborder, 2*r_shadow_shadowmapmaxsize), viewport.height + r_shadow_shadowmapborder);
4199 Vector4Set(clearcolor, 1,1,1,1);
4200 // in D3D9 we have to render to a color texture shadowmap
4201 // in GL we render directly to a depth texture only
4202 if (r_shadow_shadowmap2dtexture)
4203 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4205 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4206 // render into a slightly restricted region so that the borders of the
4207 // shadowmap area fade away, rather than streaking across everything
4208 // outside the usable area
4209 GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
4213 R_Mesh_ResetRenderTargets();
4214 R_SetupShader_ShowDepth();
4215 GL_ColorMask(1,1,1,1);
4216 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4219 for (i = 0;i < r_refdef.scene.numentities;i++)
4221 ent = r_refdef.scene.entities[i];
4223 // cast shadows from anything of the map (submodels are optional)
4224 if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4226 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4227 Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
4228 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4229 Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
4230 Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
4231 relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4232 relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4233 relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4234 relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4235 relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4236 relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4237 RSurf_ActiveModelEntity(ent, false, false, false);
4238 ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
4239 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4246 unsigned char *rawpixels = Z_Malloc(viewport.width*viewport.height*4);
4248 qglReadPixels(viewport.x, viewport.y, viewport.width, viewport.height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, rawpixels);
4250 Image_WriteTGABGRA("r_shadows_2.tga", viewport.width, viewport.height, rawpixels);
4251 Cvar_SetValueQuick(&r_test, 0);
4256 R_Shadow_RenderMode_End();
4258 Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
4259 Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
4260 Matrix4x4_CreateScale3(&scalematrix, size, -size, 1);
4261 Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
4262 Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
4263 Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
4265 switch (vid.renderpath)
4267 case RENDERPATH_GL11:
4268 case RENDERPATH_GL13:
4269 case RENDERPATH_GL20:
4270 case RENDERPATH_CGGL:
4272 case RENDERPATH_D3D9:
4273 case RENDERPATH_D3D10:
4274 case RENDERPATH_D3D11:
4275 #ifdef OPENGL_ORIENTATION
4276 r_shadow_shadowmapmatrix.m[0][0] *= -1.0f;
4277 r_shadow_shadowmapmatrix.m[0][1] *= -1.0f;
4278 r_shadow_shadowmapmatrix.m[0][2] *= -1.0f;
4279 r_shadow_shadowmapmatrix.m[0][3] *= -1.0f;
4281 r_shadow_shadowmapmatrix.m[0][0] *= -1.0f;
4282 r_shadow_shadowmapmatrix.m[1][0] *= -1.0f;
4283 r_shadow_shadowmapmatrix.m[2][0] *= -1.0f;
4284 r_shadow_shadowmapmatrix.m[3][0] *= -1.0f;
4289 r_shadow_usingshadowmaportho = true;
4290 switch (r_shadow_shadowmode)
4292 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4293 r_shadow_usingshadowmap2d = true;
4300 void R_DrawModelShadows(void)
4303 float relativethrowdistance;
4304 entity_render_t *ent;
4305 vec3_t relativelightorigin;
4306 vec3_t relativelightdirection;
4307 vec3_t relativeshadowmins, relativeshadowmaxs;
4308 vec3_t tmp, shadowdir;
4310 if (!r_refdef.scene.numentities || !vid.stencil || (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL && r_shadows.integer != 1))
4313 R_ResetViewRendering3D();
4314 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4315 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4316 R_Shadow_RenderMode_Begin();
4317 R_Shadow_RenderMode_ActiveLight(NULL);
4318 r_shadow_lightscissor[0] = r_refdef.view.x;
4319 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
4320 r_shadow_lightscissor[2] = r_refdef.view.width;
4321 r_shadow_lightscissor[3] = r_refdef.view.height;
4322 R_Shadow_RenderMode_StencilShadowVolumes(false);
4325 if (r_shadows.integer == 2)
4327 Math_atov(r_shadows_throwdirection.string, shadowdir);
4328 VectorNormalize(shadowdir);
4331 R_Shadow_ClearStencil();
4333 for (i = 0;i < r_refdef.scene.numentities;i++)
4335 ent = r_refdef.scene.entities[i];
4337 // cast shadows from anything of the map (submodels are optional)
4338 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4340 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4341 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
4342 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
4343 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
4344 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4347 if(ent->entitynumber != 0)
4349 if(ent->entitynumber >= MAX_EDICTS) // csqc entity
4351 // FIXME handle this
4352 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4356 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
4357 int entnum, entnum2, recursion;
4358 entnum = entnum2 = ent->entitynumber;
4359 for(recursion = 32; recursion > 0; --recursion)
4361 entnum2 = cl.entities[entnum].state_current.tagentity;
4362 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
4367 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
4369 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
4370 // transform into modelspace of OUR entity
4371 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
4372 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
4375 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4379 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4382 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
4383 RSurf_ActiveModelEntity(ent, false, false, false);
4384 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4385 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4389 // not really the right mode, but this will disable any silly stencil features
4390 R_Shadow_RenderMode_End();
4392 // set up ortho view for rendering this pass
4393 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4394 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4395 //GL_ScissorTest(true);
4396 //R_EntityMatrix(&identitymatrix);
4397 //R_Mesh_ResetTextureState();
4398 R_ResetViewRendering2D();
4400 // set up a darkening blend on shadowed areas
4401 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4402 //GL_DepthRange(0, 1);
4403 //GL_DepthTest(false);
4404 //GL_DepthMask(false);
4405 //GL_PolygonOffset(0, 0);CHECKGLERROR
4406 GL_Color(0, 0, 0, r_shadows_darken.value);
4407 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4408 //GL_DepthFunc(GL_ALWAYS);
4409 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_NOTEQUAL, 128, 255);
4411 // apply the blend to the shadowed areas
4412 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, NULL);
4413 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
4414 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4416 // restore the viewport
4417 R_SetViewport(&r_refdef.view.viewport);
4419 // restore other state to normal
4420 //R_Shadow_RenderMode_End();
4423 void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4426 vec3_t centerorigin;
4428 // if it's too close, skip it
4429 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
4431 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4434 if (usequery && r_numqueries + 2 <= r_maxqueries)
4436 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4437 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4438 // 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
4439 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4441 switch(vid.renderpath)
4443 case RENDERPATH_GL20:
4444 case RENDERPATH_GL13:
4445 case RENDERPATH_GL11:
4446 case RENDERPATH_CGGL:
4448 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use GL_DepthFunc instead
4449 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
4450 GL_DepthFunc(GL_ALWAYS);
4451 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4452 R_Mesh_PrepareVertices_Position_Arrays(4, vertex3f);
4453 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4454 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4455 GL_DepthFunc(GL_LEQUAL);
4456 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
4457 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4458 R_Mesh_PrepareVertices_Position_Arrays(4, vertex3f);
4459 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4460 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4463 case RENDERPATH_D3D9:
4464 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4466 case RENDERPATH_D3D10:
4467 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4469 case RENDERPATH_D3D11:
4470 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4474 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4477 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
4479 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4482 GLint allpixels = 0, visiblepixels = 0;
4483 // now we have to check the query result
4484 if (rtlight->corona_queryindex_visiblepixels)
4486 switch(vid.renderpath)
4488 case RENDERPATH_GL20:
4489 case RENDERPATH_GL13:
4490 case RENDERPATH_GL11:
4491 case RENDERPATH_CGGL:
4493 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
4494 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
4497 case RENDERPATH_D3D9:
4498 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4500 case RENDERPATH_D3D10:
4501 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4503 case RENDERPATH_D3D11:
4504 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4507 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
4508 if (visiblepixels < 1 || allpixels < 1)
4510 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
4511 cscale *= rtlight->corona_visibility;
4515 // FIXME: these traces should scan all render entities instead of cl.world
4516 if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
4519 VectorScale(rtlight->currentcolor, cscale, color);
4520 if (VectorLength(color) > (1.0f / 256.0f))
4523 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
4526 VectorNegate(color, color);
4527 switch(vid.renderpath)
4529 case RENDERPATH_GL11:
4530 case RENDERPATH_GL13:
4531 case RENDERPATH_GL20:
4532 case RENDERPATH_CGGL:
4533 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
4535 case RENDERPATH_D3D9:
4537 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_SUBTRACT);
4540 case RENDERPATH_D3D10:
4541 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4543 case RENDERPATH_D3D11:
4544 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4548 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4549 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);
4550 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4553 switch(vid.renderpath)
4555 case RENDERPATH_GL11:
4556 case RENDERPATH_GL13:
4557 case RENDERPATH_GL20:
4558 case RENDERPATH_CGGL:
4559 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
4561 case RENDERPATH_D3D9:
4563 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_ADD);
4566 case RENDERPATH_D3D10:
4567 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4569 case RENDERPATH_D3D11:
4570 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4577 void R_Shadow_DrawCoronas(void)
4580 qboolean usequery = false;
4585 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4587 if (r_waterstate.renderingscene)
4589 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4590 R_EntityMatrix(&identitymatrix);
4592 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4594 // check occlusion of coronas
4595 // use GL_ARB_occlusion_query if available
4596 // otherwise use raytraces
4598 switch (vid.renderpath)
4600 case RENDERPATH_GL11:
4601 case RENDERPATH_GL13:
4602 case RENDERPATH_GL20:
4603 case RENDERPATH_CGGL:
4604 usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
4607 GL_ColorMask(0,0,0,0);
4608 if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
4609 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
4612 r_maxqueries = (range + r_refdef.scene.numlights) * 4;
4613 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
4615 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
4618 RSurf_ActiveWorldEntity();
4619 GL_BlendFunc(GL_ONE, GL_ZERO);
4620 GL_CullFace(GL_NONE);
4621 GL_DepthMask(false);
4622 GL_DepthRange(0, 1);
4623 GL_PolygonOffset(0, 0);
4625 R_Mesh_ResetTextureState();
4626 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
4629 case RENDERPATH_D3D9:
4631 //Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4633 case RENDERPATH_D3D10:
4634 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4636 case RENDERPATH_D3D11:
4637 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4640 for (lightindex = 0;lightindex < range;lightindex++)
4642 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4645 rtlight = &light->rtlight;
4646 rtlight->corona_visibility = 0;
4647 rtlight->corona_queryindex_visiblepixels = 0;
4648 rtlight->corona_queryindex_allpixels = 0;
4649 if (!(rtlight->flags & flag))
4651 if (rtlight->corona <= 0)
4653 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4655 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4657 for (i = 0;i < r_refdef.scene.numlights;i++)
4659 rtlight = r_refdef.scene.lights[i];
4660 rtlight->corona_visibility = 0;
4661 rtlight->corona_queryindex_visiblepixels = 0;
4662 rtlight->corona_queryindex_allpixels = 0;
4663 if (!(rtlight->flags & flag))
4665 if (rtlight->corona <= 0)
4667 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4670 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4672 // now draw the coronas using the query data for intensity info
4673 for (lightindex = 0;lightindex < range;lightindex++)
4675 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4678 rtlight = &light->rtlight;
4679 if (rtlight->corona_visibility <= 0)
4681 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4683 for (i = 0;i < r_refdef.scene.numlights;i++)
4685 rtlight = r_refdef.scene.lights[i];
4686 if (rtlight->corona_visibility <= 0)
4688 if (gl_flashblend.integer)
4689 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4691 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4697 dlight_t *R_Shadow_NewWorldLight(void)
4699 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4702 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)
4705 // validate parameters
4706 if (style < 0 || style >= MAX_LIGHTSTYLES)
4708 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
4714 // copy to light properties
4715 VectorCopy(origin, light->origin);
4716 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4717 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4718 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4720 light->color[0] = max(color[0], 0);
4721 light->color[1] = max(color[1], 0);
4722 light->color[2] = max(color[2], 0);
4724 light->color[0] = color[0];
4725 light->color[1] = color[1];
4726 light->color[2] = color[2];
4727 light->radius = max(radius, 0);
4728 light->style = style;
4729 light->shadow = shadowenable;
4730 light->corona = corona;
4731 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4732 light->coronasizescale = coronasizescale;
4733 light->ambientscale = ambientscale;
4734 light->diffusescale = diffusescale;
4735 light->specularscale = specularscale;
4736 light->flags = flags;
4738 // update renderable light data
4739 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4740 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);
4743 void R_Shadow_FreeWorldLight(dlight_t *light)
4745 if (r_shadow_selectedlight == light)
4746 r_shadow_selectedlight = NULL;
4747 R_RTLight_Uncompile(&light->rtlight);
4748 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4751 void R_Shadow_ClearWorldLights(void)
4755 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4756 for (lightindex = 0;lightindex < range;lightindex++)
4758 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4760 R_Shadow_FreeWorldLight(light);
4762 r_shadow_selectedlight = NULL;
4765 void R_Shadow_SelectLight(dlight_t *light)
4767 if (r_shadow_selectedlight)
4768 r_shadow_selectedlight->selected = false;
4769 r_shadow_selectedlight = light;
4770 if (r_shadow_selectedlight)
4771 r_shadow_selectedlight->selected = true;
4774 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4776 // this is never batched (there can be only one)
4778 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
4779 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4780 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4783 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4788 skinframe_t *skinframe;
4791 // this is never batched (due to the ent parameter changing every time)
4792 // so numsurfaces == 1 and surfacelist[0] == lightnumber
4793 const dlight_t *light = (dlight_t *)ent;
4796 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
4799 VectorScale(light->color, intensity, spritecolor);
4800 if (VectorLength(spritecolor) < 0.1732f)
4801 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
4802 if (VectorLength(spritecolor) > 1.0f)
4803 VectorNormalize(spritecolor);
4805 // draw light sprite
4806 if (light->cubemapname[0] && !light->shadow)
4807 skinframe = r_editlights_sprcubemapnoshadowlight;
4808 else if (light->cubemapname[0])
4809 skinframe = r_editlights_sprcubemaplight;
4810 else if (!light->shadow)
4811 skinframe = r_editlights_sprnoshadowlight;
4813 skinframe = r_editlights_sprlight;
4815 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);
4816 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4818 // draw selection sprite if light is selected
4819 if (light->selected)
4821 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4822 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4823 // VorteX todo: add normalmode/realtime mode light overlay sprites?
4827 void R_Shadow_DrawLightSprites(void)
4831 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4832 for (lightindex = 0;lightindex < range;lightindex++)
4834 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4836 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
4838 if (!r_editlights_lockcursor)
4839 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
4842 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
4847 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
4848 if (lightindex >= range)
4850 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4853 rtlight = &light->rtlight;
4854 //if (!(rtlight->flags & flag))
4856 VectorCopy(rtlight->shadoworigin, origin);
4857 *radius = rtlight->radius;
4858 VectorCopy(rtlight->color, color);
4862 void R_Shadow_SelectLightInView(void)
4864 float bestrating, rating, temp[3];
4868 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4872 if (r_editlights_lockcursor)
4874 for (lightindex = 0;lightindex < range;lightindex++)
4876 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4879 VectorSubtract(light->origin, r_refdef.view.origin, temp);
4880 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
4883 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
4884 if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1.0f)
4886 bestrating = rating;
4891 R_Shadow_SelectLight(best);
4894 void R_Shadow_LoadWorldLights(void)
4896 int n, a, style, shadow, flags;
4897 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
4898 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
4899 if (cl.worldmodel == NULL)
4901 Con_Print("No map loaded.\n");
4904 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
4905 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4915 for (;COM_Parse(t, true) && strcmp(
4916 if (COM_Parse(t, true))
4918 if (com_token[0] == '!')
4921 origin[0] = atof(com_token+1);
4924 origin[0] = atof(com_token);
4929 while (*s && *s != '\n' && *s != '\r')
4935 // check for modifier flags
4942 #if _MSC_VER >= 1400
4943 #define sscanf sscanf_s
4945 cubemapname[sizeof(cubemapname)-1] = 0;
4946 #if MAX_QPATH != 128
4947 #error update this code if MAX_QPATH changes
4949 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
4950 #if _MSC_VER >= 1400
4951 , sizeof(cubemapname)
4953 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
4956 flags = LIGHTFLAG_REALTIMEMODE;
4964 coronasizescale = 0.25f;
4966 VectorClear(angles);
4969 if (a < 9 || !strcmp(cubemapname, "\"\""))
4971 // remove quotes on cubemapname
4972 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
4975 namelen = strlen(cubemapname) - 2;
4976 memmove(cubemapname, cubemapname + 1, namelen);
4977 cubemapname[namelen] = '\0';
4981 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);
4984 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4992 Con_Printf("invalid rtlights file \"%s\"\n", name);
4993 Mem_Free(lightsstring);
4997 void R_Shadow_SaveWorldLights(void)
5001 size_t bufchars, bufmaxchars;
5003 char name[MAX_QPATH];
5004 char line[MAX_INPUTLINE];
5005 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
5006 // I hate lines which are 3 times my screen size :( --blub
5009 if (cl.worldmodel == NULL)
5011 Con_Print("No map loaded.\n");
5014 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
5015 bufchars = bufmaxchars = 0;
5017 for (lightindex = 0;lightindex < range;lightindex++)
5019 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5022 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
5023 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);
5024 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
5025 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]);
5027 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);
5028 if (bufchars + strlen(line) > bufmaxchars)
5030 bufmaxchars = bufchars + strlen(line) + 2048;
5032 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
5036 memcpy(buf, oldbuf, bufchars);
5042 memcpy(buf + bufchars, line, strlen(line));
5043 bufchars += strlen(line);
5047 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
5052 void R_Shadow_LoadLightsFile(void)
5055 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
5056 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
5057 if (cl.worldmodel == NULL)
5059 Con_Print("No map loaded.\n");
5062 dpsnprintf(name, sizeof(name), "%s.lights", cl.worldnamenoextension);
5063 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5071 while (*s && *s != '\n' && *s != '\r')
5077 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);
5081 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);
5084 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
5085 radius = bound(15, radius, 4096);
5086 VectorScale(color, (2.0f / (8388608.0f)), color);
5087 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5095 Con_Printf("invalid lights file \"%s\"\n", name);
5096 Mem_Free(lightsstring);
5100 // tyrlite/hmap2 light types in the delay field
5101 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
5103 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
5115 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
5116 char key[256], value[MAX_INPUTLINE];
5118 if (cl.worldmodel == NULL)
5120 Con_Print("No map loaded.\n");
5123 // try to load a .ent file first
5124 dpsnprintf(key, sizeof(key), "%s.ent", cl.worldnamenoextension);
5125 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
5126 // and if that is not found, fall back to the bsp file entity string
5128 data = cl.worldmodel->brush.entities;
5131 for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
5133 type = LIGHTTYPE_MINUSX;
5134 origin[0] = origin[1] = origin[2] = 0;
5135 originhack[0] = originhack[1] = originhack[2] = 0;
5136 angles[0] = angles[1] = angles[2] = 0;
5137 color[0] = color[1] = color[2] = 1;
5138 light[0] = light[1] = light[2] = 1;light[3] = 300;
5139 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
5149 if (!COM_ParseToken_Simple(&data, false, false))
5151 if (com_token[0] == '}')
5152 break; // end of entity
5153 if (com_token[0] == '_')
5154 strlcpy(key, com_token + 1, sizeof(key));
5156 strlcpy(key, com_token, sizeof(key));
5157 while (key[strlen(key)-1] == ' ') // remove trailing spaces
5158 key[strlen(key)-1] = 0;
5159 if (!COM_ParseToken_Simple(&data, false, false))
5161 strlcpy(value, com_token, sizeof(value));
5163 // now that we have the key pair worked out...
5164 if (!strcmp("light", key))
5166 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5170 light[0] = vec[0] * (1.0f / 256.0f);
5171 light[1] = vec[0] * (1.0f / 256.0f);
5172 light[2] = vec[0] * (1.0f / 256.0f);
5178 light[0] = vec[0] * (1.0f / 255.0f);
5179 light[1] = vec[1] * (1.0f / 255.0f);
5180 light[2] = vec[2] * (1.0f / 255.0f);
5184 else if (!strcmp("delay", key))
5186 else if (!strcmp("origin", key))
5187 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5188 else if (!strcmp("angle", key))
5189 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5190 else if (!strcmp("angles", key))
5191 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5192 else if (!strcmp("color", key))
5193 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5194 else if (!strcmp("wait", key))
5195 fadescale = atof(value);
5196 else if (!strcmp("classname", key))
5198 if (!strncmp(value, "light", 5))
5201 if (!strcmp(value, "light_fluoro"))
5206 overridecolor[0] = 1;
5207 overridecolor[1] = 1;
5208 overridecolor[2] = 1;
5210 if (!strcmp(value, "light_fluorospark"))
5215 overridecolor[0] = 1;
5216 overridecolor[1] = 1;
5217 overridecolor[2] = 1;
5219 if (!strcmp(value, "light_globe"))
5224 overridecolor[0] = 1;
5225 overridecolor[1] = 0.8;
5226 overridecolor[2] = 0.4;
5228 if (!strcmp(value, "light_flame_large_yellow"))
5233 overridecolor[0] = 1;
5234 overridecolor[1] = 0.5;
5235 overridecolor[2] = 0.1;
5237 if (!strcmp(value, "light_flame_small_yellow"))
5242 overridecolor[0] = 1;
5243 overridecolor[1] = 0.5;
5244 overridecolor[2] = 0.1;
5246 if (!strcmp(value, "light_torch_small_white"))
5251 overridecolor[0] = 1;
5252 overridecolor[1] = 0.5;
5253 overridecolor[2] = 0.1;
5255 if (!strcmp(value, "light_torch_small_walltorch"))
5260 overridecolor[0] = 1;
5261 overridecolor[1] = 0.5;
5262 overridecolor[2] = 0.1;
5266 else if (!strcmp("style", key))
5267 style = atoi(value);
5268 else if (!strcmp("skin", key))
5269 skin = (int)atof(value);
5270 else if (!strcmp("pflags", key))
5271 pflags = (int)atof(value);
5272 //else if (!strcmp("effects", key))
5273 // effects = (int)atof(value);
5274 else if (cl.worldmodel->type == mod_brushq3)
5276 if (!strcmp("scale", key))
5277 lightscale = atof(value);
5278 if (!strcmp("fade", key))
5279 fadescale = atof(value);
5284 if (lightscale <= 0)
5288 if (color[0] == color[1] && color[0] == color[2])
5290 color[0] *= overridecolor[0];
5291 color[1] *= overridecolor[1];
5292 color[2] *= overridecolor[2];
5294 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5295 color[0] = color[0] * light[0];
5296 color[1] = color[1] * light[1];
5297 color[2] = color[2] * light[2];
5300 case LIGHTTYPE_MINUSX:
5302 case LIGHTTYPE_RECIPX:
5304 VectorScale(color, (1.0f / 16.0f), color);
5306 case LIGHTTYPE_RECIPXX:
5308 VectorScale(color, (1.0f / 16.0f), color);
5311 case LIGHTTYPE_NONE:
5315 case LIGHTTYPE_MINUSXX:
5318 VectorAdd(origin, originhack, origin);
5320 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);
5323 Mem_Free(entfiledata);
5327 void R_Shadow_SetCursorLocationForView(void)
5330 vec3_t dest, endpos;
5332 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5333 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
5334 if (trace.fraction < 1)
5336 dist = trace.fraction * r_editlights_cursordistance.value;
5337 push = r_editlights_cursorpushback.value;
5341 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5342 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5346 VectorClear( endpos );
5348 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5349 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5350 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5353 void R_Shadow_UpdateWorldLightSelection(void)
5355 if (r_editlights.integer)
5357 R_Shadow_SetCursorLocationForView();
5358 R_Shadow_SelectLightInView();
5361 R_Shadow_SelectLight(NULL);
5364 void R_Shadow_EditLights_Clear_f(void)
5366 R_Shadow_ClearWorldLights();
5369 void R_Shadow_EditLights_Reload_f(void)
5373 strlcpy(r_shadow_mapname, cl.worldname, sizeof(r_shadow_mapname));
5374 R_Shadow_ClearWorldLights();
5375 R_Shadow_LoadWorldLights();
5376 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5378 R_Shadow_LoadLightsFile();
5379 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5380 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5384 void R_Shadow_EditLights_Save_f(void)
5388 R_Shadow_SaveWorldLights();
5391 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
5393 R_Shadow_ClearWorldLights();
5394 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5397 void R_Shadow_EditLights_ImportLightsFile_f(void)
5399 R_Shadow_ClearWorldLights();
5400 R_Shadow_LoadLightsFile();
5403 void R_Shadow_EditLights_Spawn_f(void)
5406 if (!r_editlights.integer)
5408 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5411 if (Cmd_Argc() != 1)
5413 Con_Print("r_editlights_spawn does not take parameters\n");
5416 color[0] = color[1] = color[2] = 1;
5417 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5420 void R_Shadow_EditLights_Edit_f(void)
5422 vec3_t origin, angles, color;
5423 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5424 int style, shadows, flags, normalmode, realtimemode;
5425 char cubemapname[MAX_INPUTLINE];
5426 if (!r_editlights.integer)
5428 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5431 if (!r_shadow_selectedlight)
5433 Con_Print("No selected light.\n");
5436 VectorCopy(r_shadow_selectedlight->origin, origin);
5437 VectorCopy(r_shadow_selectedlight->angles, angles);
5438 VectorCopy(r_shadow_selectedlight->color, color);
5439 radius = r_shadow_selectedlight->radius;
5440 style = r_shadow_selectedlight->style;
5441 if (r_shadow_selectedlight->cubemapname)
5442 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5445 shadows = r_shadow_selectedlight->shadow;
5446 corona = r_shadow_selectedlight->corona;
5447 coronasizescale = r_shadow_selectedlight->coronasizescale;
5448 ambientscale = r_shadow_selectedlight->ambientscale;
5449 diffusescale = r_shadow_selectedlight->diffusescale;
5450 specularscale = r_shadow_selectedlight->specularscale;
5451 flags = r_shadow_selectedlight->flags;
5452 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5453 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5454 if (!strcmp(Cmd_Argv(1), "origin"))
5456 if (Cmd_Argc() != 5)
5458 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5461 origin[0] = atof(Cmd_Argv(2));
5462 origin[1] = atof(Cmd_Argv(3));
5463 origin[2] = atof(Cmd_Argv(4));
5465 else if (!strcmp(Cmd_Argv(1), "originx"))
5467 if (Cmd_Argc() != 3)
5469 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5472 origin[0] = atof(Cmd_Argv(2));
5474 else if (!strcmp(Cmd_Argv(1), "originy"))
5476 if (Cmd_Argc() != 3)
5478 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5481 origin[1] = atof(Cmd_Argv(2));
5483 else if (!strcmp(Cmd_Argv(1), "originz"))
5485 if (Cmd_Argc() != 3)
5487 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5490 origin[2] = atof(Cmd_Argv(2));
5492 else if (!strcmp(Cmd_Argv(1), "move"))
5494 if (Cmd_Argc() != 5)
5496 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5499 origin[0] += atof(Cmd_Argv(2));
5500 origin[1] += atof(Cmd_Argv(3));
5501 origin[2] += atof(Cmd_Argv(4));
5503 else if (!strcmp(Cmd_Argv(1), "movex"))
5505 if (Cmd_Argc() != 3)
5507 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5510 origin[0] += atof(Cmd_Argv(2));
5512 else if (!strcmp(Cmd_Argv(1), "movey"))
5514 if (Cmd_Argc() != 3)
5516 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5519 origin[1] += atof(Cmd_Argv(2));
5521 else if (!strcmp(Cmd_Argv(1), "movez"))
5523 if (Cmd_Argc() != 3)
5525 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5528 origin[2] += atof(Cmd_Argv(2));
5530 else if (!strcmp(Cmd_Argv(1), "angles"))
5532 if (Cmd_Argc() != 5)
5534 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5537 angles[0] = atof(Cmd_Argv(2));
5538 angles[1] = atof(Cmd_Argv(3));
5539 angles[2] = atof(Cmd_Argv(4));
5541 else if (!strcmp(Cmd_Argv(1), "anglesx"))
5543 if (Cmd_Argc() != 3)
5545 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5548 angles[0] = atof(Cmd_Argv(2));
5550 else if (!strcmp(Cmd_Argv(1), "anglesy"))
5552 if (Cmd_Argc() != 3)
5554 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5557 angles[1] = atof(Cmd_Argv(2));
5559 else if (!strcmp(Cmd_Argv(1), "anglesz"))
5561 if (Cmd_Argc() != 3)
5563 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5566 angles[2] = atof(Cmd_Argv(2));
5568 else if (!strcmp(Cmd_Argv(1), "color"))
5570 if (Cmd_Argc() != 5)
5572 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
5575 color[0] = atof(Cmd_Argv(2));
5576 color[1] = atof(Cmd_Argv(3));
5577 color[2] = atof(Cmd_Argv(4));
5579 else if (!strcmp(Cmd_Argv(1), "radius"))
5581 if (Cmd_Argc() != 3)
5583 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5586 radius = atof(Cmd_Argv(2));
5588 else if (!strcmp(Cmd_Argv(1), "colorscale"))
5590 if (Cmd_Argc() == 3)
5592 double scale = atof(Cmd_Argv(2));
5599 if (Cmd_Argc() != 5)
5601 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
5604 color[0] *= atof(Cmd_Argv(2));
5605 color[1] *= atof(Cmd_Argv(3));
5606 color[2] *= atof(Cmd_Argv(4));
5609 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
5611 if (Cmd_Argc() != 3)
5613 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5616 radius *= atof(Cmd_Argv(2));
5618 else if (!strcmp(Cmd_Argv(1), "style"))
5620 if (Cmd_Argc() != 3)
5622 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5625 style = atoi(Cmd_Argv(2));
5627 else if (!strcmp(Cmd_Argv(1), "cubemap"))
5631 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5634 if (Cmd_Argc() == 3)
5635 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
5639 else if (!strcmp(Cmd_Argv(1), "shadows"))
5641 if (Cmd_Argc() != 3)
5643 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5646 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5648 else if (!strcmp(Cmd_Argv(1), "corona"))
5650 if (Cmd_Argc() != 3)
5652 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5655 corona = atof(Cmd_Argv(2));
5657 else if (!strcmp(Cmd_Argv(1), "coronasize"))
5659 if (Cmd_Argc() != 3)
5661 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5664 coronasizescale = atof(Cmd_Argv(2));
5666 else if (!strcmp(Cmd_Argv(1), "ambient"))
5668 if (Cmd_Argc() != 3)
5670 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5673 ambientscale = atof(Cmd_Argv(2));
5675 else if (!strcmp(Cmd_Argv(1), "diffuse"))
5677 if (Cmd_Argc() != 3)
5679 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5682 diffusescale = atof(Cmd_Argv(2));
5684 else if (!strcmp(Cmd_Argv(1), "specular"))
5686 if (Cmd_Argc() != 3)
5688 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5691 specularscale = atof(Cmd_Argv(2));
5693 else if (!strcmp(Cmd_Argv(1), "normalmode"))
5695 if (Cmd_Argc() != 3)
5697 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5700 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5702 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
5704 if (Cmd_Argc() != 3)
5706 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5709 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5713 Con_Print("usage: r_editlights_edit [property] [value]\n");
5714 Con_Print("Selected light's properties:\n");
5715 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5716 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5717 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5718 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
5719 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
5720 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
5721 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5722 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
5723 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
5724 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
5725 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
5726 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
5727 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5728 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5731 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5732 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5735 void R_Shadow_EditLights_EditAll_f(void)
5738 dlight_t *light, *oldselected;
5741 if (!r_editlights.integer)
5743 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5747 oldselected = r_shadow_selectedlight;
5748 // EditLights doesn't seem to have a "remove" command or something so:
5749 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5750 for (lightindex = 0;lightindex < range;lightindex++)
5752 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5755 R_Shadow_SelectLight(light);
5756 R_Shadow_EditLights_Edit_f();
5758 // return to old selected (to not mess editing once selection is locked)
5759 R_Shadow_SelectLight(oldselected);
5762 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
5764 int lightnumber, lightcount;
5765 size_t lightindex, range;
5769 if (!r_editlights.integer)
5771 x = vid_conwidth.value - 240;
5773 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
5776 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5777 for (lightindex = 0;lightindex < range;lightindex++)
5779 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5782 if (light == r_shadow_selectedlight)
5783 lightnumber = lightindex;
5786 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;
5787 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;
5789 if (r_shadow_selectedlight == NULL)
5791 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;
5792 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;
5793 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;
5794 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;
5795 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;
5796 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;
5797 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;
5798 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;
5799 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;
5800 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;
5801 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;
5802 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;
5803 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;
5804 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;
5805 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;
5808 void R_Shadow_EditLights_ToggleShadow_f(void)
5810 if (!r_editlights.integer)
5812 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5815 if (!r_shadow_selectedlight)
5817 Con_Print("No selected light.\n");
5820 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);
5823 void R_Shadow_EditLights_ToggleCorona_f(void)
5825 if (!r_editlights.integer)
5827 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5830 if (!r_shadow_selectedlight)
5832 Con_Print("No selected light.\n");
5835 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);
5838 void R_Shadow_EditLights_Remove_f(void)
5840 if (!r_editlights.integer)
5842 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
5845 if (!r_shadow_selectedlight)
5847 Con_Print("No selected light.\n");
5850 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
5851 r_shadow_selectedlight = NULL;
5854 void R_Shadow_EditLights_Help_f(void)
5857 "Documentation on r_editlights system:\n"
5859 "r_editlights : enable/disable editing mode\n"
5860 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
5861 "r_editlights_cursorpushback : push back cursor this far from surface\n"
5862 "r_editlights_cursorpushoff : push cursor off surface this far\n"
5863 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
5864 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
5866 "r_editlights_help : this help\n"
5867 "r_editlights_clear : remove all lights\n"
5868 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
5869 "r_editlights_lock : lock selection to current light, if already locked - unlock\n"
5870 "r_editlights_save : save to .rtlights file\n"
5871 "r_editlights_spawn : create a light with default settings\n"
5872 "r_editlights_edit command : edit selected light - more documentation below\n"
5873 "r_editlights_remove : remove selected light\n"
5874 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
5875 "r_editlights_importlightentitiesfrommap : reload light entities\n"
5876 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
5878 "origin x y z : set light location\n"
5879 "originx x: set x component of light location\n"
5880 "originy y: set y component of light location\n"
5881 "originz z: set z component of light location\n"
5882 "move x y z : adjust light location\n"
5883 "movex x: adjust x component of light location\n"
5884 "movey y: adjust y component of light location\n"
5885 "movez z: adjust z component of light location\n"
5886 "angles x y z : set light angles\n"
5887 "anglesx x: set x component of light angles\n"
5888 "anglesy y: set y component of light angles\n"
5889 "anglesz z: set z component of light angles\n"
5890 "color r g b : set color of light (can be brighter than 1 1 1)\n"
5891 "radius radius : set radius (size) of light\n"
5892 "colorscale grey : multiply color of light (1 does nothing)\n"
5893 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
5894 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
5895 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
5896 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
5897 "cubemap basename : set filter cubemap of light (not yet supported)\n"
5898 "shadows 1/0 : turn on/off shadows\n"
5899 "corona n : set corona intensity\n"
5900 "coronasize n : set corona size (0-1)\n"
5901 "ambient n : set ambient intensity (0-1)\n"
5902 "diffuse n : set diffuse intensity (0-1)\n"
5903 "specular n : set specular intensity (0-1)\n"
5904 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
5905 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
5906 "<nothing> : print light properties to console\n"
5910 void R_Shadow_EditLights_CopyInfo_f(void)
5912 if (!r_editlights.integer)
5914 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
5917 if (!r_shadow_selectedlight)
5919 Con_Print("No selected light.\n");
5922 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
5923 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
5924 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
5925 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
5926 if (r_shadow_selectedlight->cubemapname)
5927 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
5929 r_shadow_bufferlight.cubemapname[0] = 0;
5930 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
5931 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
5932 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
5933 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
5934 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
5935 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
5936 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
5939 void R_Shadow_EditLights_PasteInfo_f(void)
5941 if (!r_editlights.integer)
5943 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
5946 if (!r_shadow_selectedlight)
5948 Con_Print("No selected light.\n");
5951 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);
5954 void R_Shadow_EditLights_Lock_f(void)
5956 if (!r_editlights.integer)
5958 Con_Print("Cannot lock on light when not in editing mode. Set r_editlights to 1.\n");
5961 if (r_editlights_lockcursor)
5963 r_editlights_lockcursor = false;
5966 if (!r_shadow_selectedlight)
5968 Con_Print("No selected light to lock on.\n");
5971 r_editlights_lockcursor = true;
5974 void R_Shadow_EditLights_Init(void)
5976 Cvar_RegisterVariable(&r_editlights);
5977 Cvar_RegisterVariable(&r_editlights_cursordistance);
5978 Cvar_RegisterVariable(&r_editlights_cursorpushback);
5979 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
5980 Cvar_RegisterVariable(&r_editlights_cursorgrid);
5981 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
5982 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
5983 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
5984 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)");
5985 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
5986 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
5987 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
5988 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)");
5989 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
5990 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
5991 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
5992 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
5993 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
5994 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
5995 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)");
5996 Cmd_AddCommand("r_editlights_lock", R_Shadow_EditLights_Lock_f, "lock selection to current light, if already locked - unlock");
6002 =============================================================================
6006 =============================================================================
6009 void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, const int flags)
6011 int i, numlights, flag;
6012 float f, relativepoint[3], dist, dist2, lightradius2;
6016 VectorClear(diffusecolor);
6017 VectorClear(diffusenormal);
6019 if (flags & LP_LIGHTMAP)
6021 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
6023 ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_refdef.scene.ambient;
6024 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
6027 VectorSet(ambientcolor, 1, 1, 1);
6029 if (flags & LP_RTWORLD)
6031 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
6032 numlights = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
6033 for (i = 0; i < numlights; i++)
6035 dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
6038 light = &dlight->rtlight;
6039 if (!(light->flags & flag))
6042 lightradius2 = light->radius * light->radius;
6043 VectorSubtract(light->shadoworigin, p, relativepoint);
6044 dist2 = VectorLength2(relativepoint);
6045 if (dist2 >= lightradius2)
6047 dist = sqrt(dist2) / light->radius;
6048 f = dist < 1 ? (r_shadow_lightintensityscale.value * ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist))) : 0;
6051 // todo: add to both ambient and diffuse
6052 if (!light->shadow || CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
6053 VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);
6056 if (flags & LP_DYNLIGHT)
6059 for (i = 0;i < r_refdef.scene.numlights;i++)
6061 light = r_refdef.scene.lights[i];
6063 lightradius2 = light->radius * light->radius;
6064 VectorSubtract(light->shadoworigin, p, relativepoint);
6065 dist2 = VectorLength2(relativepoint);
6066 if (dist2 >= lightradius2)
6068 dist = sqrt(dist2) / light->radius;
6069 f = dist < 1 ? (r_shadow_lightintensityscale.value * ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist))) : 0;
6072 // todo: add to both ambient and diffuse
6073 if (!light->shadow || CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
6074 VectorMA(ambientcolor, f, light->color, ambientcolor);