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_usenormalmap = {CVAR_SAVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"};
277 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)"};
278 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"};
279 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
280 cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
281 cvar_t r_shadow_gloss2exponent = {0, "r_shadow_gloss2exponent", "32", "same as r_shadow_glossexponent but for forced gloss (gloss 2) surfaces"};
282 cvar_t r_shadow_glossexact = {0, "r_shadow_glossexact", "0", "use exact reflection math for gloss (slightly slower, but should look a tad better)"};
283 cvar_t r_shadow_lightattenuationdividebias = {0, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"};
284 cvar_t r_shadow_lightattenuationlinearscale = {0, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"};
285 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
286 cvar_t r_shadow_lightradiusscale = {0, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
287 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "0", "how far to cast shadows"};
288 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)"};
289 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
290 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
291 cvar_t r_shadow_realtime_dlight_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
292 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
293 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)"};
294 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"};
295 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
296 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
297 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"};
298 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)"};
299 cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "0", "enables portal-based culling optimization during compilation (overrides compilesvbsp)"};
300 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)"};
301 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"};
302 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)"};
303 cvar_t r_shadow_shadowmapping_depthbits = {CVAR_SAVE, "r_shadow_shadowmapping_depthbits", "24", "requested minimum shadowmap texture depth bits"};
304 cvar_t r_shadow_shadowmapping_vsdct = {CVAR_SAVE, "r_shadow_shadowmapping_vsdct", "1", "enables use of virtual shadow depth cube texture"};
305 cvar_t r_shadow_shadowmapping_minsize = {CVAR_SAVE, "r_shadow_shadowmapping_minsize", "32", "shadowmap size limit"};
306 cvar_t r_shadow_shadowmapping_maxsize = {CVAR_SAVE, "r_shadow_shadowmapping_maxsize", "512", "shadowmap size limit"};
307 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"};
308 //cvar_t r_shadow_shadowmapping_lod_bias = {CVAR_SAVE, "r_shadow_shadowmapping_lod_bias", "16", "shadowmap size bias"};
309 //cvar_t r_shadow_shadowmapping_lod_scale = {CVAR_SAVE, "r_shadow_shadowmapping_lod_scale", "128", "shadowmap size scaling parameter"};
310 cvar_t r_shadow_shadowmapping_bordersize = {CVAR_SAVE, "r_shadow_shadowmapping_bordersize", "4", "shadowmap size bias for filtering"};
311 cvar_t r_shadow_shadowmapping_nearclip = {CVAR_SAVE, "r_shadow_shadowmapping_nearclip", "1", "shadowmap nearclip in world units"};
312 cvar_t r_shadow_shadowmapping_bias = {CVAR_SAVE, "r_shadow_shadowmapping_bias", "0.03", "shadowmap bias parameter (this is multiplied by nearclip * 1024 / lodsize)"};
313 cvar_t r_shadow_shadowmapping_polygonfactor = {CVAR_SAVE, "r_shadow_shadowmapping_polygonfactor", "2", "slope-dependent shadowmapping bias"};
314 cvar_t r_shadow_shadowmapping_polygonoffset = {CVAR_SAVE, "r_shadow_shadowmapping_polygonoffset", "0", "constant shadowmapping bias"};
315 cvar_t r_shadow_sortsurfaces = {0, "r_shadow_sortsurfaces", "1", "improve performance by sorting illuminated surfaces by texture"};
316 cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
317 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)"};
318 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)"};
319 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "1", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
320 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"};
321 cvar_t r_coronas_occlusionquery = {CVAR_SAVE, "r_coronas_occlusionquery", "1", "use GL_ARB_occlusion_query extension if supported (fades coronas according to visibility)"};
322 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
323 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
324 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
325 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
326 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
327 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
328 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
329 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
330 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
332 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
333 #define ATTENTABLESIZE 256
334 // 1D gradient, 2D circle and 3D sphere attenuation textures
335 #define ATTEN1DSIZE 32
336 #define ATTEN2DSIZE 64
337 #define ATTEN3DSIZE 32
339 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
340 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
341 static float r_shadow_attentable[ATTENTABLESIZE+1];
343 rtlight_t *r_shadow_compilingrtlight;
344 static memexpandablearray_t r_shadow_worldlightsarray;
345 dlight_t *r_shadow_selectedlight;
346 dlight_t r_shadow_bufferlight;
347 vec3_t r_editlights_cursorlocation;
348 qboolean r_editlights_lockcursor;
350 extern int con_vislines;
352 void R_Shadow_UncompileWorldLights(void);
353 void R_Shadow_ClearWorldLights(void);
354 void R_Shadow_SaveWorldLights(void);
355 void R_Shadow_LoadWorldLights(void);
356 void R_Shadow_LoadLightsFile(void);
357 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
358 void R_Shadow_EditLights_Reload_f(void);
359 void R_Shadow_ValidateCvars(void);
360 static void R_Shadow_MakeTextures(void);
362 #define EDLIGHTSPRSIZE 8
363 skinframe_t *r_editlights_sprcursor;
364 skinframe_t *r_editlights_sprlight;
365 skinframe_t *r_editlights_sprnoshadowlight;
366 skinframe_t *r_editlights_sprcubemaplight;
367 skinframe_t *r_editlights_sprcubemapnoshadowlight;
368 skinframe_t *r_editlights_sprselection;
370 void R_Shadow_SetShadowMode(void)
372 r_shadow_shadowmapmaxsize = bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4);
373 r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20;
374 r_shadow_shadowmapfilterquality = r_shadow_shadowmapping_filterquality.integer;
375 r_shadow_shadowmapdepthbits = r_shadow_shadowmapping_depthbits.integer;
376 r_shadow_shadowmapborder = bound(0, r_shadow_shadowmapping_bordersize.integer, 16);
377 r_shadow_shadowmaplod = -1;
378 r_shadow_shadowmapsize = 0;
379 r_shadow_shadowmapsampler = false;
380 r_shadow_shadowmappcf = 0;
381 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
382 if ((r_shadow_shadowmapping.integer || r_shadow_deferred.integer) && vid.support.ext_framebuffer_object)
384 switch(vid.renderpath)
386 case RENDERPATH_GL20:
387 if(r_shadow_shadowmapfilterquality < 0)
389 if(vid.support.amd_texture_texture4 || vid.support.arb_texture_gather)
390 r_shadow_shadowmappcf = 1;
391 else if(strstr(gl_vendor, "NVIDIA") || strstr(gl_renderer, "Radeon HD"))
393 r_shadow_shadowmapsampler = vid.support.arb_shadow;
394 r_shadow_shadowmappcf = 1;
396 else if(strstr(gl_vendor, "ATI"))
397 r_shadow_shadowmappcf = 1;
399 r_shadow_shadowmapsampler = vid.support.arb_shadow;
403 switch (r_shadow_shadowmapfilterquality)
406 r_shadow_shadowmapsampler = vid.support.arb_shadow;
409 r_shadow_shadowmapsampler = vid.support.arb_shadow;
410 r_shadow_shadowmappcf = 1;
413 r_shadow_shadowmappcf = 1;
416 r_shadow_shadowmappcf = 2;
420 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
421 // Cg has very little choice in depth texture sampling
423 r_shadow_shadowmapsampler = false;
425 case RENDERPATH_CGGL:
426 case RENDERPATH_D3D9:
427 case RENDERPATH_D3D10:
428 case RENDERPATH_D3D11:
429 r_shadow_shadowmapsampler = false;
430 r_shadow_shadowmappcf = 1;
431 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
433 case RENDERPATH_GL13:
435 case RENDERPATH_GL11:
441 qboolean R_Shadow_ShadowMappingEnabled(void)
443 switch (r_shadow_shadowmode)
445 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
452 void R_Shadow_FreeShadowMaps(void)
454 R_Shadow_SetShadowMode();
456 R_Mesh_DestroyFramebufferObject(r_shadow_fbo2d);
460 if (r_shadow_shadowmap2dtexture)
461 R_FreeTexture(r_shadow_shadowmap2dtexture);
462 r_shadow_shadowmap2dtexture = NULL;
464 if (r_shadow_shadowmap2dcolortexture)
465 R_FreeTexture(r_shadow_shadowmap2dcolortexture);
466 r_shadow_shadowmap2dcolortexture = NULL;
468 if (r_shadow_shadowmapvsdcttexture)
469 R_FreeTexture(r_shadow_shadowmapvsdcttexture);
470 r_shadow_shadowmapvsdcttexture = NULL;
473 void r_shadow_start(void)
475 // allocate vertex processing arrays
476 r_shadow_attenuationgradienttexture = NULL;
477 r_shadow_attenuation2dtexture = NULL;
478 r_shadow_attenuation3dtexture = NULL;
479 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
480 r_shadow_shadowmap2dtexture = NULL;
481 r_shadow_shadowmap2dcolortexture = NULL;
482 r_shadow_shadowmapvsdcttexture = NULL;
483 r_shadow_shadowmapmaxsize = 0;
484 r_shadow_shadowmapsize = 0;
485 r_shadow_shadowmaplod = 0;
486 r_shadow_shadowmapfilterquality = -1;
487 r_shadow_shadowmapdepthbits = 0;
488 r_shadow_shadowmapvsdct = false;
489 r_shadow_shadowmapsampler = false;
490 r_shadow_shadowmappcf = 0;
493 R_Shadow_FreeShadowMaps();
495 r_shadow_texturepool = NULL;
496 r_shadow_filters_texturepool = NULL;
497 R_Shadow_ValidateCvars();
498 R_Shadow_MakeTextures();
499 maxshadowtriangles = 0;
500 shadowelements = NULL;
501 maxshadowvertices = 0;
502 shadowvertex3f = NULL;
510 shadowmarklist = NULL;
515 shadowsideslist = NULL;
516 r_shadow_buffer_numleafpvsbytes = 0;
517 r_shadow_buffer_visitingleafpvs = NULL;
518 r_shadow_buffer_leafpvs = NULL;
519 r_shadow_buffer_leaflist = NULL;
520 r_shadow_buffer_numsurfacepvsbytes = 0;
521 r_shadow_buffer_surfacepvs = NULL;
522 r_shadow_buffer_surfacelist = NULL;
523 r_shadow_buffer_surfacesides = NULL;
524 r_shadow_buffer_numshadowtrispvsbytes = 0;
525 r_shadow_buffer_shadowtrispvs = NULL;
526 r_shadow_buffer_numlighttrispvsbytes = 0;
527 r_shadow_buffer_lighttrispvs = NULL;
529 r_shadow_usingdeferredprepass = false;
530 r_shadow_prepass_width = r_shadow_prepass_height = 0;
533 static void R_Shadow_FreeDeferred(void);
534 void r_shadow_shutdown(void)
537 R_Shadow_UncompileWorldLights();
539 R_Shadow_FreeShadowMaps();
541 r_shadow_usingdeferredprepass = false;
542 if (r_shadow_prepass_width)
543 R_Shadow_FreeDeferred();
544 r_shadow_prepass_width = r_shadow_prepass_height = 0;
547 r_shadow_attenuationgradienttexture = NULL;
548 r_shadow_attenuation2dtexture = NULL;
549 r_shadow_attenuation3dtexture = NULL;
550 R_FreeTexturePool(&r_shadow_texturepool);
551 R_FreeTexturePool(&r_shadow_filters_texturepool);
552 maxshadowtriangles = 0;
554 Mem_Free(shadowelements);
555 shadowelements = NULL;
557 Mem_Free(shadowvertex3f);
558 shadowvertex3f = NULL;
561 Mem_Free(vertexupdate);
564 Mem_Free(vertexremap);
570 Mem_Free(shadowmark);
573 Mem_Free(shadowmarklist);
574 shadowmarklist = NULL;
579 Mem_Free(shadowsides);
582 Mem_Free(shadowsideslist);
583 shadowsideslist = NULL;
584 r_shadow_buffer_numleafpvsbytes = 0;
585 if (r_shadow_buffer_visitingleafpvs)
586 Mem_Free(r_shadow_buffer_visitingleafpvs);
587 r_shadow_buffer_visitingleafpvs = NULL;
588 if (r_shadow_buffer_leafpvs)
589 Mem_Free(r_shadow_buffer_leafpvs);
590 r_shadow_buffer_leafpvs = NULL;
591 if (r_shadow_buffer_leaflist)
592 Mem_Free(r_shadow_buffer_leaflist);
593 r_shadow_buffer_leaflist = NULL;
594 r_shadow_buffer_numsurfacepvsbytes = 0;
595 if (r_shadow_buffer_surfacepvs)
596 Mem_Free(r_shadow_buffer_surfacepvs);
597 r_shadow_buffer_surfacepvs = NULL;
598 if (r_shadow_buffer_surfacelist)
599 Mem_Free(r_shadow_buffer_surfacelist);
600 r_shadow_buffer_surfacelist = NULL;
601 if (r_shadow_buffer_surfacesides)
602 Mem_Free(r_shadow_buffer_surfacesides);
603 r_shadow_buffer_surfacesides = NULL;
604 r_shadow_buffer_numshadowtrispvsbytes = 0;
605 if (r_shadow_buffer_shadowtrispvs)
606 Mem_Free(r_shadow_buffer_shadowtrispvs);
607 r_shadow_buffer_numlighttrispvsbytes = 0;
608 if (r_shadow_buffer_lighttrispvs)
609 Mem_Free(r_shadow_buffer_lighttrispvs);
612 void r_shadow_newmap(void)
614 if (r_shadow_lightcorona) R_SkinFrame_MarkUsed(r_shadow_lightcorona);
615 if (r_editlights_sprcursor) R_SkinFrame_MarkUsed(r_editlights_sprcursor);
616 if (r_editlights_sprlight) R_SkinFrame_MarkUsed(r_editlights_sprlight);
617 if (r_editlights_sprnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprnoshadowlight);
618 if (r_editlights_sprcubemaplight) R_SkinFrame_MarkUsed(r_editlights_sprcubemaplight);
619 if (r_editlights_sprcubemapnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprcubemapnoshadowlight);
620 if (r_editlights_sprselection) R_SkinFrame_MarkUsed(r_editlights_sprselection);
621 if (strncmp(cl.worldname, r_shadow_mapname, sizeof(r_shadow_mapname)))
622 R_Shadow_EditLights_Reload_f();
625 void R_Shadow_Init(void)
627 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
628 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
629 Cvar_RegisterVariable(&r_shadow_usenormalmap);
630 Cvar_RegisterVariable(&r_shadow_debuglight);
631 Cvar_RegisterVariable(&r_shadow_deferred);
632 Cvar_RegisterVariable(&r_shadow_deferred_8bitrange);
633 // Cvar_RegisterVariable(&r_shadow_deferred_fp);
634 Cvar_RegisterVariable(&r_shadow_gloss);
635 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
636 Cvar_RegisterVariable(&r_shadow_glossintensity);
637 Cvar_RegisterVariable(&r_shadow_glossexponent);
638 Cvar_RegisterVariable(&r_shadow_gloss2exponent);
639 Cvar_RegisterVariable(&r_shadow_glossexact);
640 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
641 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
642 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
643 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
644 Cvar_RegisterVariable(&r_shadow_projectdistance);
645 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
646 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
647 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
648 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
649 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
650 Cvar_RegisterVariable(&r_shadow_realtime_world);
651 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
652 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
653 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
654 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
655 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
656 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
657 Cvar_RegisterVariable(&r_shadow_scissor);
658 Cvar_RegisterVariable(&r_shadow_shadowmapping);
659 Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
660 Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
661 Cvar_RegisterVariable(&r_shadow_shadowmapping_depthbits);
662 Cvar_RegisterVariable(&r_shadow_shadowmapping_precision);
663 Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
664 Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
665 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
666 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
667 Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
668 Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
669 Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
670 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonfactor);
671 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonoffset);
672 Cvar_RegisterVariable(&r_shadow_sortsurfaces);
673 Cvar_RegisterVariable(&r_shadow_polygonfactor);
674 Cvar_RegisterVariable(&r_shadow_polygonoffset);
675 Cvar_RegisterVariable(&r_shadow_texture3d);
676 Cvar_RegisterVariable(&r_coronas);
677 Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
678 Cvar_RegisterVariable(&r_coronas_occlusionquery);
679 Cvar_RegisterVariable(&gl_flashblend);
680 Cvar_RegisterVariable(&gl_ext_separatestencil);
681 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
682 if (gamemode == GAME_TENEBRAE)
684 Cvar_SetValue("r_shadow_gloss", 2);
685 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
687 R_Shadow_EditLights_Init();
688 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
689 maxshadowtriangles = 0;
690 shadowelements = NULL;
691 maxshadowvertices = 0;
692 shadowvertex3f = NULL;
700 shadowmarklist = NULL;
705 shadowsideslist = NULL;
706 r_shadow_buffer_numleafpvsbytes = 0;
707 r_shadow_buffer_visitingleafpvs = NULL;
708 r_shadow_buffer_leafpvs = NULL;
709 r_shadow_buffer_leaflist = NULL;
710 r_shadow_buffer_numsurfacepvsbytes = 0;
711 r_shadow_buffer_surfacepvs = NULL;
712 r_shadow_buffer_surfacelist = NULL;
713 r_shadow_buffer_surfacesides = NULL;
714 r_shadow_buffer_shadowtrispvs = NULL;
715 r_shadow_buffer_lighttrispvs = NULL;
716 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap, NULL, NULL);
719 matrix4x4_t matrix_attenuationxyz =
722 {0.5, 0.0, 0.0, 0.5},
723 {0.0, 0.5, 0.0, 0.5},
724 {0.0, 0.0, 0.5, 0.5},
729 matrix4x4_t matrix_attenuationz =
732 {0.0, 0.0, 0.5, 0.5},
733 {0.0, 0.0, 0.0, 0.5},
734 {0.0, 0.0, 0.0, 0.5},
739 void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles, int vertscale, int triscale)
741 numvertices = ((numvertices + 255) & ~255) * vertscale;
742 numtriangles = ((numtriangles + 255) & ~255) * triscale;
743 // make sure shadowelements is big enough for this volume
744 if (maxshadowtriangles < numtriangles)
746 maxshadowtriangles = numtriangles;
748 Mem_Free(shadowelements);
749 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[3]));
751 // make sure shadowvertex3f is big enough for this volume
752 if (maxshadowvertices < numvertices)
754 maxshadowvertices = numvertices;
756 Mem_Free(shadowvertex3f);
757 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[3]));
761 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
763 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
764 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
765 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
766 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
767 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
769 if (r_shadow_buffer_visitingleafpvs)
770 Mem_Free(r_shadow_buffer_visitingleafpvs);
771 if (r_shadow_buffer_leafpvs)
772 Mem_Free(r_shadow_buffer_leafpvs);
773 if (r_shadow_buffer_leaflist)
774 Mem_Free(r_shadow_buffer_leaflist);
775 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
776 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
777 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
778 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
780 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
782 if (r_shadow_buffer_surfacepvs)
783 Mem_Free(r_shadow_buffer_surfacepvs);
784 if (r_shadow_buffer_surfacelist)
785 Mem_Free(r_shadow_buffer_surfacelist);
786 if (r_shadow_buffer_surfacesides)
787 Mem_Free(r_shadow_buffer_surfacesides);
788 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
789 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
790 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
791 r_shadow_buffer_surfacesides = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
793 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
795 if (r_shadow_buffer_shadowtrispvs)
796 Mem_Free(r_shadow_buffer_shadowtrispvs);
797 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
798 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
800 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
802 if (r_shadow_buffer_lighttrispvs)
803 Mem_Free(r_shadow_buffer_lighttrispvs);
804 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
805 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
809 void R_Shadow_PrepareShadowMark(int numtris)
811 // make sure shadowmark is big enough for this volume
812 if (maxshadowmark < numtris)
814 maxshadowmark = numtris;
816 Mem_Free(shadowmark);
818 Mem_Free(shadowmarklist);
819 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
820 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
824 // if shadowmarkcount wrapped we clear the array and adjust accordingly
825 if (shadowmarkcount == 0)
828 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
833 void R_Shadow_PrepareShadowSides(int numtris)
835 if (maxshadowsides < numtris)
837 maxshadowsides = numtris;
839 Mem_Free(shadowsides);
841 Mem_Free(shadowsideslist);
842 shadowsides = (unsigned char *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsides));
843 shadowsideslist = (int *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsideslist));
848 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)
851 int outtriangles = 0, outvertices = 0;
854 float ratio, direction[3], projectvector[3];
856 if (projectdirection)
857 VectorScale(projectdirection, projectdistance, projectvector);
859 VectorClear(projectvector);
861 // create the vertices
862 if (projectdirection)
864 for (i = 0;i < numshadowmarktris;i++)
866 element = inelement3i + shadowmarktris[i] * 3;
867 for (j = 0;j < 3;j++)
869 if (vertexupdate[element[j]] != vertexupdatenum)
871 vertexupdate[element[j]] = vertexupdatenum;
872 vertexremap[element[j]] = outvertices;
873 vertex = invertex3f + element[j] * 3;
874 // project one copy of the vertex according to projectvector
875 VectorCopy(vertex, outvertex3f);
876 VectorAdd(vertex, projectvector, (outvertex3f + 3));
885 for (i = 0;i < numshadowmarktris;i++)
887 element = inelement3i + shadowmarktris[i] * 3;
888 for (j = 0;j < 3;j++)
890 if (vertexupdate[element[j]] != vertexupdatenum)
892 vertexupdate[element[j]] = vertexupdatenum;
893 vertexremap[element[j]] = outvertices;
894 vertex = invertex3f + element[j] * 3;
895 // project one copy of the vertex to the sphere radius of the light
896 // (FIXME: would projecting it to the light box be better?)
897 VectorSubtract(vertex, projectorigin, direction);
898 ratio = projectdistance / VectorLength(direction);
899 VectorCopy(vertex, outvertex3f);
900 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
908 if (r_shadow_frontsidecasting.integer)
910 for (i = 0;i < numshadowmarktris;i++)
912 int remappedelement[3];
914 const int *neighbortriangle;
916 markindex = shadowmarktris[i] * 3;
917 element = inelement3i + markindex;
918 neighbortriangle = inneighbor3i + markindex;
919 // output the front and back triangles
920 outelement3i[0] = vertexremap[element[0]];
921 outelement3i[1] = vertexremap[element[1]];
922 outelement3i[2] = vertexremap[element[2]];
923 outelement3i[3] = vertexremap[element[2]] + 1;
924 outelement3i[4] = vertexremap[element[1]] + 1;
925 outelement3i[5] = vertexremap[element[0]] + 1;
929 // output the sides (facing outward from this triangle)
930 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
932 remappedelement[0] = vertexremap[element[0]];
933 remappedelement[1] = vertexremap[element[1]];
934 outelement3i[0] = remappedelement[1];
935 outelement3i[1] = remappedelement[0];
936 outelement3i[2] = remappedelement[0] + 1;
937 outelement3i[3] = remappedelement[1];
938 outelement3i[4] = remappedelement[0] + 1;
939 outelement3i[5] = remappedelement[1] + 1;
944 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
946 remappedelement[1] = vertexremap[element[1]];
947 remappedelement[2] = vertexremap[element[2]];
948 outelement3i[0] = remappedelement[2];
949 outelement3i[1] = remappedelement[1];
950 outelement3i[2] = remappedelement[1] + 1;
951 outelement3i[3] = remappedelement[2];
952 outelement3i[4] = remappedelement[1] + 1;
953 outelement3i[5] = remappedelement[2] + 1;
958 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
960 remappedelement[0] = vertexremap[element[0]];
961 remappedelement[2] = vertexremap[element[2]];
962 outelement3i[0] = remappedelement[0];
963 outelement3i[1] = remappedelement[2];
964 outelement3i[2] = remappedelement[2] + 1;
965 outelement3i[3] = remappedelement[0];
966 outelement3i[4] = remappedelement[2] + 1;
967 outelement3i[5] = remappedelement[0] + 1;
976 for (i = 0;i < numshadowmarktris;i++)
978 int remappedelement[3];
980 const int *neighbortriangle;
982 markindex = shadowmarktris[i] * 3;
983 element = inelement3i + markindex;
984 neighbortriangle = inneighbor3i + markindex;
985 // output the front and back triangles
986 outelement3i[0] = vertexremap[element[2]];
987 outelement3i[1] = vertexremap[element[1]];
988 outelement3i[2] = vertexremap[element[0]];
989 outelement3i[3] = vertexremap[element[0]] + 1;
990 outelement3i[4] = vertexremap[element[1]] + 1;
991 outelement3i[5] = vertexremap[element[2]] + 1;
995 // output the sides (facing outward from this triangle)
996 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
998 remappedelement[0] = vertexremap[element[0]];
999 remappedelement[1] = vertexremap[element[1]];
1000 outelement3i[0] = remappedelement[0];
1001 outelement3i[1] = remappedelement[1];
1002 outelement3i[2] = remappedelement[1] + 1;
1003 outelement3i[3] = remappedelement[0];
1004 outelement3i[4] = remappedelement[1] + 1;
1005 outelement3i[5] = remappedelement[0] + 1;
1010 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1012 remappedelement[1] = vertexremap[element[1]];
1013 remappedelement[2] = vertexremap[element[2]];
1014 outelement3i[0] = remappedelement[1];
1015 outelement3i[1] = remappedelement[2];
1016 outelement3i[2] = remappedelement[2] + 1;
1017 outelement3i[3] = remappedelement[1];
1018 outelement3i[4] = remappedelement[2] + 1;
1019 outelement3i[5] = remappedelement[1] + 1;
1024 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1026 remappedelement[0] = vertexremap[element[0]];
1027 remappedelement[2] = vertexremap[element[2]];
1028 outelement3i[0] = remappedelement[2];
1029 outelement3i[1] = remappedelement[0];
1030 outelement3i[2] = remappedelement[0] + 1;
1031 outelement3i[3] = remappedelement[2];
1032 outelement3i[4] = remappedelement[0] + 1;
1033 outelement3i[5] = remappedelement[2] + 1;
1041 *outnumvertices = outvertices;
1042 return outtriangles;
1045 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)
1048 int outtriangles = 0, outvertices = 0;
1050 const float *vertex;
1051 float ratio, direction[3], projectvector[3];
1054 if (projectdirection)
1055 VectorScale(projectdirection, projectdistance, projectvector);
1057 VectorClear(projectvector);
1059 for (i = 0;i < numshadowmarktris;i++)
1061 int remappedelement[3];
1063 const int *neighbortriangle;
1065 markindex = shadowmarktris[i] * 3;
1066 neighbortriangle = inneighbor3i + markindex;
1067 side[0] = shadowmark[neighbortriangle[0]] == shadowmarkcount;
1068 side[1] = shadowmark[neighbortriangle[1]] == shadowmarkcount;
1069 side[2] = shadowmark[neighbortriangle[2]] == shadowmarkcount;
1070 if (side[0] + side[1] + side[2] == 0)
1074 element = inelement3i + markindex;
1076 // create the vertices
1077 for (j = 0;j < 3;j++)
1079 if (side[j] + side[j+1] == 0)
1082 if (vertexupdate[k] != vertexupdatenum)
1084 vertexupdate[k] = vertexupdatenum;
1085 vertexremap[k] = outvertices;
1086 vertex = invertex3f + k * 3;
1087 VectorCopy(vertex, outvertex3f);
1088 if (projectdirection)
1090 // project one copy of the vertex according to projectvector
1091 VectorAdd(vertex, projectvector, (outvertex3f + 3));
1095 // project one copy of the vertex to the sphere radius of the light
1096 // (FIXME: would projecting it to the light box be better?)
1097 VectorSubtract(vertex, projectorigin, direction);
1098 ratio = projectdistance / VectorLength(direction);
1099 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1106 // output the sides (facing outward from this triangle)
1109 remappedelement[0] = vertexremap[element[0]];
1110 remappedelement[1] = vertexremap[element[1]];
1111 outelement3i[0] = remappedelement[1];
1112 outelement3i[1] = remappedelement[0];
1113 outelement3i[2] = remappedelement[0] + 1;
1114 outelement3i[3] = remappedelement[1];
1115 outelement3i[4] = remappedelement[0] + 1;
1116 outelement3i[5] = remappedelement[1] + 1;
1123 remappedelement[1] = vertexremap[element[1]];
1124 remappedelement[2] = vertexremap[element[2]];
1125 outelement3i[0] = remappedelement[2];
1126 outelement3i[1] = remappedelement[1];
1127 outelement3i[2] = remappedelement[1] + 1;
1128 outelement3i[3] = remappedelement[2];
1129 outelement3i[4] = remappedelement[1] + 1;
1130 outelement3i[5] = remappedelement[2] + 1;
1137 remappedelement[0] = vertexremap[element[0]];
1138 remappedelement[2] = vertexremap[element[2]];
1139 outelement3i[0] = remappedelement[0];
1140 outelement3i[1] = remappedelement[2];
1141 outelement3i[2] = remappedelement[2] + 1;
1142 outelement3i[3] = remappedelement[0];
1143 outelement3i[4] = remappedelement[2] + 1;
1144 outelement3i[5] = remappedelement[0] + 1;
1151 *outnumvertices = outvertices;
1152 return outtriangles;
1155 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)
1161 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1163 tend = firsttriangle + numtris;
1164 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1166 // surface box entirely inside light box, no box cull
1167 if (projectdirection)
1169 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1171 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
1172 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1173 shadowmarklist[numshadowmark++] = t;
1178 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1179 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
1180 shadowmarklist[numshadowmark++] = t;
1185 // surface box not entirely inside light box, cull each triangle
1186 if (projectdirection)
1188 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1190 v[0] = invertex3f + e[0] * 3;
1191 v[1] = invertex3f + e[1] * 3;
1192 v[2] = invertex3f + e[2] * 3;
1193 TriangleNormal(v[0], v[1], v[2], normal);
1194 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1195 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1196 shadowmarklist[numshadowmark++] = t;
1201 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1203 v[0] = invertex3f + e[0] * 3;
1204 v[1] = invertex3f + e[1] * 3;
1205 v[2] = invertex3f + e[2] * 3;
1206 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1207 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1208 shadowmarklist[numshadowmark++] = t;
1214 qboolean R_Shadow_UseZPass(vec3_t mins, vec3_t maxs)
1219 if (r_shadow_compilingrtlight || !r_shadow_frontsidecasting.integer || !r_shadow_usezpassifpossible.integer)
1221 // check if the shadow volume intersects the near plane
1223 // a ray between the eye and light origin may intersect the caster,
1224 // indicating that the shadow may touch the eye location, however we must
1225 // test the near plane (a polygon), not merely the eye location, so it is
1226 // easiest to enlarge the caster bounding shape slightly for this.
1232 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)
1234 int i, tris, outverts;
1235 if (projectdistance < 0.1)
1237 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
1240 if (!numverts || !nummarktris)
1242 // make sure shadowelements is big enough for this volume
1243 if (maxshadowtriangles < nummarktris*8 || maxshadowvertices < numverts*2)
1244 R_Shadow_ResizeShadowArrays(numverts, nummarktris, 2, 8);
1246 if (maxvertexupdate < numverts)
1248 maxvertexupdate = numverts;
1250 Mem_Free(vertexupdate);
1252 Mem_Free(vertexremap);
1253 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1254 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1255 vertexupdatenum = 0;
1258 if (vertexupdatenum == 0)
1260 vertexupdatenum = 1;
1261 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
1262 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
1265 for (i = 0;i < nummarktris;i++)
1266 shadowmark[marktris[i]] = shadowmarkcount;
1268 if (r_shadow_compilingrtlight)
1270 // if we're compiling an rtlight, capture the mesh
1271 //tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1272 //Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zpass, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1273 tris = R_Shadow_ConstructShadowVolume_ZFail(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_zfail, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1276 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
1278 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1279 R_Mesh_PrepareVertices_Position_Arrays(outverts, shadowvertex3f);
1280 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1284 // decide which type of shadow to generate and set stencil mode
1285 R_Shadow_RenderMode_StencilShadowVolumes(R_Shadow_UseZPass(trismins, trismaxs));
1286 // generate the sides or a solid volume, depending on type
1287 if (r_shadow_rendermode >= R_SHADOW_RENDERMODE_ZPASS_STENCIL && r_shadow_rendermode <= R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE)
1288 tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1290 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1291 r_refdef.stats.lights_dynamicshadowtriangles += tris;
1292 r_refdef.stats.lights_shadowtriangles += tris;
1293 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
1295 // increment stencil if frontface is infront of depthbuffer
1296 GL_CullFace(r_refdef.view.cullface_front);
1297 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
1298 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1299 // decrement stencil if backface is infront of depthbuffer
1300 GL_CullFace(r_refdef.view.cullface_back);
1301 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
1303 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
1305 // decrement stencil if backface is behind depthbuffer
1306 GL_CullFace(r_refdef.view.cullface_front);
1307 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
1308 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1309 // increment stencil if frontface is behind depthbuffer
1310 GL_CullFace(r_refdef.view.cullface_back);
1311 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
1313 R_Mesh_PrepareVertices_Position_Arrays(outverts, shadowvertex3f);
1314 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1318 int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias)
1320 // p1, p2, p3 are in the cubemap's local coordinate system
1321 // bias = border/(size - border)
1324 float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1325 dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2),
1326 dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3);
1327 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1329 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1330 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1331 | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1332 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1334 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1335 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1336 | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1338 dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1339 dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2),
1340 dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3);
1341 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1343 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1344 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1345 | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1346 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1348 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1349 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1350 | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1352 dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1353 dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2),
1354 dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3);
1355 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1357 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1358 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1359 | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1360 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1362 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1363 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1364 | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1369 int R_Shadow_CalcBBoxSideMask(const vec3_t mins, const vec3_t maxs, const matrix4x4_t *worldtolight, const matrix4x4_t *radiustolight, float bias)
1371 vec3_t center, radius, lightcenter, lightradius, pmin, pmax;
1372 float dp1, dn1, ap1, an1, dp2, dn2, ap2, an2;
1375 VectorSubtract(maxs, mins, radius);
1376 VectorScale(radius, 0.5f, radius);
1377 VectorAdd(mins, radius, center);
1378 Matrix4x4_Transform(worldtolight, center, lightcenter);
1379 Matrix4x4_Transform3x3(radiustolight, radius, lightradius);
1380 VectorSubtract(lightcenter, lightradius, pmin);
1381 VectorAdd(lightcenter, lightradius, pmax);
1383 dp1 = pmax[0] + pmax[1], dn1 = pmax[0] - pmin[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1384 dp2 = pmin[0] + pmin[1], dn2 = pmin[0] - pmax[1], ap2 = fabs(dp2), an2 = fabs(dn2);
1385 if(ap1 > bias*an1 && ap2 > bias*an2)
1387 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1388 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1389 if(an1 > bias*ap1 && an2 > bias*ap2)
1391 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1392 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1394 dp1 = pmax[1] + pmax[2], dn1 = pmax[1] - pmin[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1395 dp2 = pmin[1] + pmin[2], dn2 = pmin[1] - pmax[2], ap2 = fabs(dp2), an2 = fabs(dn2);
1396 if(ap1 > bias*an1 && ap2 > bias*an2)
1398 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1399 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1400 if(an1 > bias*ap1 && an2 > bias*ap2)
1402 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1403 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1405 dp1 = pmax[2] + pmax[0], dn1 = pmax[2] - pmin[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1406 dp2 = pmin[2] + pmin[0], dn2 = pmin[2] - pmax[0], ap2 = fabs(dp2), an2 = fabs(dn2);
1407 if(ap1 > bias*an1 && ap2 > bias*an2)
1409 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1410 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1411 if(an1 > bias*ap1 && an2 > bias*ap2)
1413 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1414 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1419 #define R_Shadow_CalcEntitySideMask(ent, worldtolight, radiustolight, bias) R_Shadow_CalcBBoxSideMask((ent)->mins, (ent)->maxs, worldtolight, radiustolight, bias)
1421 int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
1423 // p is in the cubemap's local coordinate system
1424 // bias = border/(size - border)
1425 float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn);
1426 float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn);
1427 float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn);
1429 if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
1430 if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
1431 if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
1432 if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
1433 if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
1434 if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
1438 int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
1442 int sides = 0x3F, masks[6] = { 3<<4, 3<<4, 3<<0, 3<<0, 3<<2, 3<<2 };
1443 float scale = (size - 2*border)/size, len;
1444 float bias = border / (float)(size - border), dp, dn, ap, an;
1445 // check if cone enclosing side would cross frustum plane
1446 scale = 2 / (scale*scale + 2);
1447 for (i = 0;i < 5;i++)
1449 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) > -0.03125)
1451 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[i].normal, n);
1452 len = scale*VectorLength2(n);
1453 if(n[0]*n[0] > len) sides &= n[0] < 0 ? ~(1<<0) : ~(2 << 0);
1454 if(n[1]*n[1] > len) sides &= n[1] < 0 ? ~(1<<2) : ~(2 << 2);
1455 if(n[2]*n[2] > len) sides &= n[2] < 0 ? ~(1<<4) : ~(2 << 4);
1457 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[4]) >= r_refdef.farclip - r_refdef.nearclip + 0.03125)
1459 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[4].normal, n);
1460 len = scale*VectorLength(n);
1461 if(n[0]*n[0] > len) sides &= n[0] >= 0 ? ~(1<<0) : ~(2 << 0);
1462 if(n[1]*n[1] > len) sides &= n[1] >= 0 ? ~(1<<2) : ~(2 << 2);
1463 if(n[2]*n[2] > len) sides &= n[2] >= 0 ? ~(1<<4) : ~(2 << 4);
1465 // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results
1466 // check if frustum corners/origin cross plane sides
1468 // infinite version, assumes frustum corners merely give direction and extend to infinite distance
1469 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.origin, p);
1470 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1471 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1472 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1473 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1474 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1475 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1476 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1477 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1478 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1479 for (i = 0;i < 4;i++)
1481 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.frustumcorner[i], n);
1482 VectorSubtract(n, p, n);
1483 dp = n[0] + n[1], dn = n[0] - n[1], ap = fabs(dp), an = fabs(dn);
1484 if(ap > 0) masks[0] |= dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2);
1485 if(an > 0) masks[1] |= dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2);
1486 dp = n[1] + n[2], dn = n[1] - n[2], ap = fabs(dp), an = fabs(dn);
1487 if(ap > 0) masks[2] |= dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4);
1488 if(an > 0) masks[3] |= dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4);
1489 dp = n[2] + n[0], dn = n[2] - n[0], ap = fabs(dp), an = fabs(dn);
1490 if(ap > 0) masks[4] |= dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0);
1491 if(an > 0) masks[5] |= dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0);
1494 // finite version, assumes corners are a finite distance from origin dependent on far plane
1495 for (i = 0;i < 5;i++)
1497 Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p);
1498 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1499 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1500 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1501 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1502 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1503 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1504 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1505 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1506 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1509 return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5];
1512 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)
1520 int mask, surfacemask = 0;
1521 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1523 bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
1524 tend = firsttriangle + numtris;
1525 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1527 // surface box entirely inside light box, no box cull
1528 if (projectdirection)
1530 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1532 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1533 TriangleNormal(v[0], v[1], v[2], normal);
1534 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1536 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1537 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1538 surfacemask |= mask;
1541 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;
1542 shadowsides[numshadowsides] = mask;
1543 shadowsideslist[numshadowsides++] = t;
1550 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1552 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1553 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]))
1555 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1556 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1557 surfacemask |= mask;
1560 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;
1561 shadowsides[numshadowsides] = mask;
1562 shadowsideslist[numshadowsides++] = t;
1570 // surface box not entirely inside light box, cull each triangle
1571 if (projectdirection)
1573 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1575 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1576 TriangleNormal(v[0], v[1], v[2], normal);
1577 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1578 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1580 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1581 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1582 surfacemask |= mask;
1585 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;
1586 shadowsides[numshadowsides] = mask;
1587 shadowsideslist[numshadowsides++] = t;
1594 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1596 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1597 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1598 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1600 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1601 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1602 surfacemask |= mask;
1605 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;
1606 shadowsides[numshadowsides] = mask;
1607 shadowsideslist[numshadowsides++] = t;
1616 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)
1618 int i, j, outtriangles = 0;
1619 int *outelement3i[6];
1620 if (!numverts || !numsidetris || !r_shadow_compilingrtlight)
1622 outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5];
1623 // make sure shadowelements is big enough for this mesh
1624 if (maxshadowtriangles < outtriangles)
1625 R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1);
1627 // compute the offset and size of the separate index lists for each cubemap side
1629 for (i = 0;i < 6;i++)
1631 outelement3i[i] = shadowelements + outtriangles * 3;
1632 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles;
1633 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i];
1634 outtriangles += sidetotals[i];
1637 // gather up the (sparse) triangles into separate index lists for each cubemap side
1638 for (i = 0;i < numsidetris;i++)
1640 const int *element = elements + sidetris[i] * 3;
1641 for (j = 0;j < 6;j++)
1643 if (sides[i] & (1 << j))
1645 outelement3i[j][0] = element[0];
1646 outelement3i[j][1] = element[1];
1647 outelement3i[j][2] = element[2];
1648 outelement3i[j] += 3;
1653 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, outtriangles, shadowelements);
1656 static void R_Shadow_MakeTextures_MakeCorona(void)
1660 unsigned char pixels[32][32][4];
1661 for (y = 0;y < 32;y++)
1663 dy = (y - 15.5f) * (1.0f / 16.0f);
1664 for (x = 0;x < 32;x++)
1666 dx = (x - 15.5f) * (1.0f / 16.0f);
1667 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1668 a = bound(0, a, 255);
1669 pixels[y][x][0] = a;
1670 pixels[y][x][1] = a;
1671 pixels[y][x][2] = a;
1672 pixels[y][x][3] = 255;
1675 r_shadow_lightcorona = R_SkinFrame_LoadInternalBGRA("lightcorona", TEXF_FORCELINEAR, &pixels[0][0][0], 32, 32);
1678 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1680 float dist = sqrt(x*x+y*y+z*z);
1681 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1682 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1683 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1686 static void R_Shadow_MakeTextures(void)
1689 float intensity, dist;
1691 R_Shadow_FreeShadowMaps();
1692 R_FreeTexturePool(&r_shadow_texturepool);
1693 r_shadow_texturepool = R_AllocTexturePool();
1694 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1695 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1696 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1697 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1698 for (x = 0;x <= ATTENTABLESIZE;x++)
1700 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1701 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1702 r_shadow_attentable[x] = bound(0, intensity, 1);
1704 // 1D gradient texture
1705 for (x = 0;x < ATTEN1DSIZE;x++)
1706 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1707 r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1708 // 2D circle texture
1709 for (y = 0;y < ATTEN2DSIZE;y++)
1710 for (x = 0;x < ATTEN2DSIZE;x++)
1711 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);
1712 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1713 // 3D sphere texture
1714 if (r_shadow_texture3d.integer && vid.support.ext_texture_3d)
1716 for (z = 0;z < ATTEN3DSIZE;z++)
1717 for (y = 0;y < ATTEN3DSIZE;y++)
1718 for (x = 0;x < ATTEN3DSIZE;x++)
1719 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));
1720 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);
1723 r_shadow_attenuation3dtexture = NULL;
1726 R_Shadow_MakeTextures_MakeCorona();
1728 // Editor light sprites
1729 r_editlights_sprcursor = R_SkinFrame_LoadInternal8bit("gfx/editlights/cursor", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1746 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1747 r_editlights_sprlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/light", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1764 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1765 r_editlights_sprnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/noshadow", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1782 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1783 r_editlights_sprcubemaplight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemaplight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1800 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1801 r_editlights_sprcubemapnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemapnoshadowlight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1818 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1819 r_editlights_sprselection = R_SkinFrame_LoadInternal8bit("gfx/editlights/selection", TEXF_ALPHA | TEXF_CLAMP, (unsigned char *)
1836 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1839 void R_Shadow_ValidateCvars(void)
1841 if (r_shadow_texture3d.integer && !vid.support.ext_texture_3d)
1842 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1843 if (gl_ext_separatestencil.integer && !vid.support.ati_separate_stencil)
1844 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
1845 if (gl_ext_stenciltwoside.integer && !vid.support.ext_stencil_two_side)
1846 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1849 //static const r_vertexposition_t resetvertexposition[3] = {{0, 0, 0}};
1851 void R_Shadow_RenderMode_Begin(void)
1857 R_Shadow_ValidateCvars();
1859 if (!r_shadow_attenuation2dtexture
1860 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1861 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1862 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1863 R_Shadow_MakeTextures();
1866 R_Mesh_ResetTextureState();
1867 // R_Mesh_PrepareVertices_Position(0, resetvertexposition, NULL);
1868 GL_BlendFunc(GL_ONE, GL_ZERO);
1869 GL_DepthRange(0, 1);
1870 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1872 GL_DepthMask(false);
1873 GL_Color(0, 0, 0, 1);
1874 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1876 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1878 if (gl_ext_separatestencil.integer && vid.support.ati_separate_stencil)
1880 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
1881 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
1883 else if (gl_ext_stenciltwoside.integer && vid.support.ext_stencil_two_side)
1885 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
1886 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
1890 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
1891 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
1894 switch(vid.renderpath)
1896 case RENDERPATH_GL20:
1897 case RENDERPATH_CGGL:
1898 case RENDERPATH_D3D9:
1899 case RENDERPATH_D3D10:
1900 case RENDERPATH_D3D11:
1901 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1903 case RENDERPATH_GL13:
1904 case RENDERPATH_GL11:
1905 if (r_textureunits.integer >= 2 && vid.texunits >= 2 && r_shadow_texture3d.integer && r_shadow_attenuation3dtexture)
1906 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN;
1907 else if (r_textureunits.integer >= 3 && vid.texunits >= 3)
1908 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN;
1909 else if (r_textureunits.integer >= 2 && vid.texunits >= 2)
1910 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN;
1912 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1918 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
1919 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
1920 r_shadow_drawbuffer = drawbuffer;
1921 r_shadow_readbuffer = readbuffer;
1923 r_shadow_cullface_front = r_refdef.view.cullface_front;
1924 r_shadow_cullface_back = r_refdef.view.cullface_back;
1927 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
1929 rsurface.rtlight = rtlight;
1932 void R_Shadow_RenderMode_Reset(void)
1934 R_Mesh_ResetRenderTargets();
1935 R_SetViewport(&r_refdef.view.viewport);
1936 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
1937 R_Mesh_ResetTextureState();
1938 // R_Mesh_PrepareVertices_Position(0, resetvertexposition, NULL);
1939 GL_DepthRange(0, 1);
1941 GL_DepthMask(false);
1942 GL_DepthFunc(GL_LEQUAL);
1943 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1944 r_refdef.view.cullface_front = r_shadow_cullface_front;
1945 r_refdef.view.cullface_back = r_shadow_cullface_back;
1946 GL_CullFace(r_refdef.view.cullface_back);
1947 GL_Color(1, 1, 1, 1);
1948 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
1949 GL_BlendFunc(GL_ONE, GL_ZERO);
1950 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
1951 r_shadow_usingshadowmap2d = false;
1952 r_shadow_usingshadowmaportho = false;
1953 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
1956 void R_Shadow_ClearStencil(void)
1958 GL_Clear(GL_STENCIL_BUFFER_BIT, NULL, 1.0f, 128);
1959 r_refdef.stats.lights_clears++;
1962 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
1964 r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
1965 if (r_shadow_rendermode == mode)
1967 R_Shadow_RenderMode_Reset();
1968 GL_DepthFunc(GL_LESS);
1969 GL_ColorMask(0, 0, 0, 0);
1970 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1971 GL_CullFace(GL_NONE);
1972 R_SetupShader_DepthOrShadow();
1973 r_shadow_rendermode = mode;
1978 case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
1979 case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
1980 R_SetStencilSeparate(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, GL_ALWAYS, 128, 255);
1982 case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
1983 case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
1984 R_SetStencilSeparate(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, GL_ALWAYS, 128, 255);
1989 static void R_Shadow_MakeVSDCT(void)
1991 // maps to a 2x3 texture rectangle with normalized coordinates
1996 // stores abs(dir.xy), offset.xy/2.5
1997 unsigned char data[4*6] =
1999 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
2000 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
2001 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
2002 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
2003 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
2004 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
2006 r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
2009 static void R_Shadow_MakeShadowMap(int side, int size)
2011 switch (r_shadow_shadowmode)
2013 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2014 if (r_shadow_shadowmap2dtexture) return;
2015 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);
2016 r_shadow_shadowmap2dcolortexture = NULL;
2017 switch(vid.renderpath)
2020 case RENDERPATH_D3D9:
2021 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);
2022 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
2026 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2dtexture, NULL, NULL, NULL, NULL);
2034 // render depth into the fbo, do not render color at all
2035 // validate the fbo now
2039 qglDrawBuffer(GL_NONE);CHECKGLERROR
2040 qglReadBuffer(GL_NONE);CHECKGLERROR
2041 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2042 if (status != GL_FRAMEBUFFER_COMPLETE_EXT && (r_shadow_shadowmapping.integer || r_shadow_deferred.integer))
2044 Con_Printf("R_Shadow_MakeShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2045 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2046 Cvar_SetValueQuick(&r_shadow_deferred, 0);
2051 void R_Shadow_RenderMode_ShadowMap(int side, int clear, int size)
2053 float nearclip, farclip, bias;
2054 r_viewport_t viewport;
2057 float clearcolor[4];
2058 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
2060 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
2061 r_shadow_shadowmap_parameters[1] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
2062 r_shadow_shadowmap_parameters[3] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
2063 r_shadow_shadowmapside = side;
2064 r_shadow_shadowmapsize = size;
2066 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2067 r_shadow_shadowmap_parameters[2] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2068 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
2069 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D) goto init_done;
2071 // complex unrolled cube approach (more flexible)
2072 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2073 R_Shadow_MakeVSDCT();
2074 if (!r_shadow_shadowmap2dtexture)
2075 R_Shadow_MakeShadowMap(side, r_shadow_shadowmapmaxsize);
2076 if (r_shadow_shadowmap2dtexture) fbo = r_shadow_fbo2d;
2077 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
2078 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
2079 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
2081 R_Mesh_ResetTextureState();
2082 R_Mesh_ResetRenderTargets();
2083 R_Shadow_RenderMode_Reset();
2086 R_Mesh_SetRenderTargets(fbo, r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
2087 R_SetupShader_DepthOrShadow();
2090 R_SetupShader_ShowDepth();
2091 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
2096 R_SetViewport(&viewport);
2097 flipped = (side & 1) ^ (side >> 2);
2098 r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
2099 r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
2100 switch(vid.renderpath)
2102 case RENDERPATH_GL11:
2103 case RENDERPATH_GL13:
2104 case RENDERPATH_GL20:
2105 case RENDERPATH_CGGL:
2106 GL_CullFace(r_refdef.view.cullface_back);
2107 // OpenGL lets us scissor larger than the viewport, so go ahead and clear all views at once
2108 if ((clear & ((2 << side) - 1)) == (1 << side)) // only clear if the side is the first in the mask
2110 // get tightest scissor rectangle that encloses all viewports in the clear mask
2111 int x1 = clear & 0x15 ? 0 : size;
2112 int x2 = clear & 0x2A ? 2 * size : size;
2113 int y1 = clear & 0x03 ? 0 : (clear & 0xC ? size : 2 * size);
2114 int y2 = clear & 0x30 ? 3 * size : (clear & 0xC ? 2 * size : size);
2115 GL_Scissor(x1, y1, x2 - x1, y2 - y1);
2116 GL_Clear(GL_DEPTH_BUFFER_BIT, NULL, 1.0f, 0);
2118 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2120 case RENDERPATH_D3D9:
2121 Vector4Set(clearcolor, 1,1,1,1);
2122 // completely different meaning than in OpenGL path
2123 r_shadow_shadowmap_parameters[1] = 0;
2124 r_shadow_shadowmap_parameters[3] = -bias;
2125 // we invert the cull mode because we flip the projection matrix
2126 // NOTE: this actually does nothing because the DrawShadowMap code sets it to doublesided...
2127 GL_CullFace(r_refdef.view.cullface_front);
2128 // D3D considers it an error to use a scissor larger than the viewport... clear just this view
2129 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2130 if (r_shadow_shadowmapsampler)
2132 GL_ColorMask(0,0,0,0);
2134 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
2138 GL_ColorMask(1,1,1,1);
2140 GL_Clear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
2143 case RENDERPATH_D3D10:
2144 case RENDERPATH_D3D11:
2145 // D3D considers it an error to use a scissor larger than the viewport... clear just this view
2146 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2147 GL_ColorMask(0,0,0,0);
2149 GL_Clear(GL_DEPTH_BUFFER_BIT, NULL, 1.0f, 0);
2154 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
2156 R_Mesh_ResetTextureState();
2157 R_Mesh_ResetRenderTargets();
2160 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2161 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2162 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2163 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2165 R_Shadow_RenderMode_Reset();
2166 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2168 GL_DepthFunc(GL_EQUAL);
2169 // do global setup needed for the chosen lighting mode
2170 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2171 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2172 r_shadow_usingshadowmap2d = shadowmapping;
2173 r_shadow_rendermode = r_shadow_lightingrendermode;
2174 // only draw light where this geometry was already rendered AND the
2175 // stencil is 128 (values other than this mean shadow)
2177 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2179 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
2182 static const unsigned short bboxelements[36] =
2192 static const float bboxpoints[8][3] =
2204 void R_Shadow_RenderMode_DrawDeferredLight(qboolean stenciltest, qboolean shadowmapping)
2207 float vertex3f[8*3];
2208 const matrix4x4_t *matrix = &rsurface.rtlight->matrix_lighttoworld;
2209 // do global setup needed for the chosen lighting mode
2210 R_Shadow_RenderMode_Reset();
2211 r_shadow_rendermode = r_shadow_lightingrendermode;
2212 R_EntityMatrix(&identitymatrix);
2213 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2214 // only draw light where this geometry was already rendered AND the
2215 // stencil is 128 (values other than this mean shadow)
2216 R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2217 R_Mesh_SetRenderTargets(r_shadow_prepasslightingfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
2219 r_shadow_usingshadowmap2d = shadowmapping;
2221 // render the lighting
2222 R_SetupShader_DeferredLight(rsurface.rtlight);
2223 for (i = 0;i < 8;i++)
2224 Matrix4x4_Transform(matrix, bboxpoints[i], vertex3f + i*3);
2225 GL_ColorMask(1,1,1,1);
2226 GL_DepthMask(false);
2227 GL_DepthRange(0, 1);
2228 GL_PolygonOffset(0, 0);
2230 GL_DepthFunc(GL_GREATER);
2231 GL_CullFace(r_refdef.view.cullface_back);
2232 R_Mesh_PrepareVertices_Position_Arrays(8, vertex3f);
2233 R_Mesh_Draw(0, 8, 0, 12, NULL, NULL, 0, bboxelements, NULL, 0);
2236 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
2238 R_Shadow_RenderMode_Reset();
2239 GL_BlendFunc(GL_ONE, GL_ONE);
2240 GL_DepthRange(0, 1);
2241 GL_DepthTest(r_showshadowvolumes.integer < 2);
2242 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
2243 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2244 GL_CullFace(GL_NONE);
2245 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
2248 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
2250 R_Shadow_RenderMode_Reset();
2251 GL_BlendFunc(GL_ONE, GL_ONE);
2252 GL_DepthRange(0, 1);
2253 GL_DepthTest(r_showlighting.integer < 2);
2254 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2256 GL_DepthFunc(GL_EQUAL);
2257 R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2258 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2261 void R_Shadow_RenderMode_End(void)
2263 R_Shadow_RenderMode_Reset();
2264 R_Shadow_RenderMode_ActiveLight(NULL);
2266 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2267 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2270 int bboxedges[12][2] =
2289 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2291 if (!r_shadow_scissor.integer)
2293 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2294 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2295 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2296 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2299 if(R_ScissorForBBox(mins, maxs, r_shadow_lightscissor))
2300 return true; // invisible
2301 if(r_shadow_lightscissor[0] != r_refdef.view.viewport.x
2302 || r_shadow_lightscissor[1] != r_refdef.view.viewport.y
2303 || r_shadow_lightscissor[2] != r_refdef.view.viewport.width
2304 || r_shadow_lightscissor[3] != r_refdef.view.viewport.height)
2305 r_refdef.stats.lights_scissored++;
2309 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, const float *diffusecolor, const float *ambientcolor)
2312 const float *vertex3f;
2313 const float *normal3f;
2315 float dist, dot, distintensity, shadeintensity, v[3], n[3];
2316 switch (r_shadow_rendermode)
2318 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2319 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2320 if (VectorLength2(diffusecolor) > 0)
2322 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)
2324 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2325 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2326 if ((dot = DotProduct(n, v)) < 0)
2328 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2329 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
2332 VectorCopy(ambientcolor, color4f);
2333 if (r_refdef.fogenabled)
2336 f = RSurf_FogVertex(vertex3f);
2337 VectorScale(color4f, f, color4f);
2344 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.array_passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
2346 VectorCopy(ambientcolor, color4f);
2347 if (r_refdef.fogenabled)
2350 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2351 f = RSurf_FogVertex(vertex3f);
2352 VectorScale(color4f + 4*i, f, color4f);
2358 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2359 if (VectorLength2(diffusecolor) > 0)
2361 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)
2363 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2364 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2366 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2367 if ((dot = DotProduct(n, v)) < 0)
2369 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2370 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2371 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2372 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2376 color4f[0] = ambientcolor[0] * distintensity;
2377 color4f[1] = ambientcolor[1] * distintensity;
2378 color4f[2] = ambientcolor[2] * distintensity;
2380 if (r_refdef.fogenabled)
2383 f = RSurf_FogVertex(vertex3f);
2384 VectorScale(color4f, f, color4f);
2388 VectorClear(color4f);
2394 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.array_passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
2396 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2397 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2399 color4f[0] = ambientcolor[0] * distintensity;
2400 color4f[1] = ambientcolor[1] * distintensity;
2401 color4f[2] = ambientcolor[2] * distintensity;
2402 if (r_refdef.fogenabled)
2405 f = RSurf_FogVertex(vertex3f);
2406 VectorScale(color4f, f, color4f);
2410 VectorClear(color4f);
2415 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2416 if (VectorLength2(diffusecolor) > 0)
2418 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)
2420 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2421 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2423 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2424 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2425 if ((dot = DotProduct(n, v)) < 0)
2427 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2428 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2429 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2430 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2434 color4f[0] = ambientcolor[0] * distintensity;
2435 color4f[1] = ambientcolor[1] * distintensity;
2436 color4f[2] = ambientcolor[2] * distintensity;
2438 if (r_refdef.fogenabled)
2441 f = RSurf_FogVertex(vertex3f);
2442 VectorScale(color4f, f, color4f);
2446 VectorClear(color4f);
2452 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.array_passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
2454 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2455 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2457 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2458 color4f[0] = ambientcolor[0] * distintensity;
2459 color4f[1] = ambientcolor[1] * distintensity;
2460 color4f[2] = ambientcolor[2] * distintensity;
2461 if (r_refdef.fogenabled)
2464 f = RSurf_FogVertex(vertex3f);
2465 VectorScale(color4f, f, color4f);
2469 VectorClear(color4f);
2479 static void R_Shadow_RenderLighting_VisibleLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
2481 // used to display how many times a surface is lit for level design purposes
2482 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
2483 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
2487 static void R_Shadow_RenderLighting_Light_GLSL(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale, float specularscale)
2489 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2490 R_SetupShader_Surface(lightcolor, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT, texturenumsurfaces, texturesurfacelist, NULL);
2491 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2492 GL_DepthFunc(GL_EQUAL);
2494 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2495 GL_DepthFunc(GL_LEQUAL);
2498 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
2505 int newnumtriangles;
2509 int maxtriangles = 4096;
2510 static int newelements[4096*3];
2511 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, diffusecolor2, ambientcolor2);
2512 for (renders = 0;renders < 4;renders++)
2517 newnumtriangles = 0;
2519 // due to low fillrate on the cards this vertex lighting path is
2520 // designed for, we manually cull all triangles that do not
2521 // contain a lit vertex
2522 // this builds batches of triangles from multiple surfaces and
2523 // renders them at once
2524 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
2526 if (VectorLength2(rsurface.array_passcolor4f + e[0] * 4) + VectorLength2(rsurface.array_passcolor4f + e[1] * 4) + VectorLength2(rsurface.array_passcolor4f + e[2] * 4) >= 0.01)
2528 if (newnumtriangles)
2530 newfirstvertex = min(newfirstvertex, e[0]);
2531 newlastvertex = max(newlastvertex, e[0]);
2535 newfirstvertex = e[0];
2536 newlastvertex = e[0];
2538 newfirstvertex = min(newfirstvertex, e[1]);
2539 newlastvertex = max(newlastvertex, e[1]);
2540 newfirstvertex = min(newfirstvertex, e[2]);
2541 newlastvertex = max(newlastvertex, e[2]);
2547 if (newnumtriangles >= maxtriangles)
2549 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
2550 newnumtriangles = 0;
2556 if (newnumtriangles >= 1)
2558 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
2561 // if we couldn't find any lit triangles, exit early
2564 // now reduce the intensity for the next overbright pass
2565 // we have to clamp to 0 here incase the drivers have improper
2566 // handling of negative colors
2567 // (some old drivers even have improper handling of >1 color)
2569 for (i = 0, c = rsurface.array_passcolor4f + 4 * firstvertex;i < numvertices;i++, c += 4)
2571 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
2573 c[0] = max(0, c[0] - 1);
2574 c[1] = max(0, c[1] - 1);
2575 c[2] = max(0, c[2] - 1);
2587 static void R_Shadow_RenderLighting_Light_Vertex(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale)
2589 // OpenGL 1.1 path (anything)
2590 float ambientcolorbase[3], diffusecolorbase[3];
2591 float ambientcolorpants[3], diffusecolorpants[3];
2592 float ambientcolorshirt[3], diffusecolorshirt[3];
2593 const float *surfacecolor = rsurface.texture->dlightcolor;
2594 const float *surfacepants = rsurface.colormap_pantscolor;
2595 const float *surfaceshirt = rsurface.colormap_shirtcolor;
2596 rtexture_t *basetexture = rsurface.texture->basetexture;
2597 rtexture_t *pantstexture = rsurface.texture->pantstexture;
2598 rtexture_t *shirttexture = rsurface.texture->shirttexture;
2599 qboolean dopants = pantstexture && VectorLength2(surfacepants) >= (1.0f / 1048576.0f);
2600 qboolean doshirt = shirttexture && VectorLength2(surfaceshirt) >= (1.0f / 1048576.0f);
2601 ambientscale *= 2 * r_refdef.view.colorscale;
2602 diffusescale *= 2 * r_refdef.view.colorscale;
2603 ambientcolorbase[0] = lightcolor[0] * ambientscale * surfacecolor[0];ambientcolorbase[1] = lightcolor[1] * ambientscale * surfacecolor[1];ambientcolorbase[2] = lightcolor[2] * ambientscale * surfacecolor[2];
2604 diffusecolorbase[0] = lightcolor[0] * diffusescale * surfacecolor[0];diffusecolorbase[1] = lightcolor[1] * diffusescale * surfacecolor[1];diffusecolorbase[2] = lightcolor[2] * diffusescale * surfacecolor[2];
2605 ambientcolorpants[0] = ambientcolorbase[0] * surfacepants[0];ambientcolorpants[1] = ambientcolorbase[1] * surfacepants[1];ambientcolorpants[2] = ambientcolorbase[2] * surfacepants[2];
2606 diffusecolorpants[0] = diffusecolorbase[0] * surfacepants[0];diffusecolorpants[1] = diffusecolorbase[1] * surfacepants[1];diffusecolorpants[2] = diffusecolorbase[2] * surfacepants[2];
2607 ambientcolorshirt[0] = ambientcolorbase[0] * surfaceshirt[0];ambientcolorshirt[1] = ambientcolorbase[1] * surfaceshirt[1];ambientcolorshirt[2] = ambientcolorbase[2] * surfaceshirt[2];
2608 diffusecolorshirt[0] = diffusecolorbase[0] * surfaceshirt[0];diffusecolorshirt[1] = diffusecolorbase[1] * surfaceshirt[1];diffusecolorshirt[2] = diffusecolorbase[2] * surfaceshirt[2];
2609 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | (diffusescale > 0 ? BATCHNEED_ARRAY_NORMAL : 0) | BATCHNEED_ARRAY_TEXCOORD, texturenumsurfaces, texturesurfacelist);
2610 R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
2611 R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.array_passcolor4f, 0, 0);
2612 R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
2613 R_Mesh_TexBind(0, basetexture);
2614 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
2615 R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
2616 switch(r_shadow_rendermode)
2618 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2619 R_Mesh_TexBind(1, r_shadow_attenuation3dtexture);
2620 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
2621 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
2622 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
2624 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2625 R_Mesh_TexBind(2, r_shadow_attenuation2dtexture);
2626 R_Mesh_TexMatrix(2, &rsurface.entitytoattenuationz);
2627 R_Mesh_TexCombine(2, GL_MODULATE, GL_MODULATE, 1, 1);
2628 R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
2630 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2631 R_Mesh_TexBind(1, r_shadow_attenuation2dtexture);
2632 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
2633 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
2634 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
2636 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2641 //R_Mesh_TexBind(0, basetexture);
2642 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorbase, ambientcolorbase);
2645 R_Mesh_TexBind(0, pantstexture);
2646 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorpants, ambientcolorpants);
2650 R_Mesh_TexBind(0, shirttexture);
2651 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorshirt, ambientcolorshirt);
2655 extern cvar_t gl_lightmaps;
2656 void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
2658 float ambientscale, diffusescale, specularscale;
2660 float lightcolor[3];
2661 VectorCopy(rsurface.rtlight->currentcolor, lightcolor);
2662 ambientscale = rsurface.rtlight->ambientscale;
2663 diffusescale = rsurface.rtlight->diffusescale;
2664 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
2665 if (!r_shadow_usenormalmap.integer)
2667 ambientscale += 1.0f * diffusescale;
2671 if ((ambientscale + diffusescale) * VectorLength2(lightcolor) + specularscale * VectorLength2(lightcolor) < (1.0f / 1048576.0f))
2673 negated = (lightcolor[0] + lightcolor[1] + lightcolor[2] < 0) && vid.support.ext_blend_subtract;
2676 VectorNegate(lightcolor, lightcolor);
2677 switch(vid.renderpath)
2679 case RENDERPATH_GL11:
2680 case RENDERPATH_GL13:
2681 case RENDERPATH_GL20:
2682 case RENDERPATH_CGGL:
2683 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
2685 case RENDERPATH_D3D9:
2687 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_SUBTRACT);
2690 case RENDERPATH_D3D10:
2691 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2693 case RENDERPATH_D3D11:
2694 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2698 RSurf_SetupDepthAndCulling();
2699 switch (r_shadow_rendermode)
2701 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2702 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2703 R_Shadow_RenderLighting_VisibleLighting(texturenumsurfaces, texturesurfacelist);
2705 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2706 R_Shadow_RenderLighting_Light_GLSL(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale, specularscale);
2708 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2709 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2710 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2711 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2712 R_Shadow_RenderLighting_Light_Vertex(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale);
2715 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2720 switch(vid.renderpath)
2722 case RENDERPATH_GL11:
2723 case RENDERPATH_GL13:
2724 case RENDERPATH_GL20:
2725 case RENDERPATH_CGGL:
2726 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
2728 case RENDERPATH_D3D9:
2730 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_ADD);
2733 case RENDERPATH_D3D10:
2734 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2736 case RENDERPATH_D3D11:
2737 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2743 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)
2745 matrix4x4_t tempmatrix = *matrix;
2746 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
2748 // if this light has been compiled before, free the associated data
2749 R_RTLight_Uncompile(rtlight);
2751 // clear it completely to avoid any lingering data
2752 memset(rtlight, 0, sizeof(*rtlight));
2754 // copy the properties
2755 rtlight->matrix_lighttoworld = tempmatrix;
2756 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
2757 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
2758 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
2759 VectorCopy(color, rtlight->color);
2760 rtlight->cubemapname[0] = 0;
2761 if (cubemapname && cubemapname[0])
2762 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
2763 rtlight->shadow = shadow;
2764 rtlight->corona = corona;
2765 rtlight->style = style;
2766 rtlight->isstatic = isstatic;
2767 rtlight->coronasizescale = coronasizescale;
2768 rtlight->ambientscale = ambientscale;
2769 rtlight->diffusescale = diffusescale;
2770 rtlight->specularscale = specularscale;
2771 rtlight->flags = flags;
2773 // compute derived data
2774 //rtlight->cullradius = rtlight->radius;
2775 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2776 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2777 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2778 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2779 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2780 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2781 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2784 // compiles rtlight geometry
2785 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2786 void R_RTLight_Compile(rtlight_t *rtlight)
2789 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
2790 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
2791 entity_render_t *ent = r_refdef.scene.worldentity;
2792 dp_model_t *model = r_refdef.scene.worldmodel;
2793 unsigned char *data;
2796 // compile the light
2797 rtlight->compiled = true;
2798 rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
2799 rtlight->static_numleafs = 0;
2800 rtlight->static_numleafpvsbytes = 0;
2801 rtlight->static_leaflist = NULL;
2802 rtlight->static_leafpvs = NULL;
2803 rtlight->static_numsurfaces = 0;
2804 rtlight->static_surfacelist = NULL;
2805 rtlight->static_shadowmap_receivers = 0x3F;
2806 rtlight->static_shadowmap_casters = 0x3F;
2807 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2808 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2809 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2810 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2811 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2812 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2814 if (model && model->GetLightInfo)
2816 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
2817 r_shadow_compilingrtlight = rtlight;
2818 model->GetLightInfo(ent, rtlight->shadoworigin, rtlight->radius, rtlight->cullmins, rtlight->cullmaxs, r_shadow_buffer_leaflist, r_shadow_buffer_leafpvs, &numleafs, r_shadow_buffer_surfacelist, r_shadow_buffer_surfacepvs, &numsurfaces, r_shadow_buffer_shadowtrispvs, r_shadow_buffer_lighttrispvs, r_shadow_buffer_visitingleafpvs, 0, NULL);
2819 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2820 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
2821 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
2822 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
2823 rtlight->static_numsurfaces = numsurfaces;
2824 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
2825 rtlight->static_numleafs = numleafs;
2826 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
2827 rtlight->static_numleafpvsbytes = numleafpvsbytes;
2828 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
2829 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
2830 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
2831 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
2832 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
2833 if (rtlight->static_numsurfaces)
2834 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
2835 if (rtlight->static_numleafs)
2836 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
2837 if (rtlight->static_numleafpvsbytes)
2838 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
2839 if (rtlight->static_numshadowtrispvsbytes)
2840 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
2841 if (rtlight->static_numlighttrispvsbytes)
2842 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
2843 switch (rtlight->shadowmode)
2845 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2846 if (model->CompileShadowMap && rtlight->shadow)
2847 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2850 if (model->CompileShadowVolume && rtlight->shadow)
2851 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2854 // now we're done compiling the rtlight
2855 r_shadow_compilingrtlight = NULL;
2859 // use smallest available cullradius - box radius or light radius
2860 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2861 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2863 shadowzpasstris = 0;
2864 if (rtlight->static_meshchain_shadow_zpass)
2865 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
2866 shadowzpasstris += mesh->numtriangles;
2868 shadowzfailtris = 0;
2869 if (rtlight->static_meshchain_shadow_zfail)
2870 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
2871 shadowzfailtris += mesh->numtriangles;
2874 if (rtlight->static_numlighttrispvsbytes)
2875 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
2876 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
2880 if (rtlight->static_numlighttrispvsbytes)
2881 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
2882 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
2885 if (developer_extra.integer)
2886 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);
2889 void R_RTLight_Uncompile(rtlight_t *rtlight)
2891 if (rtlight->compiled)
2893 if (rtlight->static_meshchain_shadow_zpass)
2894 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
2895 rtlight->static_meshchain_shadow_zpass = NULL;
2896 if (rtlight->static_meshchain_shadow_zfail)
2897 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
2898 rtlight->static_meshchain_shadow_zfail = NULL;
2899 if (rtlight->static_meshchain_shadow_shadowmap)
2900 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
2901 rtlight->static_meshchain_shadow_shadowmap = NULL;
2902 // these allocations are grouped
2903 if (rtlight->static_surfacelist)
2904 Mem_Free(rtlight->static_surfacelist);
2905 rtlight->static_numleafs = 0;
2906 rtlight->static_numleafpvsbytes = 0;
2907 rtlight->static_leaflist = NULL;
2908 rtlight->static_leafpvs = NULL;
2909 rtlight->static_numsurfaces = 0;
2910 rtlight->static_surfacelist = NULL;
2911 rtlight->static_numshadowtrispvsbytes = 0;
2912 rtlight->static_shadowtrispvs = NULL;
2913 rtlight->static_numlighttrispvsbytes = 0;
2914 rtlight->static_lighttrispvs = NULL;
2915 rtlight->compiled = false;
2919 void R_Shadow_UncompileWorldLights(void)
2923 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
2924 for (lightindex = 0;lightindex < range;lightindex++)
2926 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2929 R_RTLight_Uncompile(&light->rtlight);
2933 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
2937 // reset the count of frustum planes
2938 // see rtlight->cached_frustumplanes definition for how much this array
2940 rtlight->cached_numfrustumplanes = 0;
2942 // haven't implemented a culling path for ortho rendering
2943 if (!r_refdef.view.useperspective)
2945 // check if the light is on screen and copy the 4 planes if it is
2946 for (i = 0;i < 4;i++)
2947 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
2950 for (i = 0;i < 4;i++)
2951 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
2956 // generate a deformed frustum that includes the light origin, this is
2957 // used to cull shadow casting surfaces that can not possibly cast a
2958 // shadow onto the visible light-receiving surfaces, which can be a
2961 // if the light origin is onscreen the result will be 4 planes exactly
2962 // if the light origin is offscreen on only one axis the result will
2963 // be exactly 5 planes (split-side case)
2964 // if the light origin is offscreen on two axes the result will be
2965 // exactly 4 planes (stretched corner case)
2966 for (i = 0;i < 4;i++)
2968 // quickly reject standard frustum planes that put the light
2969 // origin outside the frustum
2970 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
2973 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
2975 // if all the standard frustum planes were accepted, the light is onscreen
2976 // otherwise we need to generate some more planes below...
2977 if (rtlight->cached_numfrustumplanes < 4)
2979 // at least one of the stock frustum planes failed, so we need to
2980 // create one or two custom planes to enclose the light origin
2981 for (i = 0;i < 4;i++)
2983 // create a plane using the view origin and light origin, and a
2984 // single point from the frustum corner set
2985 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
2986 VectorNormalize(plane.normal);
2987 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
2988 // see if this plane is backwards and flip it if so
2989 for (j = 0;j < 4;j++)
2990 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
2994 VectorNegate(plane.normal, plane.normal);
2996 // flipped plane, test again to see if it is now valid
2997 for (j = 0;j < 4;j++)
2998 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3000 // if the plane is still not valid, then it is dividing the
3001 // frustum and has to be rejected
3005 // we have created a valid plane, compute extra info
3006 PlaneClassify(&plane);
3008 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3010 // if we've found 5 frustum planes then we have constructed a
3011 // proper split-side case and do not need to keep searching for
3012 // planes to enclose the light origin
3013 if (rtlight->cached_numfrustumplanes == 5)
3021 for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
3023 plane = rtlight->cached_frustumplanes[i];
3024 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));
3029 // now add the light-space box planes if the light box is rotated, as any
3030 // caster outside the oriented light box is irrelevant (even if it passed
3031 // the worldspace light box, which is axial)
3032 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3034 for (i = 0;i < 6;i++)
3038 v[i >> 1] = (i & 1) ? -1 : 1;
3039 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3040 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3041 plane.dist = VectorNormalizeLength(plane.normal);
3042 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3043 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3049 // add the world-space reduced box planes
3050 for (i = 0;i < 6;i++)
3052 VectorClear(plane.normal);
3053 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3054 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
3055 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3064 // reduce all plane distances to tightly fit the rtlight cull box, which
3066 VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3067 VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3068 VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3069 VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3070 VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3071 VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3072 VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3073 VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3074 oldnum = rtlight->cached_numfrustumplanes;
3075 rtlight->cached_numfrustumplanes = 0;
3076 for (j = 0;j < oldnum;j++)
3078 // find the nearest point on the box to this plane
3079 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
3080 for (i = 1;i < 8;i++)
3082 dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
3083 if (bestdist > dist)
3086 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);
3087 // if the nearest point is near or behind the plane, we want this
3088 // plane, otherwise the plane is useless as it won't cull anything
3089 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
3091 PlaneClassify(&rtlight->cached_frustumplanes[j]);
3092 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
3099 void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
3103 RSurf_ActiveWorldEntity();
3105 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3108 GL_CullFace(GL_NONE);
3109 mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3110 for (;mesh;mesh = mesh->next)
3112 if (!mesh->sidetotals[r_shadow_shadowmapside])
3114 r_refdef.stats.lights_shadowtriangles += mesh->sidetotals[r_shadow_shadowmapside];
3115 R_Mesh_PrepareVertices_Position(mesh->numverts, mesh->vertexposition, mesh->vertexpositionbuffer);
3116 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);
3120 else if (r_refdef.scene.worldentity->model)
3121 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);
3123 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3126 void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3128 qboolean zpass = false;
3131 int surfacelistindex;
3132 msurface_t *surface;
3134 RSurf_ActiveWorldEntity();
3136 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3139 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
3141 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
3142 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
3144 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
3145 for (;mesh;mesh = mesh->next)
3147 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
3148 R_Mesh_PrepareVertices_Position(mesh->numverts, mesh->vertexposition, mesh->vertexpositionbuffer);
3149 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
3151 // increment stencil if frontface is infront of depthbuffer
3152 GL_CullFace(r_refdef.view.cullface_back);
3153 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
3154 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);
3155 // decrement stencil if backface is infront of depthbuffer
3156 GL_CullFace(r_refdef.view.cullface_front);
3157 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
3159 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
3161 // decrement stencil if backface is behind depthbuffer
3162 GL_CullFace(r_refdef.view.cullface_front);
3163 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
3164 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);
3165 // increment stencil if frontface is behind depthbuffer
3166 GL_CullFace(r_refdef.view.cullface_back);
3167 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
3169 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3i_indexbuffer, mesh->element3i_bufferoffset, mesh->element3s, mesh->element3s_indexbuffer, mesh->element3s_bufferoffset);
3173 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh)
3175 // use the shadow trispvs calculated earlier by GetLightInfo to cull world triangles on this dynamic light
3176 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
3177 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
3179 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
3180 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
3181 if (CHECKPVSBIT(trispvs, t))
3182 shadowmarklist[numshadowmark++] = t;
3184 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);
3186 else if (numsurfaces)
3187 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);
3189 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3192 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3194 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3195 vec_t relativeshadowradius;
3196 RSurf_ActiveModelEntity(ent, false, false, false);
3197 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3198 // we need to re-init the shader for each entity because the matrix changed
3199 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3200 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3201 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3202 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3203 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3204 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3205 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3206 switch (r_shadow_rendermode)
3208 case R_SHADOW_RENDERMODE_SHADOWMAP2D:
3209 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
3212 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3215 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3218 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3220 // set up properties for rendering light onto this entity
3221 RSurf_ActiveModelEntity(ent, true, true, false);
3222 GL_AlphaTest(false);
3223 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3224 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3225 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3226 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3229 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
3231 if (!r_refdef.scene.worldmodel->DrawLight)
3234 // set up properties for rendering light onto this entity
3235 RSurf_ActiveWorldEntity();
3236 GL_AlphaTest(false);
3237 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3238 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3239 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3240 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3242 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
3244 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3247 void R_Shadow_DrawEntityLight(entity_render_t *ent)
3249 dp_model_t *model = ent->model;
3250 if (!model->DrawLight)
3253 R_Shadow_SetupEntityLight(ent);
3255 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3257 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3260 void R_Shadow_PrepareLight(rtlight_t *rtlight)
3264 int numleafs, numsurfaces;
3265 int *leaflist, *surfacelist;
3266 unsigned char *leafpvs;
3267 unsigned char *shadowtrispvs;
3268 unsigned char *lighttrispvs;
3269 //unsigned char *surfacesides;
3270 int numlightentities;
3271 int numlightentities_noselfshadow;
3272 int numshadowentities;
3273 int numshadowentities_noselfshadow;
3274 static entity_render_t *lightentities[MAX_EDICTS];
3275 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3276 static entity_render_t *shadowentities[MAX_EDICTS];
3277 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3280 rtlight->draw = false;
3282 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3283 // skip lights that are basically invisible (color 0 0 0)
3284 nolight = VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f);
3286 // loading is done before visibility checks because loading should happen
3287 // all at once at the start of a level, not when it stalls gameplay.
3288 // (especially important to benchmarks)
3290 if (rtlight->isstatic && !nolight && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
3292 if (rtlight->compiled)
3293 R_RTLight_Uncompile(rtlight);
3294 R_RTLight_Compile(rtlight);
3298 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
3300 // look up the light style value at this time
3301 f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3302 VectorScale(rtlight->color, f, rtlight->currentcolor);
3304 if (rtlight->selected)
3306 f = 2 + sin(realtime * M_PI * 4.0);
3307 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3311 // if lightstyle is currently off, don't draw the light
3312 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3315 // skip processing on corona-only lights
3319 // if the light box is offscreen, skip it
3320 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3323 VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
3324 VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
3326 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3328 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3330 // compiled light, world available and can receive realtime lighting
3331 // retrieve leaf information
3332 numleafs = rtlight->static_numleafs;
3333 leaflist = rtlight->static_leaflist;
3334 leafpvs = rtlight->static_leafpvs;
3335 numsurfaces = rtlight->static_numsurfaces;
3336 surfacelist = rtlight->static_surfacelist;
3337 //surfacesides = NULL;
3338 shadowtrispvs = rtlight->static_shadowtrispvs;
3339 lighttrispvs = rtlight->static_lighttrispvs;
3341 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3343 // dynamic light, world available and can receive realtime lighting
3344 // calculate lit surfaces and leafs
3345 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);
3346 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3347 leaflist = r_shadow_buffer_leaflist;
3348 leafpvs = r_shadow_buffer_leafpvs;
3349 surfacelist = r_shadow_buffer_surfacelist;
3350 //surfacesides = r_shadow_buffer_surfacesides;
3351 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3352 lighttrispvs = r_shadow_buffer_lighttrispvs;
3353 // if the reduced leaf bounds are offscreen, skip it
3354 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3365 //surfacesides = NULL;
3366 shadowtrispvs = NULL;
3367 lighttrispvs = NULL;
3369 // check if light is illuminating any visible leafs
3372 for (i = 0;i < numleafs;i++)
3373 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3379 // make a list of lit entities and shadow casting entities
3380 numlightentities = 0;
3381 numlightentities_noselfshadow = 0;
3382 numshadowentities = 0;
3383 numshadowentities_noselfshadow = 0;
3385 // add dynamic entities that are lit by the light
3386 for (i = 0;i < r_refdef.scene.numentities;i++)
3389 entity_render_t *ent = r_refdef.scene.entities[i];
3391 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3393 // skip the object entirely if it is not within the valid
3394 // shadow-casting region (which includes the lit region)
3395 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
3397 if (!(model = ent->model))
3399 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
3401 // this entity wants to receive light, is visible, and is
3402 // inside the light box
3403 // TODO: check if the surfaces in the model can receive light
3404 // so now check if it's in a leaf seen by the light
3405 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))
3407 if (ent->flags & RENDER_NOSELFSHADOW)
3408 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
3410 lightentities[numlightentities++] = ent;
3411 // since it is lit, it probably also casts a shadow...
3412 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3413 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3414 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3416 // note: exterior models without the RENDER_NOSELFSHADOW
3417 // flag still create a RENDER_NOSELFSHADOW shadow but
3418 // are lit normally, this means that they are
3419 // self-shadowing but do not shadow other
3420 // RENDER_NOSELFSHADOW entities such as the gun
3421 // (very weird, but keeps the player shadow off the gun)
3422 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3423 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3425 shadowentities[numshadowentities++] = ent;
3428 else if (ent->flags & RENDER_SHADOW)
3430 // this entity is not receiving light, but may still need to
3432 // TODO: check if the surfaces in the model can cast shadow
3433 // now check if it is in a leaf seen by the light
3434 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))
3436 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3437 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3438 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3440 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3441 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3443 shadowentities[numshadowentities++] = ent;
3448 // return if there's nothing at all to light
3449 if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
3452 // count this light in the r_speeds
3453 r_refdef.stats.lights++;
3455 // flag it as worth drawing later
3456 rtlight->draw = true;
3458 // cache all the animated entities that cast a shadow but are not visible
3459 for (i = 0;i < numshadowentities;i++)
3460 if (!shadowentities[i]->animcache_vertex3f)
3461 R_AnimCache_GetEntity(shadowentities[i], false, false);
3462 for (i = 0;i < numshadowentities_noselfshadow;i++)
3463 if (!shadowentities_noselfshadow[i]->animcache_vertex3f)
3464 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
3466 // allocate some temporary memory for rendering this light later in the frame
3467 // reusable buffers need to be copied, static data can be used as-is
3468 rtlight->cached_numlightentities = numlightentities;
3469 rtlight->cached_numlightentities_noselfshadow = numlightentities_noselfshadow;
3470 rtlight->cached_numshadowentities = numshadowentities;
3471 rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
3472 rtlight->cached_numsurfaces = numsurfaces;
3473 rtlight->cached_lightentities = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
3474 rtlight->cached_lightentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
3475 rtlight->cached_shadowentities = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
3476 rtlight->cached_shadowentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
3477 if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
3479 int numshadowtrispvsbytes = (((r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles) + 7) >> 3);
3480 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
3481 rtlight->cached_shadowtrispvs = (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
3482 rtlight->cached_lighttrispvs = (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
3483 rtlight->cached_surfacelist = (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
3487 // compiled light data
3488 rtlight->cached_shadowtrispvs = shadowtrispvs;
3489 rtlight->cached_lighttrispvs = lighttrispvs;
3490 rtlight->cached_surfacelist = surfacelist;
3494 void R_Shadow_DrawLight(rtlight_t *rtlight)
3498 unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
3499 int numlightentities;
3500 int numlightentities_noselfshadow;
3501 int numshadowentities;
3502 int numshadowentities_noselfshadow;
3503 entity_render_t **lightentities;
3504 entity_render_t **lightentities_noselfshadow;
3505 entity_render_t **shadowentities;
3506 entity_render_t **shadowentities_noselfshadow;
3508 static unsigned char entitysides[MAX_EDICTS];
3509 static unsigned char entitysides_noselfshadow[MAX_EDICTS];
3510 vec3_t nearestpoint;
3512 qboolean castshadows;
3515 // check if we cached this light this frame (meaning it is worth drawing)
3519 // if R_FrameData_Store ran out of space we skip anything dependent on it
3520 if (r_framedata_failed)
3523 numlightentities = rtlight->cached_numlightentities;
3524 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
3525 numshadowentities = rtlight->cached_numshadowentities;
3526 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
3527 numsurfaces = rtlight->cached_numsurfaces;
3528 lightentities = rtlight->cached_lightentities;
3529 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
3530 shadowentities = rtlight->cached_shadowentities;
3531 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
3532 shadowtrispvs = rtlight->cached_shadowtrispvs;
3533 lighttrispvs = rtlight->cached_lighttrispvs;
3534 surfacelist = rtlight->cached_surfacelist;
3536 // set up a scissor rectangle for this light
3537 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3540 // don't let sound skip if going slow
3541 if (r_refdef.scene.extraupdate)
3544 // make this the active rtlight for rendering purposes
3545 R_Shadow_RenderMode_ActiveLight(rtlight);
3547 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
3549 // optionally draw visible shape of the shadow volumes
3550 // for performance analysis by level designers
3551 R_Shadow_RenderMode_VisibleShadowVolumes();
3553 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
3554 for (i = 0;i < numshadowentities;i++)
3555 R_Shadow_DrawEntityShadow(shadowentities[i]);
3556 for (i = 0;i < numshadowentities_noselfshadow;i++)
3557 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3558 R_Shadow_RenderMode_VisibleLighting(false, false);
3561 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
3563 // optionally draw the illuminated areas
3564 // for performance analysis by level designers
3565 R_Shadow_RenderMode_VisibleLighting(false, false);
3567 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3568 for (i = 0;i < numlightentities;i++)
3569 R_Shadow_DrawEntityLight(lightentities[i]);
3570 for (i = 0;i < numlightentities_noselfshadow;i++)
3571 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3574 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
3576 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
3577 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
3578 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
3579 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
3581 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance/rtlight->radius));
3582 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
3583 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
3585 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
3591 int receivermask = 0;
3592 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
3593 Matrix4x4_Abs(&radiustolight);
3595 r_shadow_shadowmaplod = 0;
3596 for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
3597 if ((r_shadow_shadowmapmaxsize >> i) > lodlinear)
3598 r_shadow_shadowmaplod = i;
3600 size = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
3602 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
3604 surfacesides = NULL;
3607 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3609 castermask = rtlight->static_shadowmap_casters;
3610 receivermask = rtlight->static_shadowmap_receivers;
3614 surfacesides = r_shadow_buffer_surfacesides;
3615 for(i = 0;i < numsurfaces;i++)
3617 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
3618 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3619 castermask |= surfacesides[i];
3620 receivermask |= surfacesides[i];
3624 if (receivermask < 0x3F)
3626 for (i = 0;i < numlightentities;i++)
3627 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3628 if (receivermask < 0x3F)
3629 for(i = 0; i < numlightentities_noselfshadow;i++)
3630 receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3633 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
3637 for (i = 0;i < numshadowentities;i++)
3638 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3639 for (i = 0;i < numshadowentities_noselfshadow;i++)
3640 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3643 //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
3645 // render shadow casters into 6 sided depth texture
3646 for (side = 0;side < 6;side++) if (receivermask & (1 << side))
3648 R_Shadow_RenderMode_ShadowMap(side, receivermask, size);
3649 if (! (castermask & (1 << side))) continue;
3651 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
3652 for (i = 0;i < numshadowentities;i++) if (entitysides[i] & (1 << side))
3653 R_Shadow_DrawEntityShadow(shadowentities[i]);
3656 if (numlightentities_noselfshadow)
3658 // render lighting using the depth texture as shadowmap
3659 // draw lighting in the unmasked areas
3660 R_Shadow_RenderMode_Lighting(false, false, true);
3661 for (i = 0;i < numlightentities_noselfshadow;i++)
3662 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3665 // render shadow casters into 6 sided depth texture
3666 if (numshadowentities_noselfshadow)
3668 for (side = 0;side < 6;side++) if ((receivermask & castermask) & (1 << side))
3670 R_Shadow_RenderMode_ShadowMap(side, 0, size);
3671 for (i = 0;i < numshadowentities_noselfshadow;i++) if (entitysides_noselfshadow[i] & (1 << side))
3672 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3676 // render lighting using the depth texture as shadowmap
3677 // draw lighting in the unmasked areas
3678 R_Shadow_RenderMode_Lighting(false, false, true);
3679 // draw lighting in the unmasked areas
3681 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3682 for (i = 0;i < numlightentities;i++)
3683 R_Shadow_DrawEntityLight(lightentities[i]);
3685 else if (castshadows && vid.stencil)
3687 // draw stencil shadow volumes to mask off pixels that are in shadow
3688 // so that they won't receive lighting
3689 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
3690 R_Shadow_ClearStencil();
3693 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
3694 for (i = 0;i < numshadowentities;i++)
3695 R_Shadow_DrawEntityShadow(shadowentities[i]);
3697 // draw lighting in the unmasked areas
3698 R_Shadow_RenderMode_Lighting(true, false, false);
3699 for (i = 0;i < numlightentities_noselfshadow;i++)
3700 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3702 for (i = 0;i < numshadowentities_noselfshadow;i++)
3703 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3705 // draw lighting in the unmasked areas
3706 R_Shadow_RenderMode_Lighting(true, false, false);
3708 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3709 for (i = 0;i < numlightentities;i++)
3710 R_Shadow_DrawEntityLight(lightentities[i]);
3714 // draw lighting in the unmasked areas
3715 R_Shadow_RenderMode_Lighting(false, false, false);
3717 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3718 for (i = 0;i < numlightentities;i++)
3719 R_Shadow_DrawEntityLight(lightentities[i]);
3720 for (i = 0;i < numlightentities_noselfshadow;i++)
3721 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3724 if (r_shadow_usingdeferredprepass)
3726 // when rendering deferred lighting, we simply rasterize the box
3727 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
3728 R_Shadow_RenderMode_DrawDeferredLight(false, true);
3729 else if (castshadows && vid.stencil)
3730 R_Shadow_RenderMode_DrawDeferredLight(true, false);
3732 R_Shadow_RenderMode_DrawDeferredLight(false, false);
3736 static void R_Shadow_FreeDeferred(void)
3738 R_Mesh_DestroyFramebufferObject(r_shadow_prepassgeometryfbo);
3739 r_shadow_prepassgeometryfbo = 0;
3741 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingfbo);
3742 r_shadow_prepasslightingfbo = 0;
3744 if (r_shadow_prepassgeometrydepthtexture)
3745 R_FreeTexture(r_shadow_prepassgeometrydepthtexture);
3746 r_shadow_prepassgeometrydepthtexture = NULL;
3748 if (r_shadow_prepassgeometrydepthcolortexture)
3749 R_FreeTexture(r_shadow_prepassgeometrydepthcolortexture);
3750 r_shadow_prepassgeometrydepthcolortexture = NULL;
3752 if (r_shadow_prepassgeometrynormalmaptexture)
3753 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
3754 r_shadow_prepassgeometrynormalmaptexture = NULL;
3756 if (r_shadow_prepasslightingdiffusetexture)
3757 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
3758 r_shadow_prepasslightingdiffusetexture = NULL;
3760 if (r_shadow_prepasslightingspeculartexture)
3761 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
3762 r_shadow_prepasslightingspeculartexture = NULL;
3765 void R_Shadow_DrawPrepass(void)
3773 entity_render_t *ent;
3774 float clearcolor[4];
3776 GL_AlphaTest(false);
3777 R_Mesh_ResetTextureState();
3779 GL_ColorMask(1,1,1,1);
3780 GL_BlendFunc(GL_ONE, GL_ZERO);
3783 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, r_shadow_prepassgeometrydepthcolortexture, NULL, NULL);
3784 Vector4Set(clearcolor, 0.5f,0.5f,0.5f,1.0f);
3785 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
3786 if (r_timereport_active)
3787 R_TimeReport("prepasscleargeom");
3789 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
3790 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
3791 if (r_timereport_active)
3792 R_TimeReport("prepassworld");
3794 for (i = 0;i < r_refdef.scene.numentities;i++)
3796 if (!r_refdef.viewcache.entityvisible[i])
3798 ent = r_refdef.scene.entities[i];
3799 if (ent->model && ent->model->DrawPrepass != NULL)
3800 ent->model->DrawPrepass(ent);
3803 if (r_timereport_active)
3804 R_TimeReport("prepassmodels");
3806 GL_DepthMask(false);
3807 GL_ColorMask(1,1,1,1);
3810 R_Mesh_SetRenderTargets(r_shadow_prepasslightingfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
3811 Vector4Set(clearcolor, 0, 0, 0, 0);
3812 GL_Clear(GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
3813 if (r_timereport_active)
3814 R_TimeReport("prepassclearlit");
3816 R_Shadow_RenderMode_Begin();
3818 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3819 if (r_shadow_debuglight.integer >= 0)
3821 lightindex = r_shadow_debuglight.integer;
3822 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3823 if (light && (light->flags & flag) && light->rtlight.draw)
3824 R_Shadow_DrawLight(&light->rtlight);
3828 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3829 for (lightindex = 0;lightindex < range;lightindex++)
3831 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3832 if (light && (light->flags & flag) && light->rtlight.draw)
3833 R_Shadow_DrawLight(&light->rtlight);
3836 if (r_refdef.scene.rtdlight)
3837 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
3838 if (r_refdef.scene.lights[lnum]->draw)
3839 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
3841 R_Mesh_ResetRenderTargets();
3843 R_Shadow_RenderMode_End();
3845 if (r_timereport_active)
3846 R_TimeReport("prepasslights");
3849 void R_Shadow_DrawLightSprites(void);
3850 void R_Shadow_PrepareLights(void)
3860 if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4) ||
3861 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
3862 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20) ||
3863 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
3864 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
3865 r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
3866 R_Shadow_FreeShadowMaps();
3868 r_shadow_usingshadowmaportho = false;
3870 switch (vid.renderpath)
3872 case RENDERPATH_GL20:
3873 case RENDERPATH_CGGL:
3874 case RENDERPATH_D3D9:
3875 case RENDERPATH_D3D10:
3876 case RENDERPATH_D3D11:
3877 if (!r_shadow_deferred.integer || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_STENCIL || !vid.support.ext_framebuffer_object || vid.maxdrawbuffers < 2)
3879 r_shadow_usingdeferredprepass = false;
3880 if (r_shadow_prepass_width)
3881 R_Shadow_FreeDeferred();
3882 r_shadow_prepass_width = r_shadow_prepass_height = 0;
3886 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
3888 R_Shadow_FreeDeferred();
3890 r_shadow_usingdeferredprepass = true;
3891 r_shadow_prepass_width = vid.width;
3892 r_shadow_prepass_height = vid.height;
3893 r_shadow_prepassgeometrydepthtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "prepassgeometrydepthmap", vid.width, vid.height, 24, false);
3894 switch (vid.renderpath)
3896 case RENDERPATH_D3D9:
3897 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);
3902 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);
3903 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);
3904 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);
3906 // set up the geometry pass fbo (depth + normalmap)
3907 r_shadow_prepassgeometryfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
3908 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, r_shadow_prepassgeometrydepthcolortexture, NULL, NULL);
3909 // render depth into one texture and normalmap into the other
3910 if (qglDrawBuffersARB)
3912 qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);CHECKGLERROR
3913 qglReadBuffer(GL_NONE);CHECKGLERROR
3914 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
3915 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
3917 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
3918 Cvar_SetValueQuick(&r_shadow_deferred, 0);
3919 r_shadow_usingdeferredprepass = false;
3923 // set up the lighting pass fbo (diffuse + specular)
3924 r_shadow_prepasslightingfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
3925 R_Mesh_SetRenderTargets(r_shadow_prepasslightingfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
3926 // render diffuse into one texture and specular into another,
3927 // with depth and normalmap bound as textures,
3928 // with depth bound as attachment as well
3929 if (qglDrawBuffersARB)
3931 qglDrawBuffersARB(2, r_shadow_prepasslightingdrawbuffers);CHECKGLERROR
3932 qglReadBuffer(GL_NONE);CHECKGLERROR
3933 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
3934 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
3936 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
3937 Cvar_SetValueQuick(&r_shadow_deferred, 0);
3938 r_shadow_usingdeferredprepass = false;
3943 case RENDERPATH_GL13:
3944 case RENDERPATH_GL11:
3945 r_shadow_usingdeferredprepass = false;
3949 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);
3951 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3952 if (r_shadow_debuglight.integer >= 0)
3954 lightindex = r_shadow_debuglight.integer;
3955 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3956 if (light && (light->flags & flag))
3957 R_Shadow_PrepareLight(&light->rtlight);
3961 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3962 for (lightindex = 0;lightindex < range;lightindex++)
3964 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3965 if (light && (light->flags & flag))
3966 R_Shadow_PrepareLight(&light->rtlight);
3969 if (r_refdef.scene.rtdlight)
3971 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
3972 R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
3974 else if(gl_flashblend.integer)
3976 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
3978 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
3979 f = (rtlight->style >= 0 ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3980 VectorScale(rtlight->color, f, rtlight->currentcolor);
3984 if (r_editlights.integer)
3985 R_Shadow_DrawLightSprites();
3988 void R_Shadow_DrawLights(void)
3996 R_Shadow_RenderMode_Begin();
3998 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3999 if (r_shadow_debuglight.integer >= 0)
4001 lightindex = r_shadow_debuglight.integer;
4002 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4003 if (light && (light->flags & flag))
4004 R_Shadow_DrawLight(&light->rtlight);
4008 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4009 for (lightindex = 0;lightindex < range;lightindex++)
4011 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4012 if (light && (light->flags & flag))
4013 R_Shadow_DrawLight(&light->rtlight);
4016 if (r_refdef.scene.rtdlight)
4017 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4018 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4020 R_Shadow_RenderMode_End();
4023 extern const float r_screenvertex3f[12];
4024 extern void R_SetupView(qboolean allowwaterclippingplane);
4025 extern void R_ResetViewRendering3D(void);
4026 extern void R_ResetViewRendering2D(void);
4027 extern cvar_t r_shadows;
4028 extern cvar_t r_shadows_darken;
4029 extern cvar_t r_shadows_drawafterrtlighting;
4030 extern cvar_t r_shadows_castfrombmodels;
4031 extern cvar_t r_shadows_throwdistance;
4032 extern cvar_t r_shadows_throwdirection;
4033 extern cvar_t r_shadows_focus;
4034 extern cvar_t r_shadows_shadowmapscale;
4036 void R_Shadow_PrepareModelShadows(void)
4039 float scale, size, radius, dot1, dot2;
4040 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
4041 entity_render_t *ent;
4043 if (!r_refdef.scene.numentities)
4046 switch (r_shadow_shadowmode)
4048 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4049 if (r_shadows.integer >= 2)
4052 case R_SHADOW_SHADOWMODE_STENCIL:
4053 for (i = 0;i < r_refdef.scene.numentities;i++)
4055 ent = r_refdef.scene.entities[i];
4056 if (!ent->animcache_vertex3f && ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4057 R_AnimCache_GetEntity(ent, false, false);
4064 size = 2*r_shadow_shadowmapmaxsize;
4065 scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
4066 radius = 0.5f * size / scale;
4068 Math_atov(r_shadows_throwdirection.string, shadowdir);
4069 VectorNormalize(shadowdir);
4070 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4071 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4072 if (fabs(dot1) <= fabs(dot2))
4073 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4075 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4076 VectorNormalize(shadowforward);
4077 CrossProduct(shadowdir, shadowforward, shadowright);
4078 Math_atov(r_shadows_focus.string, shadowfocus);
4079 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4080 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4081 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4082 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4083 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4085 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4087 shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4088 shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4089 shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4090 shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4091 shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4092 shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4094 for (i = 0;i < r_refdef.scene.numentities;i++)
4096 ent = r_refdef.scene.entities[i];
4097 if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
4099 // cast shadows from anything of the map (submodels are optional)
4100 if (!ent->animcache_vertex3f && ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4101 R_AnimCache_GetEntity(ent, false, false);
4105 void R_DrawModelShadowMaps(void)
4108 float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
4109 entity_render_t *ent;
4110 vec3_t relativelightorigin;
4111 vec3_t relativelightdirection, relativeforward, relativeright;
4112 vec3_t relativeshadowmins, relativeshadowmaxs;
4113 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
4115 matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
4116 r_viewport_t viewport;
4118 float clearcolor[4];
4120 if (!r_refdef.scene.numentities)
4123 switch (r_shadow_shadowmode)
4125 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4131 R_ResetViewRendering3D();
4132 R_Shadow_RenderMode_Begin();
4133 R_Shadow_RenderMode_ActiveLight(NULL);
4135 switch (r_shadow_shadowmode)
4137 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4138 if (!r_shadow_shadowmap2dtexture)
4139 R_Shadow_MakeShadowMap(0, r_shadow_shadowmapmaxsize);
4140 fbo = r_shadow_fbo2d;
4141 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
4142 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
4143 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
4149 size = 2*r_shadow_shadowmapmaxsize;
4150 scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
4151 radius = 0.5f / scale;
4152 nearclip = -r_shadows_throwdistance.value;
4153 farclip = r_shadows_throwdistance.value;
4154 bias = r_shadow_shadowmapping_bias.value * r_shadow_shadowmapping_nearclip.value / (2 * r_shadows_throwdistance.value) * (1024.0f / size);
4156 r_shadow_shadowmap_parameters[0] = size;
4157 r_shadow_shadowmap_parameters[1] = size;
4158 r_shadow_shadowmap_parameters[2] = 1.0;
4159 r_shadow_shadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
4161 Math_atov(r_shadows_throwdirection.string, shadowdir);
4162 VectorNormalize(shadowdir);
4163 Math_atov(r_shadows_focus.string, shadowfocus);
4164 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4165 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4166 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4167 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4168 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4169 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4170 if (fabs(dot1) <= fabs(dot2))
4171 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4173 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4174 VectorNormalize(shadowforward);
4175 VectorM(scale, shadowforward, &m[0]);
4176 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4178 m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
4179 CrossProduct(shadowdir, shadowforward, shadowright);
4180 VectorM(scale, shadowright, &m[4]);
4181 m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
4182 VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
4183 m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
4184 Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
4185 Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
4186 R_Viewport_InitOrtho(&viewport, &cameramatrix, 0, 0, size, size, 0, 0, 1, 1, 0, -1, NULL);
4188 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4190 R_Mesh_SetRenderTargets(fbo, r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
4191 R_SetupShader_DepthOrShadow();
4192 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
4195 R_SetViewport(&viewport);
4196 GL_Scissor(viewport.x, viewport.y, min(viewport.width + r_shadow_shadowmapborder, 2*r_shadow_shadowmapmaxsize), viewport.height + r_shadow_shadowmapborder);
4197 Vector4Set(clearcolor, 1,1,1,1);
4198 // in D3D9 we have to render to a color texture shadowmap
4199 // in GL we render directly to a depth texture only
4200 if (r_shadow_shadowmap2dtexture)
4201 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4203 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4204 // render into a slightly restricted region so that the borders of the
4205 // shadowmap area fade away, rather than streaking across everything
4206 // outside the usable area
4207 GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
4211 R_Mesh_ResetRenderTargets();
4212 R_SetupShader_ShowDepth();
4213 GL_ColorMask(1,1,1,1);
4214 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4217 for (i = 0;i < r_refdef.scene.numentities;i++)
4219 ent = r_refdef.scene.entities[i];
4221 // cast shadows from anything of the map (submodels are optional)
4222 if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4224 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4225 Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
4226 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4227 Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
4228 Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
4229 relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4230 relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4231 relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4232 relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4233 relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4234 relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4235 RSurf_ActiveModelEntity(ent, false, false, false);
4236 ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
4237 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4244 unsigned char *rawpixels = Z_Malloc(viewport.width*viewport.height*4);
4246 qglReadPixels(viewport.x, viewport.y, viewport.width, viewport.height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, rawpixels);
4248 Image_WriteTGABGRA("r_shadows_2.tga", viewport.width, viewport.height, rawpixels);
4249 Cvar_SetValueQuick(&r_test, 0);
4254 R_Shadow_RenderMode_End();
4256 Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
4257 Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
4258 Matrix4x4_CreateScale3(&scalematrix, size, -size, 1);
4259 Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
4260 Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
4261 Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
4263 switch (vid.renderpath)
4265 case RENDERPATH_GL11:
4266 case RENDERPATH_GL13:
4267 case RENDERPATH_GL20:
4268 case RENDERPATH_CGGL:
4270 case RENDERPATH_D3D9:
4271 case RENDERPATH_D3D10:
4272 case RENDERPATH_D3D11:
4273 #ifdef OPENGL_ORIENTATION
4274 r_shadow_shadowmapmatrix.m[0][0] *= -1.0f;
4275 r_shadow_shadowmapmatrix.m[0][1] *= -1.0f;
4276 r_shadow_shadowmapmatrix.m[0][2] *= -1.0f;
4277 r_shadow_shadowmapmatrix.m[0][3] *= -1.0f;
4279 r_shadow_shadowmapmatrix.m[0][0] *= -1.0f;
4280 r_shadow_shadowmapmatrix.m[1][0] *= -1.0f;
4281 r_shadow_shadowmapmatrix.m[2][0] *= -1.0f;
4282 r_shadow_shadowmapmatrix.m[3][0] *= -1.0f;
4287 r_shadow_usingshadowmaportho = true;
4288 switch (r_shadow_shadowmode)
4290 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4291 r_shadow_usingshadowmap2d = true;
4298 void R_DrawModelShadows(void)
4301 float relativethrowdistance;
4302 entity_render_t *ent;
4303 vec3_t relativelightorigin;
4304 vec3_t relativelightdirection;
4305 vec3_t relativeshadowmins, relativeshadowmaxs;
4306 vec3_t tmp, shadowdir;
4308 if (!r_refdef.scene.numentities || !vid.stencil || (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL && r_shadows.integer != 1))
4311 R_ResetViewRendering3D();
4312 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4313 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4314 R_Shadow_RenderMode_Begin();
4315 R_Shadow_RenderMode_ActiveLight(NULL);
4316 r_shadow_lightscissor[0] = r_refdef.view.x;
4317 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
4318 r_shadow_lightscissor[2] = r_refdef.view.width;
4319 r_shadow_lightscissor[3] = r_refdef.view.height;
4320 R_Shadow_RenderMode_StencilShadowVolumes(false);
4323 if (r_shadows.integer == 2)
4325 Math_atov(r_shadows_throwdirection.string, shadowdir);
4326 VectorNormalize(shadowdir);
4329 R_Shadow_ClearStencil();
4331 for (i = 0;i < r_refdef.scene.numentities;i++)
4333 ent = r_refdef.scene.entities[i];
4335 // cast shadows from anything of the map (submodels are optional)
4336 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4338 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4339 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
4340 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
4341 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
4342 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4345 if(ent->entitynumber != 0)
4347 if(ent->entitynumber >= MAX_EDICTS) // csqc entity
4349 // FIXME handle this
4350 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4354 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
4355 int entnum, entnum2, recursion;
4356 entnum = entnum2 = ent->entitynumber;
4357 for(recursion = 32; recursion > 0; --recursion)
4359 entnum2 = cl.entities[entnum].state_current.tagentity;
4360 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
4365 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
4367 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
4368 // transform into modelspace of OUR entity
4369 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
4370 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
4373 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4377 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4380 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
4381 RSurf_ActiveModelEntity(ent, false, false, false);
4382 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4383 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4387 // not really the right mode, but this will disable any silly stencil features
4388 R_Shadow_RenderMode_End();
4390 // set up ortho view for rendering this pass
4391 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4392 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4393 //GL_ScissorTest(true);
4394 //R_EntityMatrix(&identitymatrix);
4395 //R_Mesh_ResetTextureState();
4396 R_ResetViewRendering2D();
4398 // set up a darkening blend on shadowed areas
4399 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4400 //GL_DepthRange(0, 1);
4401 //GL_DepthTest(false);
4402 //GL_DepthMask(false);
4403 //GL_PolygonOffset(0, 0);CHECKGLERROR
4404 GL_Color(0, 0, 0, r_shadows_darken.value);
4405 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4406 //GL_DepthFunc(GL_ALWAYS);
4407 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_NOTEQUAL, 128, 255);
4409 // apply the blend to the shadowed areas
4410 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, NULL);
4411 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
4412 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4414 // restore the viewport
4415 R_SetViewport(&r_refdef.view.viewport);
4417 // restore other state to normal
4418 //R_Shadow_RenderMode_End();
4421 void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4424 vec3_t centerorigin;
4426 // if it's too close, skip it
4427 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
4429 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4432 if (usequery && r_numqueries + 2 <= r_maxqueries)
4434 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4435 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4436 // 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
4437 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4439 switch(vid.renderpath)
4441 case RENDERPATH_GL20:
4442 case RENDERPATH_GL13:
4443 case RENDERPATH_GL11:
4444 case RENDERPATH_CGGL:
4446 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use GL_DepthFunc instead
4447 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
4448 GL_DepthFunc(GL_ALWAYS);
4449 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4450 R_Mesh_PrepareVertices_Position_Arrays(4, vertex3f);
4451 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4452 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4453 GL_DepthFunc(GL_LEQUAL);
4454 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
4455 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4456 R_Mesh_PrepareVertices_Position_Arrays(4, vertex3f);
4457 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4458 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4461 case RENDERPATH_D3D9:
4462 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4464 case RENDERPATH_D3D10:
4465 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4467 case RENDERPATH_D3D11:
4468 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4472 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4475 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
4477 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4480 GLint allpixels = 0, visiblepixels = 0;
4481 // now we have to check the query result
4482 if (rtlight->corona_queryindex_visiblepixels)
4484 switch(vid.renderpath)
4486 case RENDERPATH_GL20:
4487 case RENDERPATH_GL13:
4488 case RENDERPATH_GL11:
4489 case RENDERPATH_CGGL:
4491 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
4492 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
4495 case RENDERPATH_D3D9:
4496 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4498 case RENDERPATH_D3D10:
4499 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4501 case RENDERPATH_D3D11:
4502 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4505 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
4506 if (visiblepixels < 1 || allpixels < 1)
4508 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
4509 cscale *= rtlight->corona_visibility;
4513 // FIXME: these traces should scan all render entities instead of cl.world
4514 if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
4517 VectorScale(rtlight->currentcolor, cscale, color);
4518 if (VectorLength(color) > (1.0f / 256.0f))
4521 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
4524 VectorNegate(color, color);
4525 switch(vid.renderpath)
4527 case RENDERPATH_GL11:
4528 case RENDERPATH_GL13:
4529 case RENDERPATH_GL20:
4530 case RENDERPATH_CGGL:
4531 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
4533 case RENDERPATH_D3D9:
4535 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_SUBTRACT);
4538 case RENDERPATH_D3D10:
4539 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4541 case RENDERPATH_D3D11:
4542 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4546 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4547 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);
4548 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4551 switch(vid.renderpath)
4553 case RENDERPATH_GL11:
4554 case RENDERPATH_GL13:
4555 case RENDERPATH_GL20:
4556 case RENDERPATH_CGGL:
4557 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
4559 case RENDERPATH_D3D9:
4561 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_ADD);
4564 case RENDERPATH_D3D10:
4565 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4567 case RENDERPATH_D3D11:
4568 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4575 void R_Shadow_DrawCoronas(void)
4578 qboolean usequery = false;
4583 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4585 if (r_waterstate.renderingscene)
4587 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4588 R_EntityMatrix(&identitymatrix);
4590 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4592 // check occlusion of coronas
4593 // use GL_ARB_occlusion_query if available
4594 // otherwise use raytraces
4596 switch (vid.renderpath)
4598 case RENDERPATH_GL11:
4599 case RENDERPATH_GL13:
4600 case RENDERPATH_GL20:
4601 case RENDERPATH_CGGL:
4602 usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
4605 GL_ColorMask(0,0,0,0);
4606 if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
4607 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
4610 r_maxqueries = (range + r_refdef.scene.numlights) * 4;
4611 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
4613 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
4616 RSurf_ActiveWorldEntity();
4617 GL_BlendFunc(GL_ONE, GL_ZERO);
4618 GL_CullFace(GL_NONE);
4619 GL_DepthMask(false);
4620 GL_DepthRange(0, 1);
4621 GL_PolygonOffset(0, 0);
4623 R_Mesh_ResetTextureState();
4624 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
4627 case RENDERPATH_D3D9:
4629 //Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4631 case RENDERPATH_D3D10:
4632 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4634 case RENDERPATH_D3D11:
4635 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4638 for (lightindex = 0;lightindex < range;lightindex++)
4640 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4643 rtlight = &light->rtlight;
4644 rtlight->corona_visibility = 0;
4645 rtlight->corona_queryindex_visiblepixels = 0;
4646 rtlight->corona_queryindex_allpixels = 0;
4647 if (!(rtlight->flags & flag))
4649 if (rtlight->corona <= 0)
4651 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4653 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4655 for (i = 0;i < r_refdef.scene.numlights;i++)
4657 rtlight = r_refdef.scene.lights[i];
4658 rtlight->corona_visibility = 0;
4659 rtlight->corona_queryindex_visiblepixels = 0;
4660 rtlight->corona_queryindex_allpixels = 0;
4661 if (!(rtlight->flags & flag))
4663 if (rtlight->corona <= 0)
4665 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4668 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4670 // now draw the coronas using the query data for intensity info
4671 for (lightindex = 0;lightindex < range;lightindex++)
4673 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4676 rtlight = &light->rtlight;
4677 if (rtlight->corona_visibility <= 0)
4679 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4681 for (i = 0;i < r_refdef.scene.numlights;i++)
4683 rtlight = r_refdef.scene.lights[i];
4684 if (rtlight->corona_visibility <= 0)
4686 if (gl_flashblend.integer)
4687 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4689 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4695 dlight_t *R_Shadow_NewWorldLight(void)
4697 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4700 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)
4703 // validate parameters
4704 if (style < 0 || style >= MAX_LIGHTSTYLES)
4706 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
4712 // copy to light properties
4713 VectorCopy(origin, light->origin);
4714 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4715 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4716 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4718 light->color[0] = max(color[0], 0);
4719 light->color[1] = max(color[1], 0);
4720 light->color[2] = max(color[2], 0);
4722 light->color[0] = color[0];
4723 light->color[1] = color[1];
4724 light->color[2] = color[2];
4725 light->radius = max(radius, 0);
4726 light->style = style;
4727 light->shadow = shadowenable;
4728 light->corona = corona;
4729 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4730 light->coronasizescale = coronasizescale;
4731 light->ambientscale = ambientscale;
4732 light->diffusescale = diffusescale;
4733 light->specularscale = specularscale;
4734 light->flags = flags;
4736 // update renderable light data
4737 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4738 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);
4741 void R_Shadow_FreeWorldLight(dlight_t *light)
4743 if (r_shadow_selectedlight == light)
4744 r_shadow_selectedlight = NULL;
4745 R_RTLight_Uncompile(&light->rtlight);
4746 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4749 void R_Shadow_ClearWorldLights(void)
4753 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4754 for (lightindex = 0;lightindex < range;lightindex++)
4756 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4758 R_Shadow_FreeWorldLight(light);
4760 r_shadow_selectedlight = NULL;
4763 void R_Shadow_SelectLight(dlight_t *light)
4765 if (r_shadow_selectedlight)
4766 r_shadow_selectedlight->selected = false;
4767 r_shadow_selectedlight = light;
4768 if (r_shadow_selectedlight)
4769 r_shadow_selectedlight->selected = true;
4772 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4774 // this is never batched (there can be only one)
4776 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
4777 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4778 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4781 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4786 skinframe_t *skinframe;
4789 // this is never batched (due to the ent parameter changing every time)
4790 // so numsurfaces == 1 and surfacelist[0] == lightnumber
4791 const dlight_t *light = (dlight_t *)ent;
4794 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
4797 VectorScale(light->color, intensity, spritecolor);
4798 if (VectorLength(spritecolor) < 0.1732f)
4799 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
4800 if (VectorLength(spritecolor) > 1.0f)
4801 VectorNormalize(spritecolor);
4803 // draw light sprite
4804 if (light->cubemapname[0] && !light->shadow)
4805 skinframe = r_editlights_sprcubemapnoshadowlight;
4806 else if (light->cubemapname[0])
4807 skinframe = r_editlights_sprcubemaplight;
4808 else if (!light->shadow)
4809 skinframe = r_editlights_sprnoshadowlight;
4811 skinframe = r_editlights_sprlight;
4813 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);
4814 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4816 // draw selection sprite if light is selected
4817 if (light->selected)
4819 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4820 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4821 // VorteX todo: add normalmode/realtime mode light overlay sprites?
4825 void R_Shadow_DrawLightSprites(void)
4829 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4830 for (lightindex = 0;lightindex < range;lightindex++)
4832 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4834 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
4836 if (!r_editlights_lockcursor)
4837 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
4840 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
4845 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
4846 if (lightindex >= range)
4848 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4851 rtlight = &light->rtlight;
4852 //if (!(rtlight->flags & flag))
4854 VectorCopy(rtlight->shadoworigin, origin);
4855 *radius = rtlight->radius;
4856 VectorCopy(rtlight->color, color);
4860 void R_Shadow_SelectLightInView(void)
4862 float bestrating, rating, temp[3];
4866 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4870 if (r_editlights_lockcursor)
4872 for (lightindex = 0;lightindex < range;lightindex++)
4874 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4877 VectorSubtract(light->origin, r_refdef.view.origin, temp);
4878 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
4881 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
4882 if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1.0f)
4884 bestrating = rating;
4889 R_Shadow_SelectLight(best);
4892 void R_Shadow_LoadWorldLights(void)
4894 int n, a, style, shadow, flags;
4895 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
4896 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
4897 if (cl.worldmodel == NULL)
4899 Con_Print("No map loaded.\n");
4902 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
4903 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4913 for (;COM_Parse(t, true) && strcmp(
4914 if (COM_Parse(t, true))
4916 if (com_token[0] == '!')
4919 origin[0] = atof(com_token+1);
4922 origin[0] = atof(com_token);
4927 while (*s && *s != '\n' && *s != '\r')
4933 // check for modifier flags
4940 #if _MSC_VER >= 1400
4941 #define sscanf sscanf_s
4943 cubemapname[sizeof(cubemapname)-1] = 0;
4944 #if MAX_QPATH != 128
4945 #error update this code if MAX_QPATH changes
4947 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
4948 #if _MSC_VER >= 1400
4949 , sizeof(cubemapname)
4951 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
4954 flags = LIGHTFLAG_REALTIMEMODE;
4962 coronasizescale = 0.25f;
4964 VectorClear(angles);
4967 if (a < 9 || !strcmp(cubemapname, "\"\""))
4969 // remove quotes on cubemapname
4970 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
4973 namelen = strlen(cubemapname) - 2;
4974 memmove(cubemapname, cubemapname + 1, namelen);
4975 cubemapname[namelen] = '\0';
4979 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);
4982 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4990 Con_Printf("invalid rtlights file \"%s\"\n", name);
4991 Mem_Free(lightsstring);
4995 void R_Shadow_SaveWorldLights(void)
4999 size_t bufchars, bufmaxchars;
5001 char name[MAX_QPATH];
5002 char line[MAX_INPUTLINE];
5003 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
5004 // I hate lines which are 3 times my screen size :( --blub
5007 if (cl.worldmodel == NULL)
5009 Con_Print("No map loaded.\n");
5012 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
5013 bufchars = bufmaxchars = 0;
5015 for (lightindex = 0;lightindex < range;lightindex++)
5017 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5020 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
5021 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);
5022 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
5023 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]);
5025 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);
5026 if (bufchars + strlen(line) > bufmaxchars)
5028 bufmaxchars = bufchars + strlen(line) + 2048;
5030 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
5034 memcpy(buf, oldbuf, bufchars);
5040 memcpy(buf + bufchars, line, strlen(line));
5041 bufchars += strlen(line);
5045 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
5050 void R_Shadow_LoadLightsFile(void)
5053 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
5054 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
5055 if (cl.worldmodel == NULL)
5057 Con_Print("No map loaded.\n");
5060 dpsnprintf(name, sizeof(name), "%s.lights", cl.worldnamenoextension);
5061 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5069 while (*s && *s != '\n' && *s != '\r')
5075 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);
5079 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);
5082 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
5083 radius = bound(15, radius, 4096);
5084 VectorScale(color, (2.0f / (8388608.0f)), color);
5085 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5093 Con_Printf("invalid lights file \"%s\"\n", name);
5094 Mem_Free(lightsstring);
5098 // tyrlite/hmap2 light types in the delay field
5099 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
5101 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
5113 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
5114 char key[256], value[MAX_INPUTLINE];
5116 if (cl.worldmodel == NULL)
5118 Con_Print("No map loaded.\n");
5121 // try to load a .ent file first
5122 dpsnprintf(key, sizeof(key), "%s.ent", cl.worldnamenoextension);
5123 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
5124 // and if that is not found, fall back to the bsp file entity string
5126 data = cl.worldmodel->brush.entities;
5129 for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
5131 type = LIGHTTYPE_MINUSX;
5132 origin[0] = origin[1] = origin[2] = 0;
5133 originhack[0] = originhack[1] = originhack[2] = 0;
5134 angles[0] = angles[1] = angles[2] = 0;
5135 color[0] = color[1] = color[2] = 1;
5136 light[0] = light[1] = light[2] = 1;light[3] = 300;
5137 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
5147 if (!COM_ParseToken_Simple(&data, false, false))
5149 if (com_token[0] == '}')
5150 break; // end of entity
5151 if (com_token[0] == '_')
5152 strlcpy(key, com_token + 1, sizeof(key));
5154 strlcpy(key, com_token, sizeof(key));
5155 while (key[strlen(key)-1] == ' ') // remove trailing spaces
5156 key[strlen(key)-1] = 0;
5157 if (!COM_ParseToken_Simple(&data, false, false))
5159 strlcpy(value, com_token, sizeof(value));
5161 // now that we have the key pair worked out...
5162 if (!strcmp("light", key))
5164 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5168 light[0] = vec[0] * (1.0f / 256.0f);
5169 light[1] = vec[0] * (1.0f / 256.0f);
5170 light[2] = vec[0] * (1.0f / 256.0f);
5176 light[0] = vec[0] * (1.0f / 255.0f);
5177 light[1] = vec[1] * (1.0f / 255.0f);
5178 light[2] = vec[2] * (1.0f / 255.0f);
5182 else if (!strcmp("delay", key))
5184 else if (!strcmp("origin", key))
5185 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5186 else if (!strcmp("angle", key))
5187 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5188 else if (!strcmp("angles", key))
5189 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5190 else if (!strcmp("color", key))
5191 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5192 else if (!strcmp("wait", key))
5193 fadescale = atof(value);
5194 else if (!strcmp("classname", key))
5196 if (!strncmp(value, "light", 5))
5199 if (!strcmp(value, "light_fluoro"))
5204 overridecolor[0] = 1;
5205 overridecolor[1] = 1;
5206 overridecolor[2] = 1;
5208 if (!strcmp(value, "light_fluorospark"))
5213 overridecolor[0] = 1;
5214 overridecolor[1] = 1;
5215 overridecolor[2] = 1;
5217 if (!strcmp(value, "light_globe"))
5222 overridecolor[0] = 1;
5223 overridecolor[1] = 0.8;
5224 overridecolor[2] = 0.4;
5226 if (!strcmp(value, "light_flame_large_yellow"))
5231 overridecolor[0] = 1;
5232 overridecolor[1] = 0.5;
5233 overridecolor[2] = 0.1;
5235 if (!strcmp(value, "light_flame_small_yellow"))
5240 overridecolor[0] = 1;
5241 overridecolor[1] = 0.5;
5242 overridecolor[2] = 0.1;
5244 if (!strcmp(value, "light_torch_small_white"))
5249 overridecolor[0] = 1;
5250 overridecolor[1] = 0.5;
5251 overridecolor[2] = 0.1;
5253 if (!strcmp(value, "light_torch_small_walltorch"))
5258 overridecolor[0] = 1;
5259 overridecolor[1] = 0.5;
5260 overridecolor[2] = 0.1;
5264 else if (!strcmp("style", key))
5265 style = atoi(value);
5266 else if (!strcmp("skin", key))
5267 skin = (int)atof(value);
5268 else if (!strcmp("pflags", key))
5269 pflags = (int)atof(value);
5270 //else if (!strcmp("effects", key))
5271 // effects = (int)atof(value);
5272 else if (cl.worldmodel->type == mod_brushq3)
5274 if (!strcmp("scale", key))
5275 lightscale = atof(value);
5276 if (!strcmp("fade", key))
5277 fadescale = atof(value);
5282 if (lightscale <= 0)
5286 if (color[0] == color[1] && color[0] == color[2])
5288 color[0] *= overridecolor[0];
5289 color[1] *= overridecolor[1];
5290 color[2] *= overridecolor[2];
5292 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5293 color[0] = color[0] * light[0];
5294 color[1] = color[1] * light[1];
5295 color[2] = color[2] * light[2];
5298 case LIGHTTYPE_MINUSX:
5300 case LIGHTTYPE_RECIPX:
5302 VectorScale(color, (1.0f / 16.0f), color);
5304 case LIGHTTYPE_RECIPXX:
5306 VectorScale(color, (1.0f / 16.0f), color);
5309 case LIGHTTYPE_NONE:
5313 case LIGHTTYPE_MINUSXX:
5316 VectorAdd(origin, originhack, origin);
5318 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);
5321 Mem_Free(entfiledata);
5325 void R_Shadow_SetCursorLocationForView(void)
5328 vec3_t dest, endpos;
5330 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5331 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
5332 if (trace.fraction < 1)
5334 dist = trace.fraction * r_editlights_cursordistance.value;
5335 push = r_editlights_cursorpushback.value;
5339 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5340 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5344 VectorClear( endpos );
5346 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5347 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5348 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5351 void R_Shadow_UpdateWorldLightSelection(void)
5353 if (r_editlights.integer)
5355 R_Shadow_SetCursorLocationForView();
5356 R_Shadow_SelectLightInView();
5359 R_Shadow_SelectLight(NULL);
5362 void R_Shadow_EditLights_Clear_f(void)
5364 R_Shadow_ClearWorldLights();
5367 void R_Shadow_EditLights_Reload_f(void)
5371 strlcpy(r_shadow_mapname, cl.worldname, sizeof(r_shadow_mapname));
5372 R_Shadow_ClearWorldLights();
5373 R_Shadow_LoadWorldLights();
5374 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5376 R_Shadow_LoadLightsFile();
5377 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5378 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5382 void R_Shadow_EditLights_Save_f(void)
5386 R_Shadow_SaveWorldLights();
5389 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
5391 R_Shadow_ClearWorldLights();
5392 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5395 void R_Shadow_EditLights_ImportLightsFile_f(void)
5397 R_Shadow_ClearWorldLights();
5398 R_Shadow_LoadLightsFile();
5401 void R_Shadow_EditLights_Spawn_f(void)
5404 if (!r_editlights.integer)
5406 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5409 if (Cmd_Argc() != 1)
5411 Con_Print("r_editlights_spawn does not take parameters\n");
5414 color[0] = color[1] = color[2] = 1;
5415 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5418 void R_Shadow_EditLights_Edit_f(void)
5420 vec3_t origin, angles, color;
5421 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5422 int style, shadows, flags, normalmode, realtimemode;
5423 char cubemapname[MAX_INPUTLINE];
5424 if (!r_editlights.integer)
5426 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5429 if (!r_shadow_selectedlight)
5431 Con_Print("No selected light.\n");
5434 VectorCopy(r_shadow_selectedlight->origin, origin);
5435 VectorCopy(r_shadow_selectedlight->angles, angles);
5436 VectorCopy(r_shadow_selectedlight->color, color);
5437 radius = r_shadow_selectedlight->radius;
5438 style = r_shadow_selectedlight->style;
5439 if (r_shadow_selectedlight->cubemapname)
5440 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5443 shadows = r_shadow_selectedlight->shadow;
5444 corona = r_shadow_selectedlight->corona;
5445 coronasizescale = r_shadow_selectedlight->coronasizescale;
5446 ambientscale = r_shadow_selectedlight->ambientscale;
5447 diffusescale = r_shadow_selectedlight->diffusescale;
5448 specularscale = r_shadow_selectedlight->specularscale;
5449 flags = r_shadow_selectedlight->flags;
5450 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5451 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5452 if (!strcmp(Cmd_Argv(1), "origin"))
5454 if (Cmd_Argc() != 5)
5456 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5459 origin[0] = atof(Cmd_Argv(2));
5460 origin[1] = atof(Cmd_Argv(3));
5461 origin[2] = atof(Cmd_Argv(4));
5463 else if (!strcmp(Cmd_Argv(1), "originx"))
5465 if (Cmd_Argc() != 3)
5467 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5470 origin[0] = atof(Cmd_Argv(2));
5472 else if (!strcmp(Cmd_Argv(1), "originy"))
5474 if (Cmd_Argc() != 3)
5476 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5479 origin[1] = atof(Cmd_Argv(2));
5481 else if (!strcmp(Cmd_Argv(1), "originz"))
5483 if (Cmd_Argc() != 3)
5485 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5488 origin[2] = atof(Cmd_Argv(2));
5490 else if (!strcmp(Cmd_Argv(1), "move"))
5492 if (Cmd_Argc() != 5)
5494 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5497 origin[0] += atof(Cmd_Argv(2));
5498 origin[1] += atof(Cmd_Argv(3));
5499 origin[2] += atof(Cmd_Argv(4));
5501 else if (!strcmp(Cmd_Argv(1), "movex"))
5503 if (Cmd_Argc() != 3)
5505 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5508 origin[0] += atof(Cmd_Argv(2));
5510 else if (!strcmp(Cmd_Argv(1), "movey"))
5512 if (Cmd_Argc() != 3)
5514 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5517 origin[1] += atof(Cmd_Argv(2));
5519 else if (!strcmp(Cmd_Argv(1), "movez"))
5521 if (Cmd_Argc() != 3)
5523 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5526 origin[2] += atof(Cmd_Argv(2));
5528 else if (!strcmp(Cmd_Argv(1), "angles"))
5530 if (Cmd_Argc() != 5)
5532 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5535 angles[0] = atof(Cmd_Argv(2));
5536 angles[1] = atof(Cmd_Argv(3));
5537 angles[2] = atof(Cmd_Argv(4));
5539 else if (!strcmp(Cmd_Argv(1), "anglesx"))
5541 if (Cmd_Argc() != 3)
5543 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5546 angles[0] = atof(Cmd_Argv(2));
5548 else if (!strcmp(Cmd_Argv(1), "anglesy"))
5550 if (Cmd_Argc() != 3)
5552 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5555 angles[1] = atof(Cmd_Argv(2));
5557 else if (!strcmp(Cmd_Argv(1), "anglesz"))
5559 if (Cmd_Argc() != 3)
5561 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5564 angles[2] = atof(Cmd_Argv(2));
5566 else if (!strcmp(Cmd_Argv(1), "color"))
5568 if (Cmd_Argc() != 5)
5570 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
5573 color[0] = atof(Cmd_Argv(2));
5574 color[1] = atof(Cmd_Argv(3));
5575 color[2] = atof(Cmd_Argv(4));
5577 else if (!strcmp(Cmd_Argv(1), "radius"))
5579 if (Cmd_Argc() != 3)
5581 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5584 radius = atof(Cmd_Argv(2));
5586 else if (!strcmp(Cmd_Argv(1), "colorscale"))
5588 if (Cmd_Argc() == 3)
5590 double scale = atof(Cmd_Argv(2));
5597 if (Cmd_Argc() != 5)
5599 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
5602 color[0] *= atof(Cmd_Argv(2));
5603 color[1] *= atof(Cmd_Argv(3));
5604 color[2] *= atof(Cmd_Argv(4));
5607 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
5609 if (Cmd_Argc() != 3)
5611 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5614 radius *= atof(Cmd_Argv(2));
5616 else if (!strcmp(Cmd_Argv(1), "style"))
5618 if (Cmd_Argc() != 3)
5620 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5623 style = atoi(Cmd_Argv(2));
5625 else if (!strcmp(Cmd_Argv(1), "cubemap"))
5629 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5632 if (Cmd_Argc() == 3)
5633 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
5637 else if (!strcmp(Cmd_Argv(1), "shadows"))
5639 if (Cmd_Argc() != 3)
5641 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5644 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5646 else if (!strcmp(Cmd_Argv(1), "corona"))
5648 if (Cmd_Argc() != 3)
5650 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5653 corona = atof(Cmd_Argv(2));
5655 else if (!strcmp(Cmd_Argv(1), "coronasize"))
5657 if (Cmd_Argc() != 3)
5659 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5662 coronasizescale = atof(Cmd_Argv(2));
5664 else if (!strcmp(Cmd_Argv(1), "ambient"))
5666 if (Cmd_Argc() != 3)
5668 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5671 ambientscale = atof(Cmd_Argv(2));
5673 else if (!strcmp(Cmd_Argv(1), "diffuse"))
5675 if (Cmd_Argc() != 3)
5677 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5680 diffusescale = atof(Cmd_Argv(2));
5682 else if (!strcmp(Cmd_Argv(1), "specular"))
5684 if (Cmd_Argc() != 3)
5686 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5689 specularscale = atof(Cmd_Argv(2));
5691 else if (!strcmp(Cmd_Argv(1), "normalmode"))
5693 if (Cmd_Argc() != 3)
5695 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5698 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5700 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
5702 if (Cmd_Argc() != 3)
5704 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5707 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5711 Con_Print("usage: r_editlights_edit [property] [value]\n");
5712 Con_Print("Selected light's properties:\n");
5713 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5714 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5715 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5716 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
5717 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
5718 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
5719 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5720 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
5721 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
5722 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
5723 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
5724 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
5725 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5726 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5729 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5730 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5733 void R_Shadow_EditLights_EditAll_f(void)
5736 dlight_t *light, *oldselected;
5739 if (!r_editlights.integer)
5741 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5745 oldselected = r_shadow_selectedlight;
5746 // EditLights doesn't seem to have a "remove" command or something so:
5747 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5748 for (lightindex = 0;lightindex < range;lightindex++)
5750 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5753 R_Shadow_SelectLight(light);
5754 R_Shadow_EditLights_Edit_f();
5756 // return to old selected (to not mess editing once selection is locked)
5757 R_Shadow_SelectLight(oldselected);
5760 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
5762 int lightnumber, lightcount;
5763 size_t lightindex, range;
5767 if (!r_editlights.integer)
5769 x = vid_conwidth.value - 240;
5771 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
5774 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5775 for (lightindex = 0;lightindex < range;lightindex++)
5777 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5780 if (light == r_shadow_selectedlight)
5781 lightnumber = lightindex;
5784 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;
5785 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;
5787 if (r_shadow_selectedlight == NULL)
5789 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;
5790 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;
5791 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;
5792 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;
5793 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;
5794 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;
5795 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;
5796 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;
5797 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;
5798 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;
5799 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;
5800 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;
5801 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;
5802 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;
5803 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;
5806 void R_Shadow_EditLights_ToggleShadow_f(void)
5808 if (!r_editlights.integer)
5810 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5813 if (!r_shadow_selectedlight)
5815 Con_Print("No selected light.\n");
5818 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);
5821 void R_Shadow_EditLights_ToggleCorona_f(void)
5823 if (!r_editlights.integer)
5825 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5828 if (!r_shadow_selectedlight)
5830 Con_Print("No selected light.\n");
5833 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);
5836 void R_Shadow_EditLights_Remove_f(void)
5838 if (!r_editlights.integer)
5840 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
5843 if (!r_shadow_selectedlight)
5845 Con_Print("No selected light.\n");
5848 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
5849 r_shadow_selectedlight = NULL;
5852 void R_Shadow_EditLights_Help_f(void)
5855 "Documentation on r_editlights system:\n"
5857 "r_editlights : enable/disable editing mode\n"
5858 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
5859 "r_editlights_cursorpushback : push back cursor this far from surface\n"
5860 "r_editlights_cursorpushoff : push cursor off surface this far\n"
5861 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
5862 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
5864 "r_editlights_help : this help\n"
5865 "r_editlights_clear : remove all lights\n"
5866 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
5867 "r_editlights_lock : lock selection to current light, if already locked - unlock\n"
5868 "r_editlights_save : save to .rtlights file\n"
5869 "r_editlights_spawn : create a light with default settings\n"
5870 "r_editlights_edit command : edit selected light - more documentation below\n"
5871 "r_editlights_remove : remove selected light\n"
5872 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
5873 "r_editlights_importlightentitiesfrommap : reload light entities\n"
5874 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
5876 "origin x y z : set light location\n"
5877 "originx x: set x component of light location\n"
5878 "originy y: set y component of light location\n"
5879 "originz z: set z component of light location\n"
5880 "move x y z : adjust light location\n"
5881 "movex x: adjust x component of light location\n"
5882 "movey y: adjust y component of light location\n"
5883 "movez z: adjust z component of light location\n"
5884 "angles x y z : set light angles\n"
5885 "anglesx x: set x component of light angles\n"
5886 "anglesy y: set y component of light angles\n"
5887 "anglesz z: set z component of light angles\n"
5888 "color r g b : set color of light (can be brighter than 1 1 1)\n"
5889 "radius radius : set radius (size) of light\n"
5890 "colorscale grey : multiply color of light (1 does nothing)\n"
5891 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
5892 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
5893 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
5894 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
5895 "cubemap basename : set filter cubemap of light (not yet supported)\n"
5896 "shadows 1/0 : turn on/off shadows\n"
5897 "corona n : set corona intensity\n"
5898 "coronasize n : set corona size (0-1)\n"
5899 "ambient n : set ambient intensity (0-1)\n"
5900 "diffuse n : set diffuse intensity (0-1)\n"
5901 "specular n : set specular intensity (0-1)\n"
5902 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
5903 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
5904 "<nothing> : print light properties to console\n"
5908 void R_Shadow_EditLights_CopyInfo_f(void)
5910 if (!r_editlights.integer)
5912 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
5915 if (!r_shadow_selectedlight)
5917 Con_Print("No selected light.\n");
5920 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
5921 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
5922 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
5923 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
5924 if (r_shadow_selectedlight->cubemapname)
5925 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
5927 r_shadow_bufferlight.cubemapname[0] = 0;
5928 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
5929 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
5930 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
5931 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
5932 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
5933 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
5934 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
5937 void R_Shadow_EditLights_PasteInfo_f(void)
5939 if (!r_editlights.integer)
5941 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
5944 if (!r_shadow_selectedlight)
5946 Con_Print("No selected light.\n");
5949 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);
5952 void R_Shadow_EditLights_Lock_f(void)
5954 if (!r_editlights.integer)
5956 Con_Print("Cannot lock on light when not in editing mode. Set r_editlights to 1.\n");
5959 if (r_editlights_lockcursor)
5961 r_editlights_lockcursor = false;
5964 if (!r_shadow_selectedlight)
5966 Con_Print("No selected light to lock on.\n");
5969 r_editlights_lockcursor = true;
5972 void R_Shadow_EditLights_Init(void)
5974 Cvar_RegisterVariable(&r_editlights);
5975 Cvar_RegisterVariable(&r_editlights_cursordistance);
5976 Cvar_RegisterVariable(&r_editlights_cursorpushback);
5977 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
5978 Cvar_RegisterVariable(&r_editlights_cursorgrid);
5979 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
5980 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
5981 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
5982 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)");
5983 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
5984 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
5985 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
5986 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)");
5987 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
5988 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
5989 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
5990 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
5991 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
5992 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
5993 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)");
5994 Cmd_AddCommand("r_editlights_lock", R_Shadow_EditLights_Lock_f, "lock selection to current light, if already locked - unlock");
6000 =============================================================================
6004 =============================================================================
6007 void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, qboolean dynamic, qboolean rtworld)
6009 VectorClear(diffusecolor);
6010 VectorClear(diffusenormal);
6012 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
6014 ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_refdef.scene.ambient;
6015 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
6018 VectorSet(ambientcolor, 1, 1, 1);
6022 int i, numlights, flag;
6023 float f, relativepoint[3], dist, dist2, lightradius2;
6030 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
6031 numlights = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
6032 for (i = 0; i < numlights; i++)
6034 dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
6037 light = &dlight->rtlight;
6038 if (!(light->flags & flag))
6041 lightradius2 = light->radius * light->radius;
6042 VectorSubtract(light->shadoworigin, p, relativepoint);
6043 dist2 = VectorLength2(relativepoint);
6044 if (dist2 >= lightradius2)
6046 dist = sqrt(dist2) / light->radius;
6047 f = dist < 1 ? (r_shadow_lightintensityscale.value * ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist))) : 0;
6050 // todo: add to both ambient and diffuse
6051 if (!light->shadow || CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
6052 VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);
6057 for (i = 0;i < r_refdef.scene.numlights;i++)
6059 light = r_refdef.scene.lights[i];
6061 lightradius2 = light->radius * light->radius;
6062 VectorSubtract(light->shadoworigin, p, relativepoint);
6063 dist2 = VectorLength2(relativepoint);
6064 if (dist2 >= lightradius2)
6066 dist = sqrt(dist2) / light->radius;
6067 f = dist < 1 ? (r_shadow_lightintensityscale.value * ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist))) : 0;
6070 // todo: add to both ambient and diffuse
6071 if (!light->shadow || CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
6072 VectorMA(ambientcolor, f, light->color, ambientcolor);