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_polygonfactor = {0, "r_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
316 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)"};
317 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)"};
318 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "1", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
319 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"};
320 cvar_t r_coronas_occlusionquery = {CVAR_SAVE, "r_coronas_occlusionquery", "1", "use GL_ARB_occlusion_query extension if supported (fades coronas according to visibility)"};
321 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
322 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
323 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
324 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
325 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
326 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
327 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
328 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
329 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
331 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
332 #define ATTENTABLESIZE 256
333 // 1D gradient, 2D circle and 3D sphere attenuation textures
334 #define ATTEN1DSIZE 32
335 #define ATTEN2DSIZE 64
336 #define ATTEN3DSIZE 32
338 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
339 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
340 static float r_shadow_attentable[ATTENTABLESIZE+1];
342 rtlight_t *r_shadow_compilingrtlight;
343 static memexpandablearray_t r_shadow_worldlightsarray;
344 dlight_t *r_shadow_selectedlight;
345 dlight_t r_shadow_bufferlight;
346 vec3_t r_editlights_cursorlocation;
347 qboolean r_editlights_lockcursor;
349 extern int con_vislines;
351 void R_Shadow_UncompileWorldLights(void);
352 void R_Shadow_ClearWorldLights(void);
353 void R_Shadow_SaveWorldLights(void);
354 void R_Shadow_LoadWorldLights(void);
355 void R_Shadow_LoadLightsFile(void);
356 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
357 void R_Shadow_EditLights_Reload_f(void);
358 void R_Shadow_ValidateCvars(void);
359 static void R_Shadow_MakeTextures(void);
361 #define EDLIGHTSPRSIZE 8
362 skinframe_t *r_editlights_sprcursor;
363 skinframe_t *r_editlights_sprlight;
364 skinframe_t *r_editlights_sprnoshadowlight;
365 skinframe_t *r_editlights_sprcubemaplight;
366 skinframe_t *r_editlights_sprcubemapnoshadowlight;
367 skinframe_t *r_editlights_sprselection;
369 void R_Shadow_SetShadowMode(void)
371 r_shadow_shadowmapmaxsize = bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4);
372 r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20;
373 r_shadow_shadowmapfilterquality = r_shadow_shadowmapping_filterquality.integer;
374 r_shadow_shadowmapdepthbits = r_shadow_shadowmapping_depthbits.integer;
375 r_shadow_shadowmapborder = bound(0, r_shadow_shadowmapping_bordersize.integer, 16);
376 r_shadow_shadowmaplod = -1;
377 r_shadow_shadowmapsize = 0;
378 r_shadow_shadowmapsampler = false;
379 r_shadow_shadowmappcf = 0;
380 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
381 if ((r_shadow_shadowmapping.integer || r_shadow_deferred.integer) && vid.support.ext_framebuffer_object)
383 switch(vid.renderpath)
385 case RENDERPATH_GL20:
386 if(r_shadow_shadowmapfilterquality < 0)
388 if(vid.support.amd_texture_texture4 || vid.support.arb_texture_gather)
389 r_shadow_shadowmappcf = 1;
390 else if(strstr(gl_vendor, "NVIDIA") || strstr(gl_renderer, "Radeon HD"))
392 r_shadow_shadowmapsampler = vid.support.arb_shadow;
393 r_shadow_shadowmappcf = 1;
395 else if(strstr(gl_vendor, "ATI"))
396 r_shadow_shadowmappcf = 1;
398 r_shadow_shadowmapsampler = vid.support.arb_shadow;
402 switch (r_shadow_shadowmapfilterquality)
405 r_shadow_shadowmapsampler = vid.support.arb_shadow;
408 r_shadow_shadowmapsampler = vid.support.arb_shadow;
409 r_shadow_shadowmappcf = 1;
412 r_shadow_shadowmappcf = 1;
415 r_shadow_shadowmappcf = 2;
419 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
420 // Cg has very little choice in depth texture sampling
422 r_shadow_shadowmapsampler = false;
424 case RENDERPATH_CGGL:
425 case RENDERPATH_D3D9:
426 case RENDERPATH_D3D10:
427 case RENDERPATH_D3D11:
428 r_shadow_shadowmapsampler = false;
429 r_shadow_shadowmappcf = 1;
430 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
432 case RENDERPATH_GL13:
434 case RENDERPATH_GL11:
440 qboolean R_Shadow_ShadowMappingEnabled(void)
442 switch (r_shadow_shadowmode)
444 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
451 void R_Shadow_FreeShadowMaps(void)
453 R_Shadow_SetShadowMode();
455 R_Mesh_DestroyFramebufferObject(r_shadow_fbo2d);
459 if (r_shadow_shadowmap2dtexture)
460 R_FreeTexture(r_shadow_shadowmap2dtexture);
461 r_shadow_shadowmap2dtexture = NULL;
463 if (r_shadow_shadowmap2dcolortexture)
464 R_FreeTexture(r_shadow_shadowmap2dcolortexture);
465 r_shadow_shadowmap2dcolortexture = NULL;
467 if (r_shadow_shadowmapvsdcttexture)
468 R_FreeTexture(r_shadow_shadowmapvsdcttexture);
469 r_shadow_shadowmapvsdcttexture = NULL;
472 void r_shadow_start(void)
474 // allocate vertex processing arrays
475 r_shadow_attenuationgradienttexture = NULL;
476 r_shadow_attenuation2dtexture = NULL;
477 r_shadow_attenuation3dtexture = NULL;
478 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
479 r_shadow_shadowmap2dtexture = NULL;
480 r_shadow_shadowmap2dcolortexture = NULL;
481 r_shadow_shadowmapvsdcttexture = NULL;
482 r_shadow_shadowmapmaxsize = 0;
483 r_shadow_shadowmapsize = 0;
484 r_shadow_shadowmaplod = 0;
485 r_shadow_shadowmapfilterquality = -1;
486 r_shadow_shadowmapdepthbits = 0;
487 r_shadow_shadowmapvsdct = false;
488 r_shadow_shadowmapsampler = false;
489 r_shadow_shadowmappcf = 0;
492 R_Shadow_FreeShadowMaps();
494 r_shadow_texturepool = NULL;
495 r_shadow_filters_texturepool = NULL;
496 R_Shadow_ValidateCvars();
497 R_Shadow_MakeTextures();
498 maxshadowtriangles = 0;
499 shadowelements = NULL;
500 maxshadowvertices = 0;
501 shadowvertex3f = NULL;
509 shadowmarklist = NULL;
514 shadowsideslist = NULL;
515 r_shadow_buffer_numleafpvsbytes = 0;
516 r_shadow_buffer_visitingleafpvs = NULL;
517 r_shadow_buffer_leafpvs = NULL;
518 r_shadow_buffer_leaflist = NULL;
519 r_shadow_buffer_numsurfacepvsbytes = 0;
520 r_shadow_buffer_surfacepvs = NULL;
521 r_shadow_buffer_surfacelist = NULL;
522 r_shadow_buffer_surfacesides = NULL;
523 r_shadow_buffer_numshadowtrispvsbytes = 0;
524 r_shadow_buffer_shadowtrispvs = NULL;
525 r_shadow_buffer_numlighttrispvsbytes = 0;
526 r_shadow_buffer_lighttrispvs = NULL;
528 r_shadow_usingdeferredprepass = false;
529 r_shadow_prepass_width = r_shadow_prepass_height = 0;
532 static void R_Shadow_FreeDeferred(void);
533 void r_shadow_shutdown(void)
536 R_Shadow_UncompileWorldLights();
538 R_Shadow_FreeShadowMaps();
540 r_shadow_usingdeferredprepass = false;
541 if (r_shadow_prepass_width)
542 R_Shadow_FreeDeferred();
543 r_shadow_prepass_width = r_shadow_prepass_height = 0;
546 r_shadow_attenuationgradienttexture = NULL;
547 r_shadow_attenuation2dtexture = NULL;
548 r_shadow_attenuation3dtexture = NULL;
549 R_FreeTexturePool(&r_shadow_texturepool);
550 R_FreeTexturePool(&r_shadow_filters_texturepool);
551 maxshadowtriangles = 0;
553 Mem_Free(shadowelements);
554 shadowelements = NULL;
556 Mem_Free(shadowvertex3f);
557 shadowvertex3f = NULL;
560 Mem_Free(vertexupdate);
563 Mem_Free(vertexremap);
569 Mem_Free(shadowmark);
572 Mem_Free(shadowmarklist);
573 shadowmarklist = NULL;
578 Mem_Free(shadowsides);
581 Mem_Free(shadowsideslist);
582 shadowsideslist = NULL;
583 r_shadow_buffer_numleafpvsbytes = 0;
584 if (r_shadow_buffer_visitingleafpvs)
585 Mem_Free(r_shadow_buffer_visitingleafpvs);
586 r_shadow_buffer_visitingleafpvs = NULL;
587 if (r_shadow_buffer_leafpvs)
588 Mem_Free(r_shadow_buffer_leafpvs);
589 r_shadow_buffer_leafpvs = NULL;
590 if (r_shadow_buffer_leaflist)
591 Mem_Free(r_shadow_buffer_leaflist);
592 r_shadow_buffer_leaflist = NULL;
593 r_shadow_buffer_numsurfacepvsbytes = 0;
594 if (r_shadow_buffer_surfacepvs)
595 Mem_Free(r_shadow_buffer_surfacepvs);
596 r_shadow_buffer_surfacepvs = NULL;
597 if (r_shadow_buffer_surfacelist)
598 Mem_Free(r_shadow_buffer_surfacelist);
599 r_shadow_buffer_surfacelist = NULL;
600 if (r_shadow_buffer_surfacesides)
601 Mem_Free(r_shadow_buffer_surfacesides);
602 r_shadow_buffer_surfacesides = NULL;
603 r_shadow_buffer_numshadowtrispvsbytes = 0;
604 if (r_shadow_buffer_shadowtrispvs)
605 Mem_Free(r_shadow_buffer_shadowtrispvs);
606 r_shadow_buffer_numlighttrispvsbytes = 0;
607 if (r_shadow_buffer_lighttrispvs)
608 Mem_Free(r_shadow_buffer_lighttrispvs);
611 void r_shadow_newmap(void)
613 if (r_shadow_lightcorona) R_SkinFrame_MarkUsed(r_shadow_lightcorona);
614 if (r_editlights_sprcursor) R_SkinFrame_MarkUsed(r_editlights_sprcursor);
615 if (r_editlights_sprlight) R_SkinFrame_MarkUsed(r_editlights_sprlight);
616 if (r_editlights_sprnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprnoshadowlight);
617 if (r_editlights_sprcubemaplight) R_SkinFrame_MarkUsed(r_editlights_sprcubemaplight);
618 if (r_editlights_sprcubemapnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprcubemapnoshadowlight);
619 if (r_editlights_sprselection) R_SkinFrame_MarkUsed(r_editlights_sprselection);
620 if (strncmp(cl.worldname, r_shadow_mapname, sizeof(r_shadow_mapname)))
621 R_Shadow_EditLights_Reload_f();
624 void R_Shadow_Init(void)
626 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
627 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
628 Cvar_RegisterVariable(&r_shadow_usenormalmap);
629 Cvar_RegisterVariable(&r_shadow_debuglight);
630 Cvar_RegisterVariable(&r_shadow_deferred);
631 Cvar_RegisterVariable(&r_shadow_deferred_8bitrange);
632 // Cvar_RegisterVariable(&r_shadow_deferred_fp);
633 Cvar_RegisterVariable(&r_shadow_gloss);
634 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
635 Cvar_RegisterVariable(&r_shadow_glossintensity);
636 Cvar_RegisterVariable(&r_shadow_glossexponent);
637 Cvar_RegisterVariable(&r_shadow_gloss2exponent);
638 Cvar_RegisterVariable(&r_shadow_glossexact);
639 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
640 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
641 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
642 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
643 Cvar_RegisterVariable(&r_shadow_projectdistance);
644 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
645 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
646 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
647 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
648 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
649 Cvar_RegisterVariable(&r_shadow_realtime_world);
650 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
651 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
652 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
653 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
654 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
655 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
656 Cvar_RegisterVariable(&r_shadow_scissor);
657 Cvar_RegisterVariable(&r_shadow_shadowmapping);
658 Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
659 Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
660 Cvar_RegisterVariable(&r_shadow_shadowmapping_depthbits);
661 Cvar_RegisterVariable(&r_shadow_shadowmapping_precision);
662 Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
663 Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
664 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
665 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
666 Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
667 Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
668 Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
669 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonfactor);
670 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonoffset);
671 Cvar_RegisterVariable(&r_shadow_polygonfactor);
672 Cvar_RegisterVariable(&r_shadow_polygonoffset);
673 Cvar_RegisterVariable(&r_shadow_texture3d);
674 Cvar_RegisterVariable(&r_coronas);
675 Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
676 Cvar_RegisterVariable(&r_coronas_occlusionquery);
677 Cvar_RegisterVariable(&gl_flashblend);
678 Cvar_RegisterVariable(&gl_ext_separatestencil);
679 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
680 if (gamemode == GAME_TENEBRAE)
682 Cvar_SetValue("r_shadow_gloss", 2);
683 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
685 R_Shadow_EditLights_Init();
686 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
687 maxshadowtriangles = 0;
688 shadowelements = NULL;
689 maxshadowvertices = 0;
690 shadowvertex3f = NULL;
698 shadowmarklist = NULL;
703 shadowsideslist = NULL;
704 r_shadow_buffer_numleafpvsbytes = 0;
705 r_shadow_buffer_visitingleafpvs = NULL;
706 r_shadow_buffer_leafpvs = NULL;
707 r_shadow_buffer_leaflist = NULL;
708 r_shadow_buffer_numsurfacepvsbytes = 0;
709 r_shadow_buffer_surfacepvs = NULL;
710 r_shadow_buffer_surfacelist = NULL;
711 r_shadow_buffer_surfacesides = NULL;
712 r_shadow_buffer_shadowtrispvs = NULL;
713 r_shadow_buffer_lighttrispvs = NULL;
714 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap, NULL, NULL);
717 matrix4x4_t matrix_attenuationxyz =
720 {0.5, 0.0, 0.0, 0.5},
721 {0.0, 0.5, 0.0, 0.5},
722 {0.0, 0.0, 0.5, 0.5},
727 matrix4x4_t matrix_attenuationz =
730 {0.0, 0.0, 0.5, 0.5},
731 {0.0, 0.0, 0.0, 0.5},
732 {0.0, 0.0, 0.0, 0.5},
737 void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles, int vertscale, int triscale)
739 numvertices = ((numvertices + 255) & ~255) * vertscale;
740 numtriangles = ((numtriangles + 255) & ~255) * triscale;
741 // make sure shadowelements is big enough for this volume
742 if (maxshadowtriangles < numtriangles)
744 maxshadowtriangles = numtriangles;
746 Mem_Free(shadowelements);
747 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[3]));
749 // make sure shadowvertex3f is big enough for this volume
750 if (maxshadowvertices < numvertices)
752 maxshadowvertices = numvertices;
754 Mem_Free(shadowvertex3f);
755 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[3]));
759 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
761 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
762 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
763 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
764 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
765 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
767 if (r_shadow_buffer_visitingleafpvs)
768 Mem_Free(r_shadow_buffer_visitingleafpvs);
769 if (r_shadow_buffer_leafpvs)
770 Mem_Free(r_shadow_buffer_leafpvs);
771 if (r_shadow_buffer_leaflist)
772 Mem_Free(r_shadow_buffer_leaflist);
773 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
774 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
775 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
776 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
778 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
780 if (r_shadow_buffer_surfacepvs)
781 Mem_Free(r_shadow_buffer_surfacepvs);
782 if (r_shadow_buffer_surfacelist)
783 Mem_Free(r_shadow_buffer_surfacelist);
784 if (r_shadow_buffer_surfacesides)
785 Mem_Free(r_shadow_buffer_surfacesides);
786 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
787 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
788 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
789 r_shadow_buffer_surfacesides = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
791 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
793 if (r_shadow_buffer_shadowtrispvs)
794 Mem_Free(r_shadow_buffer_shadowtrispvs);
795 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
796 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
798 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
800 if (r_shadow_buffer_lighttrispvs)
801 Mem_Free(r_shadow_buffer_lighttrispvs);
802 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
803 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
807 void R_Shadow_PrepareShadowMark(int numtris)
809 // make sure shadowmark is big enough for this volume
810 if (maxshadowmark < numtris)
812 maxshadowmark = numtris;
814 Mem_Free(shadowmark);
816 Mem_Free(shadowmarklist);
817 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
818 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
822 // if shadowmarkcount wrapped we clear the array and adjust accordingly
823 if (shadowmarkcount == 0)
826 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
831 void R_Shadow_PrepareShadowSides(int numtris)
833 if (maxshadowsides < numtris)
835 maxshadowsides = numtris;
837 Mem_Free(shadowsides);
839 Mem_Free(shadowsideslist);
840 shadowsides = (unsigned char *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsides));
841 shadowsideslist = (int *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsideslist));
846 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)
849 int outtriangles = 0, outvertices = 0;
852 float ratio, direction[3], projectvector[3];
854 if (projectdirection)
855 VectorScale(projectdirection, projectdistance, projectvector);
857 VectorClear(projectvector);
859 // create the vertices
860 if (projectdirection)
862 for (i = 0;i < numshadowmarktris;i++)
864 element = inelement3i + shadowmarktris[i] * 3;
865 for (j = 0;j < 3;j++)
867 if (vertexupdate[element[j]] != vertexupdatenum)
869 vertexupdate[element[j]] = vertexupdatenum;
870 vertexremap[element[j]] = outvertices;
871 vertex = invertex3f + element[j] * 3;
872 // project one copy of the vertex according to projectvector
873 VectorCopy(vertex, outvertex3f);
874 VectorAdd(vertex, projectvector, (outvertex3f + 3));
883 for (i = 0;i < numshadowmarktris;i++)
885 element = inelement3i + shadowmarktris[i] * 3;
886 for (j = 0;j < 3;j++)
888 if (vertexupdate[element[j]] != vertexupdatenum)
890 vertexupdate[element[j]] = vertexupdatenum;
891 vertexremap[element[j]] = outvertices;
892 vertex = invertex3f + element[j] * 3;
893 // project one copy of the vertex to the sphere radius of the light
894 // (FIXME: would projecting it to the light box be better?)
895 VectorSubtract(vertex, projectorigin, direction);
896 ratio = projectdistance / VectorLength(direction);
897 VectorCopy(vertex, outvertex3f);
898 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
906 if (r_shadow_frontsidecasting.integer)
908 for (i = 0;i < numshadowmarktris;i++)
910 int remappedelement[3];
912 const int *neighbortriangle;
914 markindex = shadowmarktris[i] * 3;
915 element = inelement3i + markindex;
916 neighbortriangle = inneighbor3i + markindex;
917 // output the front and back triangles
918 outelement3i[0] = vertexremap[element[0]];
919 outelement3i[1] = vertexremap[element[1]];
920 outelement3i[2] = vertexremap[element[2]];
921 outelement3i[3] = vertexremap[element[2]] + 1;
922 outelement3i[4] = vertexremap[element[1]] + 1;
923 outelement3i[5] = vertexremap[element[0]] + 1;
927 // output the sides (facing outward from this triangle)
928 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
930 remappedelement[0] = vertexremap[element[0]];
931 remappedelement[1] = vertexremap[element[1]];
932 outelement3i[0] = remappedelement[1];
933 outelement3i[1] = remappedelement[0];
934 outelement3i[2] = remappedelement[0] + 1;
935 outelement3i[3] = remappedelement[1];
936 outelement3i[4] = remappedelement[0] + 1;
937 outelement3i[5] = remappedelement[1] + 1;
942 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
944 remappedelement[1] = vertexremap[element[1]];
945 remappedelement[2] = vertexremap[element[2]];
946 outelement3i[0] = remappedelement[2];
947 outelement3i[1] = remappedelement[1];
948 outelement3i[2] = remappedelement[1] + 1;
949 outelement3i[3] = remappedelement[2];
950 outelement3i[4] = remappedelement[1] + 1;
951 outelement3i[5] = remappedelement[2] + 1;
956 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
958 remappedelement[0] = vertexremap[element[0]];
959 remappedelement[2] = vertexremap[element[2]];
960 outelement3i[0] = remappedelement[0];
961 outelement3i[1] = remappedelement[2];
962 outelement3i[2] = remappedelement[2] + 1;
963 outelement3i[3] = remappedelement[0];
964 outelement3i[4] = remappedelement[2] + 1;
965 outelement3i[5] = remappedelement[0] + 1;
974 for (i = 0;i < numshadowmarktris;i++)
976 int remappedelement[3];
978 const int *neighbortriangle;
980 markindex = shadowmarktris[i] * 3;
981 element = inelement3i + markindex;
982 neighbortriangle = inneighbor3i + markindex;
983 // output the front and back triangles
984 outelement3i[0] = vertexremap[element[2]];
985 outelement3i[1] = vertexremap[element[1]];
986 outelement3i[2] = vertexremap[element[0]];
987 outelement3i[3] = vertexremap[element[0]] + 1;
988 outelement3i[4] = vertexremap[element[1]] + 1;
989 outelement3i[5] = vertexremap[element[2]] + 1;
993 // output the sides (facing outward from this triangle)
994 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
996 remappedelement[0] = vertexremap[element[0]];
997 remappedelement[1] = vertexremap[element[1]];
998 outelement3i[0] = remappedelement[0];
999 outelement3i[1] = remappedelement[1];
1000 outelement3i[2] = remappedelement[1] + 1;
1001 outelement3i[3] = remappedelement[0];
1002 outelement3i[4] = remappedelement[1] + 1;
1003 outelement3i[5] = remappedelement[0] + 1;
1008 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1010 remappedelement[1] = vertexremap[element[1]];
1011 remappedelement[2] = vertexremap[element[2]];
1012 outelement3i[0] = remappedelement[1];
1013 outelement3i[1] = remappedelement[2];
1014 outelement3i[2] = remappedelement[2] + 1;
1015 outelement3i[3] = remappedelement[1];
1016 outelement3i[4] = remappedelement[2] + 1;
1017 outelement3i[5] = remappedelement[1] + 1;
1022 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1024 remappedelement[0] = vertexremap[element[0]];
1025 remappedelement[2] = vertexremap[element[2]];
1026 outelement3i[0] = remappedelement[2];
1027 outelement3i[1] = remappedelement[0];
1028 outelement3i[2] = remappedelement[0] + 1;
1029 outelement3i[3] = remappedelement[2];
1030 outelement3i[4] = remappedelement[0] + 1;
1031 outelement3i[5] = remappedelement[2] + 1;
1039 *outnumvertices = outvertices;
1040 return outtriangles;
1043 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)
1046 int outtriangles = 0, outvertices = 0;
1048 const float *vertex;
1049 float ratio, direction[3], projectvector[3];
1052 if (projectdirection)
1053 VectorScale(projectdirection, projectdistance, projectvector);
1055 VectorClear(projectvector);
1057 for (i = 0;i < numshadowmarktris;i++)
1059 int remappedelement[3];
1061 const int *neighbortriangle;
1063 markindex = shadowmarktris[i] * 3;
1064 neighbortriangle = inneighbor3i + markindex;
1065 side[0] = shadowmark[neighbortriangle[0]] == shadowmarkcount;
1066 side[1] = shadowmark[neighbortriangle[1]] == shadowmarkcount;
1067 side[2] = shadowmark[neighbortriangle[2]] == shadowmarkcount;
1068 if (side[0] + side[1] + side[2] == 0)
1072 element = inelement3i + markindex;
1074 // create the vertices
1075 for (j = 0;j < 3;j++)
1077 if (side[j] + side[j+1] == 0)
1080 if (vertexupdate[k] != vertexupdatenum)
1082 vertexupdate[k] = vertexupdatenum;
1083 vertexremap[k] = outvertices;
1084 vertex = invertex3f + k * 3;
1085 VectorCopy(vertex, outvertex3f);
1086 if (projectdirection)
1088 // project one copy of the vertex according to projectvector
1089 VectorAdd(vertex, projectvector, (outvertex3f + 3));
1093 // project one copy of the vertex to the sphere radius of the light
1094 // (FIXME: would projecting it to the light box be better?)
1095 VectorSubtract(vertex, projectorigin, direction);
1096 ratio = projectdistance / VectorLength(direction);
1097 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1104 // output the sides (facing outward from this triangle)
1107 remappedelement[0] = vertexremap[element[0]];
1108 remappedelement[1] = vertexremap[element[1]];
1109 outelement3i[0] = remappedelement[1];
1110 outelement3i[1] = remappedelement[0];
1111 outelement3i[2] = remappedelement[0] + 1;
1112 outelement3i[3] = remappedelement[1];
1113 outelement3i[4] = remappedelement[0] + 1;
1114 outelement3i[5] = remappedelement[1] + 1;
1121 remappedelement[1] = vertexremap[element[1]];
1122 remappedelement[2] = vertexremap[element[2]];
1123 outelement3i[0] = remappedelement[2];
1124 outelement3i[1] = remappedelement[1];
1125 outelement3i[2] = remappedelement[1] + 1;
1126 outelement3i[3] = remappedelement[2];
1127 outelement3i[4] = remappedelement[1] + 1;
1128 outelement3i[5] = remappedelement[2] + 1;
1135 remappedelement[0] = vertexremap[element[0]];
1136 remappedelement[2] = vertexremap[element[2]];
1137 outelement3i[0] = remappedelement[0];
1138 outelement3i[1] = remappedelement[2];
1139 outelement3i[2] = remappedelement[2] + 1;
1140 outelement3i[3] = remappedelement[0];
1141 outelement3i[4] = remappedelement[2] + 1;
1142 outelement3i[5] = remappedelement[0] + 1;
1149 *outnumvertices = outvertices;
1150 return outtriangles;
1153 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)
1159 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1161 tend = firsttriangle + numtris;
1162 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1164 // surface box entirely inside light box, no box cull
1165 if (projectdirection)
1167 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1169 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
1170 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1171 shadowmarklist[numshadowmark++] = t;
1176 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1177 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
1178 shadowmarklist[numshadowmark++] = t;
1183 // surface box not entirely inside light box, cull each triangle
1184 if (projectdirection)
1186 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1188 v[0] = invertex3f + e[0] * 3;
1189 v[1] = invertex3f + e[1] * 3;
1190 v[2] = invertex3f + e[2] * 3;
1191 TriangleNormal(v[0], v[1], v[2], normal);
1192 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1193 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1194 shadowmarklist[numshadowmark++] = t;
1199 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1201 v[0] = invertex3f + e[0] * 3;
1202 v[1] = invertex3f + e[1] * 3;
1203 v[2] = invertex3f + e[2] * 3;
1204 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1205 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1206 shadowmarklist[numshadowmark++] = t;
1212 qboolean R_Shadow_UseZPass(vec3_t mins, vec3_t maxs)
1217 if (r_shadow_compilingrtlight || !r_shadow_frontsidecasting.integer || !r_shadow_usezpassifpossible.integer)
1219 // check if the shadow volume intersects the near plane
1221 // a ray between the eye and light origin may intersect the caster,
1222 // indicating that the shadow may touch the eye location, however we must
1223 // test the near plane (a polygon), not merely the eye location, so it is
1224 // easiest to enlarge the caster bounding shape slightly for this.
1230 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)
1232 int i, tris, outverts;
1233 if (projectdistance < 0.1)
1235 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
1238 if (!numverts || !nummarktris)
1240 // make sure shadowelements is big enough for this volume
1241 if (maxshadowtriangles < nummarktris*8 || maxshadowvertices < numverts*2)
1242 R_Shadow_ResizeShadowArrays(numverts, nummarktris, 2, 8);
1244 if (maxvertexupdate < numverts)
1246 maxvertexupdate = numverts;
1248 Mem_Free(vertexupdate);
1250 Mem_Free(vertexremap);
1251 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1252 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1253 vertexupdatenum = 0;
1256 if (vertexupdatenum == 0)
1258 vertexupdatenum = 1;
1259 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
1260 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
1263 for (i = 0;i < nummarktris;i++)
1264 shadowmark[marktris[i]] = shadowmarkcount;
1266 if (r_shadow_compilingrtlight)
1268 // if we're compiling an rtlight, capture the mesh
1269 //tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1270 //Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zpass, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1271 tris = R_Shadow_ConstructShadowVolume_ZFail(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_zfail, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1274 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
1276 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1277 R_Mesh_PrepareVertices_Position_Arrays(outverts, shadowvertex3f);
1278 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1282 // decide which type of shadow to generate and set stencil mode
1283 R_Shadow_RenderMode_StencilShadowVolumes(R_Shadow_UseZPass(trismins, trismaxs));
1284 // generate the sides or a solid volume, depending on type
1285 if (r_shadow_rendermode >= R_SHADOW_RENDERMODE_ZPASS_STENCIL && r_shadow_rendermode <= R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE)
1286 tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1288 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1289 r_refdef.stats.lights_dynamicshadowtriangles += tris;
1290 r_refdef.stats.lights_shadowtriangles += tris;
1291 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
1293 // increment stencil if frontface is infront of depthbuffer
1294 GL_CullFace(r_refdef.view.cullface_front);
1295 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
1296 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1297 // decrement stencil if backface is infront of depthbuffer
1298 GL_CullFace(r_refdef.view.cullface_back);
1299 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
1301 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
1303 // decrement stencil if backface is behind depthbuffer
1304 GL_CullFace(r_refdef.view.cullface_front);
1305 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
1306 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1307 // increment stencil if frontface is behind depthbuffer
1308 GL_CullFace(r_refdef.view.cullface_back);
1309 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
1311 R_Mesh_PrepareVertices_Position_Arrays(outverts, shadowvertex3f);
1312 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1316 int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias)
1318 // p1, p2, p3 are in the cubemap's local coordinate system
1319 // bias = border/(size - border)
1322 float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1323 dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2),
1324 dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3);
1325 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1327 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1328 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1329 | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1330 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1332 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1333 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1334 | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1336 dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1337 dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2),
1338 dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3);
1339 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1341 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1342 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1343 | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1344 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1346 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1347 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1348 | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1350 dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1351 dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2),
1352 dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3);
1353 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1355 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1356 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1357 | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1358 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1360 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1361 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1362 | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1367 int R_Shadow_CalcBBoxSideMask(const vec3_t mins, const vec3_t maxs, const matrix4x4_t *worldtolight, const matrix4x4_t *radiustolight, float bias)
1369 vec3_t center, radius, lightcenter, lightradius, pmin, pmax;
1370 float dp1, dn1, ap1, an1, dp2, dn2, ap2, an2;
1373 VectorSubtract(maxs, mins, radius);
1374 VectorScale(radius, 0.5f, radius);
1375 VectorAdd(mins, radius, center);
1376 Matrix4x4_Transform(worldtolight, center, lightcenter);
1377 Matrix4x4_Transform3x3(radiustolight, radius, lightradius);
1378 VectorSubtract(lightcenter, lightradius, pmin);
1379 VectorAdd(lightcenter, lightradius, pmax);
1381 dp1 = pmax[0] + pmax[1], dn1 = pmax[0] - pmin[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1382 dp2 = pmin[0] + pmin[1], dn2 = pmin[0] - pmax[1], ap2 = fabs(dp2), an2 = fabs(dn2);
1383 if(ap1 > bias*an1 && ap2 > bias*an2)
1385 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1386 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1387 if(an1 > bias*ap1 && an2 > bias*ap2)
1389 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1390 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1392 dp1 = pmax[1] + pmax[2], dn1 = pmax[1] - pmin[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1393 dp2 = pmin[1] + pmin[2], dn2 = pmin[1] - pmax[2], ap2 = fabs(dp2), an2 = fabs(dn2);
1394 if(ap1 > bias*an1 && ap2 > bias*an2)
1396 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1397 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1398 if(an1 > bias*ap1 && an2 > bias*ap2)
1400 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1401 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1403 dp1 = pmax[2] + pmax[0], dn1 = pmax[2] - pmin[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1404 dp2 = pmin[2] + pmin[0], dn2 = pmin[2] - pmax[0], ap2 = fabs(dp2), an2 = fabs(dn2);
1405 if(ap1 > bias*an1 && ap2 > bias*an2)
1407 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1408 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1409 if(an1 > bias*ap1 && an2 > bias*ap2)
1411 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1412 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1417 #define R_Shadow_CalcEntitySideMask(ent, worldtolight, radiustolight, bias) R_Shadow_CalcBBoxSideMask((ent)->mins, (ent)->maxs, worldtolight, radiustolight, bias)
1419 int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
1421 // p is in the cubemap's local coordinate system
1422 // bias = border/(size - border)
1423 float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn);
1424 float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn);
1425 float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn);
1427 if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
1428 if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
1429 if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
1430 if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
1431 if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
1432 if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
1436 int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
1440 int sides = 0x3F, masks[6] = { 3<<4, 3<<4, 3<<0, 3<<0, 3<<2, 3<<2 };
1441 float scale = (size - 2*border)/size, len;
1442 float bias = border / (float)(size - border), dp, dn, ap, an;
1443 // check if cone enclosing side would cross frustum plane
1444 scale = 2 / (scale*scale + 2);
1445 for (i = 0;i < 5;i++)
1447 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) > -0.03125)
1449 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[i].normal, n);
1450 len = scale*VectorLength2(n);
1451 if(n[0]*n[0] > len) sides &= n[0] < 0 ? ~(1<<0) : ~(2 << 0);
1452 if(n[1]*n[1] > len) sides &= n[1] < 0 ? ~(1<<2) : ~(2 << 2);
1453 if(n[2]*n[2] > len) sides &= n[2] < 0 ? ~(1<<4) : ~(2 << 4);
1455 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[4]) >= r_refdef.farclip - r_refdef.nearclip + 0.03125)
1457 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[4].normal, n);
1458 len = scale*VectorLength(n);
1459 if(n[0]*n[0] > len) sides &= n[0] >= 0 ? ~(1<<0) : ~(2 << 0);
1460 if(n[1]*n[1] > len) sides &= n[1] >= 0 ? ~(1<<2) : ~(2 << 2);
1461 if(n[2]*n[2] > len) sides &= n[2] >= 0 ? ~(1<<4) : ~(2 << 4);
1463 // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results
1464 // check if frustum corners/origin cross plane sides
1466 // infinite version, assumes frustum corners merely give direction and extend to infinite distance
1467 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.origin, p);
1468 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1469 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1470 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1471 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1472 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1473 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1474 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1475 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1476 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1477 for (i = 0;i < 4;i++)
1479 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.frustumcorner[i], n);
1480 VectorSubtract(n, p, n);
1481 dp = n[0] + n[1], dn = n[0] - n[1], ap = fabs(dp), an = fabs(dn);
1482 if(ap > 0) masks[0] |= dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2);
1483 if(an > 0) masks[1] |= dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2);
1484 dp = n[1] + n[2], dn = n[1] - n[2], ap = fabs(dp), an = fabs(dn);
1485 if(ap > 0) masks[2] |= dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4);
1486 if(an > 0) masks[3] |= dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4);
1487 dp = n[2] + n[0], dn = n[2] - n[0], ap = fabs(dp), an = fabs(dn);
1488 if(ap > 0) masks[4] |= dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0);
1489 if(an > 0) masks[5] |= dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0);
1492 // finite version, assumes corners are a finite distance from origin dependent on far plane
1493 for (i = 0;i < 5;i++)
1495 Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p);
1496 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1497 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1498 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1499 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1500 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1501 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1502 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1503 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1504 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1507 return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5];
1510 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)
1518 int mask, surfacemask = 0;
1519 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1521 bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
1522 tend = firsttriangle + numtris;
1523 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1525 // surface box entirely inside light box, no box cull
1526 if (projectdirection)
1528 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1530 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1531 TriangleNormal(v[0], v[1], v[2], normal);
1532 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1534 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1535 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1536 surfacemask |= mask;
1539 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;
1540 shadowsides[numshadowsides] = mask;
1541 shadowsideslist[numshadowsides++] = t;
1548 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1550 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1551 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]))
1553 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1554 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1555 surfacemask |= mask;
1558 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;
1559 shadowsides[numshadowsides] = mask;
1560 shadowsideslist[numshadowsides++] = t;
1568 // surface box not entirely inside light box, cull each triangle
1569 if (projectdirection)
1571 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1573 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1574 TriangleNormal(v[0], v[1], v[2], normal);
1575 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1576 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1578 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1579 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1580 surfacemask |= mask;
1583 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;
1584 shadowsides[numshadowsides] = mask;
1585 shadowsideslist[numshadowsides++] = t;
1592 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1594 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1595 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1596 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1598 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1599 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1600 surfacemask |= mask;
1603 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;
1604 shadowsides[numshadowsides] = mask;
1605 shadowsideslist[numshadowsides++] = t;
1614 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)
1616 int i, j, outtriangles = 0;
1617 int *outelement3i[6];
1618 if (!numverts || !numsidetris || !r_shadow_compilingrtlight)
1620 outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5];
1621 // make sure shadowelements is big enough for this mesh
1622 if (maxshadowtriangles < outtriangles)
1623 R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1);
1625 // compute the offset and size of the separate index lists for each cubemap side
1627 for (i = 0;i < 6;i++)
1629 outelement3i[i] = shadowelements + outtriangles * 3;
1630 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles;
1631 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i];
1632 outtriangles += sidetotals[i];
1635 // gather up the (sparse) triangles into separate index lists for each cubemap side
1636 for (i = 0;i < numsidetris;i++)
1638 const int *element = elements + sidetris[i] * 3;
1639 for (j = 0;j < 6;j++)
1641 if (sides[i] & (1 << j))
1643 outelement3i[j][0] = element[0];
1644 outelement3i[j][1] = element[1];
1645 outelement3i[j][2] = element[2];
1646 outelement3i[j] += 3;
1651 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, outtriangles, shadowelements);
1654 static void R_Shadow_MakeTextures_MakeCorona(void)
1658 unsigned char pixels[32][32][4];
1659 for (y = 0;y < 32;y++)
1661 dy = (y - 15.5f) * (1.0f / 16.0f);
1662 for (x = 0;x < 32;x++)
1664 dx = (x - 15.5f) * (1.0f / 16.0f);
1665 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1666 a = bound(0, a, 255);
1667 pixels[y][x][0] = a;
1668 pixels[y][x][1] = a;
1669 pixels[y][x][2] = a;
1670 pixels[y][x][3] = 255;
1673 r_shadow_lightcorona = R_SkinFrame_LoadInternalBGRA("lightcorona", TEXF_FORCELINEAR, &pixels[0][0][0], 32, 32);
1676 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1678 float dist = sqrt(x*x+y*y+z*z);
1679 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1680 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1681 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1684 static void R_Shadow_MakeTextures(void)
1687 float intensity, dist;
1689 R_Shadow_FreeShadowMaps();
1690 R_FreeTexturePool(&r_shadow_texturepool);
1691 r_shadow_texturepool = R_AllocTexturePool();
1692 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1693 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1694 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1695 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1696 for (x = 0;x <= ATTENTABLESIZE;x++)
1698 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1699 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1700 r_shadow_attentable[x] = bound(0, intensity, 1);
1702 // 1D gradient texture
1703 for (x = 0;x < ATTEN1DSIZE;x++)
1704 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1705 r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1706 // 2D circle texture
1707 for (y = 0;y < ATTEN2DSIZE;y++)
1708 for (x = 0;x < ATTEN2DSIZE;x++)
1709 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);
1710 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1711 // 3D sphere texture
1712 if (r_shadow_texture3d.integer && vid.support.ext_texture_3d)
1714 for (z = 0;z < ATTEN3DSIZE;z++)
1715 for (y = 0;y < ATTEN3DSIZE;y++)
1716 for (x = 0;x < ATTEN3DSIZE;x++)
1717 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));
1718 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);
1721 r_shadow_attenuation3dtexture = NULL;
1724 R_Shadow_MakeTextures_MakeCorona();
1726 // Editor light sprites
1727 r_editlights_sprcursor = R_SkinFrame_LoadInternal8bit("gfx/editlights/cursor", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1744 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1745 r_editlights_sprlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/light", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1762 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1763 r_editlights_sprnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/noshadow", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1780 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1781 r_editlights_sprcubemaplight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemaplight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1798 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1799 r_editlights_sprcubemapnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemapnoshadowlight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1816 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1817 r_editlights_sprselection = R_SkinFrame_LoadInternal8bit("gfx/editlights/selection", TEXF_ALPHA | TEXF_CLAMP, (unsigned char *)
1834 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1837 void R_Shadow_ValidateCvars(void)
1839 if (r_shadow_texture3d.integer && !vid.support.ext_texture_3d)
1840 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1841 if (gl_ext_separatestencil.integer && !vid.support.ati_separate_stencil)
1842 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
1843 if (gl_ext_stenciltwoside.integer && !vid.support.ext_stencil_two_side)
1844 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1847 //static const r_vertexposition_t resetvertexposition[3] = {{0, 0, 0}};
1849 void R_Shadow_RenderMode_Begin(void)
1855 R_Shadow_ValidateCvars();
1857 if (!r_shadow_attenuation2dtexture
1858 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1859 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1860 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1861 R_Shadow_MakeTextures();
1864 R_Mesh_ResetTextureState();
1865 // R_Mesh_PrepareVertices_Position(0, resetvertexposition, NULL);
1866 GL_BlendFunc(GL_ONE, GL_ZERO);
1867 GL_DepthRange(0, 1);
1868 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1870 GL_DepthMask(false);
1871 GL_Color(0, 0, 0, 1);
1872 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1874 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1876 if (gl_ext_separatestencil.integer && vid.support.ati_separate_stencil)
1878 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
1879 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
1881 else if (gl_ext_stenciltwoside.integer && vid.support.ext_stencil_two_side)
1883 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
1884 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
1888 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
1889 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
1892 switch(vid.renderpath)
1894 case RENDERPATH_GL20:
1895 case RENDERPATH_CGGL:
1896 case RENDERPATH_D3D9:
1897 case RENDERPATH_D3D10:
1898 case RENDERPATH_D3D11:
1899 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1901 case RENDERPATH_GL13:
1902 case RENDERPATH_GL11:
1903 if (r_textureunits.integer >= 2 && vid.texunits >= 2 && r_shadow_texture3d.integer && r_shadow_attenuation3dtexture)
1904 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN;
1905 else if (r_textureunits.integer >= 3 && vid.texunits >= 3)
1906 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN;
1907 else if (r_textureunits.integer >= 2 && vid.texunits >= 2)
1908 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN;
1910 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1916 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
1917 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
1918 r_shadow_drawbuffer = drawbuffer;
1919 r_shadow_readbuffer = readbuffer;
1921 r_shadow_cullface_front = r_refdef.view.cullface_front;
1922 r_shadow_cullface_back = r_refdef.view.cullface_back;
1925 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
1927 rsurface.rtlight = rtlight;
1930 void R_Shadow_RenderMode_Reset(void)
1932 R_Mesh_ResetRenderTargets();
1933 R_SetViewport(&r_refdef.view.viewport);
1934 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
1935 R_Mesh_ResetTextureState();
1936 // R_Mesh_PrepareVertices_Position(0, resetvertexposition, NULL);
1937 GL_DepthRange(0, 1);
1939 GL_DepthMask(false);
1940 GL_DepthFunc(GL_LEQUAL);
1941 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1942 r_refdef.view.cullface_front = r_shadow_cullface_front;
1943 r_refdef.view.cullface_back = r_shadow_cullface_back;
1944 GL_CullFace(r_refdef.view.cullface_back);
1945 GL_Color(1, 1, 1, 1);
1946 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
1947 GL_BlendFunc(GL_ONE, GL_ZERO);
1948 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
1949 r_shadow_usingshadowmap2d = false;
1950 r_shadow_usingshadowmaportho = false;
1951 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
1954 void R_Shadow_ClearStencil(void)
1956 GL_Clear(GL_STENCIL_BUFFER_BIT, NULL, 1.0f, 128);
1957 r_refdef.stats.lights_clears++;
1960 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
1962 r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
1963 if (r_shadow_rendermode == mode)
1965 R_Shadow_RenderMode_Reset();
1966 GL_DepthFunc(GL_LESS);
1967 GL_ColorMask(0, 0, 0, 0);
1968 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1969 GL_CullFace(GL_NONE);
1970 R_SetupShader_DepthOrShadow();
1971 r_shadow_rendermode = mode;
1976 case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
1977 case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
1978 R_SetStencilSeparate(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, GL_ALWAYS, 128, 255);
1980 case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
1981 case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
1982 R_SetStencilSeparate(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, GL_ALWAYS, 128, 255);
1987 static void R_Shadow_MakeVSDCT(void)
1989 // maps to a 2x3 texture rectangle with normalized coordinates
1994 // stores abs(dir.xy), offset.xy/2.5
1995 unsigned char data[4*6] =
1997 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
1998 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
1999 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
2000 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
2001 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
2002 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
2004 r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
2007 static void R_Shadow_MakeShadowMap(int side, int size)
2009 switch (r_shadow_shadowmode)
2011 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2012 if (r_shadow_shadowmap2dtexture) return;
2013 r_shadow_shadowmap2dtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "shadowmap", size*2, size*(vid.support.arb_texture_non_power_of_two ? 3 : 4), r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
2014 r_shadow_shadowmap2dcolortexture = NULL;
2015 switch(vid.renderpath)
2018 case RENDERPATH_D3D9:
2019 r_shadow_shadowmap2dcolortexture = R_LoadTexture2D(r_shadow_texturepool, "shadowmaprendertarget", size*2, size*(vid.support.arb_texture_non_power_of_two ? 3 : 4), NULL, TEXTYPE_BGRA, TEXF_RENDERTARGET | TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
2020 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
2024 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2dtexture, NULL, NULL, NULL, NULL);
2032 // render depth into the fbo, do not render color at all
2033 // validate the fbo now
2037 qglDrawBuffer(GL_NONE);CHECKGLERROR
2038 qglReadBuffer(GL_NONE);CHECKGLERROR
2039 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2040 if (status != GL_FRAMEBUFFER_COMPLETE_EXT && (r_shadow_shadowmapping.integer || r_shadow_deferred.integer))
2042 Con_Printf("R_Shadow_MakeShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2043 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2044 Cvar_SetValueQuick(&r_shadow_deferred, 0);
2049 void R_Shadow_RenderMode_ShadowMap(int side, int clear, int size)
2051 float nearclip, farclip, bias;
2052 r_viewport_t viewport;
2055 float clearcolor[4];
2056 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
2058 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
2059 r_shadow_shadowmap_parameters[1] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
2060 r_shadow_shadowmap_parameters[3] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
2061 r_shadow_shadowmapside = side;
2062 r_shadow_shadowmapsize = size;
2064 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2065 r_shadow_shadowmap_parameters[2] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2066 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
2067 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D) goto init_done;
2069 // complex unrolled cube approach (more flexible)
2070 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2071 R_Shadow_MakeVSDCT();
2072 if (!r_shadow_shadowmap2dtexture)
2073 R_Shadow_MakeShadowMap(side, r_shadow_shadowmapmaxsize);
2074 if (r_shadow_shadowmap2dtexture) fbo = r_shadow_fbo2d;
2075 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
2076 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
2077 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
2079 R_Mesh_ResetTextureState();
2080 R_Mesh_ResetRenderTargets();
2081 R_Shadow_RenderMode_Reset();
2084 R_Mesh_SetRenderTargets(fbo, r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
2085 R_SetupShader_DepthOrShadow();
2088 R_SetupShader_ShowDepth();
2089 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
2094 R_SetViewport(&viewport);
2095 flipped = (side & 1) ^ (side >> 2);
2096 r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
2097 r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
2098 switch(vid.renderpath)
2100 case RENDERPATH_GL11:
2101 case RENDERPATH_GL13:
2102 case RENDERPATH_GL20:
2103 case RENDERPATH_CGGL:
2104 GL_CullFace(r_refdef.view.cullface_back);
2105 // OpenGL lets us scissor larger than the viewport, so go ahead and clear all views at once
2106 if ((clear & ((2 << side) - 1)) == (1 << side)) // only clear if the side is the first in the mask
2108 // get tightest scissor rectangle that encloses all viewports in the clear mask
2109 int x1 = clear & 0x15 ? 0 : size;
2110 int x2 = clear & 0x2A ? 2 * size : size;
2111 int y1 = clear & 0x03 ? 0 : (clear & 0xC ? size : 2 * size);
2112 int y2 = clear & 0x30 ? 3 * size : (clear & 0xC ? 2 * size : size);
2113 GL_Scissor(x1, y1, x2 - x1, y2 - y1);
2114 GL_Clear(GL_DEPTH_BUFFER_BIT, NULL, 1.0f, 0);
2116 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2118 case RENDERPATH_D3D9:
2119 Vector4Set(clearcolor, 1,1,1,1);
2120 // completely different meaning than in OpenGL path
2121 r_shadow_shadowmap_parameters[1] = 0;
2122 r_shadow_shadowmap_parameters[3] = -bias;
2123 // we invert the cull mode because we flip the projection matrix
2124 // NOTE: this actually does nothing because the DrawShadowMap code sets it to doublesided...
2125 GL_CullFace(r_refdef.view.cullface_front);
2126 // D3D considers it an error to use a scissor larger than the viewport... clear just this view
2127 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2128 if (r_shadow_shadowmapsampler)
2130 GL_ColorMask(0,0,0,0);
2132 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
2136 GL_ColorMask(1,1,1,1);
2138 GL_Clear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
2141 case RENDERPATH_D3D10:
2142 case RENDERPATH_D3D11:
2143 // D3D considers it an error to use a scissor larger than the viewport... clear just this view
2144 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2145 GL_ColorMask(0,0,0,0);
2147 GL_Clear(GL_DEPTH_BUFFER_BIT, NULL, 1.0f, 0);
2152 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
2154 R_Mesh_ResetTextureState();
2155 R_Mesh_ResetRenderTargets();
2158 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2159 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2160 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2161 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2163 R_Shadow_RenderMode_Reset();
2164 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2166 GL_DepthFunc(GL_EQUAL);
2167 // do global setup needed for the chosen lighting mode
2168 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2169 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2170 r_shadow_usingshadowmap2d = shadowmapping;
2171 r_shadow_rendermode = r_shadow_lightingrendermode;
2172 // only draw light where this geometry was already rendered AND the
2173 // stencil is 128 (values other than this mean shadow)
2175 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2177 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
2180 static const unsigned short bboxelements[36] =
2190 static const float bboxpoints[8][3] =
2202 void R_Shadow_RenderMode_DrawDeferredLight(qboolean stenciltest, qboolean shadowmapping)
2205 float vertex3f[8*3];
2206 const matrix4x4_t *matrix = &rsurface.rtlight->matrix_lighttoworld;
2207 // do global setup needed for the chosen lighting mode
2208 R_Shadow_RenderMode_Reset();
2209 r_shadow_rendermode = r_shadow_lightingrendermode;
2210 R_EntityMatrix(&identitymatrix);
2211 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2212 // only draw light where this geometry was already rendered AND the
2213 // stencil is 128 (values other than this mean shadow)
2214 R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2215 R_Mesh_SetRenderTargets(r_shadow_prepasslightingfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
2217 r_shadow_usingshadowmap2d = shadowmapping;
2219 // render the lighting
2220 R_SetupShader_DeferredLight(rsurface.rtlight);
2221 for (i = 0;i < 8;i++)
2222 Matrix4x4_Transform(matrix, bboxpoints[i], vertex3f + i*3);
2223 GL_ColorMask(1,1,1,1);
2224 GL_DepthMask(false);
2225 GL_DepthRange(0, 1);
2226 GL_PolygonOffset(0, 0);
2228 GL_DepthFunc(GL_GREATER);
2229 GL_CullFace(r_refdef.view.cullface_back);
2230 R_Mesh_PrepareVertices_Position_Arrays(8, vertex3f);
2231 R_Mesh_Draw(0, 8, 0, 12, NULL, NULL, 0, bboxelements, NULL, 0);
2234 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
2236 R_Shadow_RenderMode_Reset();
2237 GL_BlendFunc(GL_ONE, GL_ONE);
2238 GL_DepthRange(0, 1);
2239 GL_DepthTest(r_showshadowvolumes.integer < 2);
2240 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
2241 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2242 GL_CullFace(GL_NONE);
2243 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
2246 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
2248 R_Shadow_RenderMode_Reset();
2249 GL_BlendFunc(GL_ONE, GL_ONE);
2250 GL_DepthRange(0, 1);
2251 GL_DepthTest(r_showlighting.integer < 2);
2252 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2254 GL_DepthFunc(GL_EQUAL);
2255 R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2256 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2259 void R_Shadow_RenderMode_End(void)
2261 R_Shadow_RenderMode_Reset();
2262 R_Shadow_RenderMode_ActiveLight(NULL);
2264 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2265 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2268 int bboxedges[12][2] =
2287 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2289 if (!r_shadow_scissor.integer)
2291 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2292 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2293 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2294 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2297 if(R_ScissorForBBox(mins, maxs, r_shadow_lightscissor))
2298 return true; // invisible
2299 if(r_shadow_lightscissor[0] != r_refdef.view.viewport.x
2300 || r_shadow_lightscissor[1] != r_refdef.view.viewport.y
2301 || r_shadow_lightscissor[2] != r_refdef.view.viewport.width
2302 || r_shadow_lightscissor[3] != r_refdef.view.viewport.height)
2303 r_refdef.stats.lights_scissored++;
2307 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, const float *diffusecolor, const float *ambientcolor)
2310 const float *vertex3f;
2311 const float *normal3f;
2313 float dist, dot, distintensity, shadeintensity, v[3], n[3];
2314 switch (r_shadow_rendermode)
2316 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2317 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2318 if (VectorLength2(diffusecolor) > 0)
2320 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, normal3f = rsurface.batchnormal3f + 3*firstvertex, color4f = rsurface.array_passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, normal3f += 3, color4f += 4)
2322 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2323 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2324 if ((dot = DotProduct(n, v)) < 0)
2326 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2327 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
2330 VectorCopy(ambientcolor, color4f);
2331 if (r_refdef.fogenabled)
2334 f = RSurf_FogVertex(vertex3f);
2335 VectorScale(color4f, f, color4f);
2342 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.array_passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
2344 VectorCopy(ambientcolor, color4f);
2345 if (r_refdef.fogenabled)
2348 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2349 f = RSurf_FogVertex(vertex3f);
2350 VectorScale(color4f + 4*i, f, color4f);
2356 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2357 if (VectorLength2(diffusecolor) > 0)
2359 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, normal3f = rsurface.batchnormal3f + 3*firstvertex, color4f = rsurface.array_passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, normal3f += 3, color4f += 4)
2361 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2362 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2364 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2365 if ((dot = DotProduct(n, v)) < 0)
2367 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2368 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2369 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2370 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2374 color4f[0] = ambientcolor[0] * distintensity;
2375 color4f[1] = ambientcolor[1] * distintensity;
2376 color4f[2] = ambientcolor[2] * distintensity;
2378 if (r_refdef.fogenabled)
2381 f = RSurf_FogVertex(vertex3f);
2382 VectorScale(color4f, f, color4f);
2386 VectorClear(color4f);
2392 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.array_passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
2394 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2395 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2397 color4f[0] = ambientcolor[0] * distintensity;
2398 color4f[1] = ambientcolor[1] * distintensity;
2399 color4f[2] = ambientcolor[2] * distintensity;
2400 if (r_refdef.fogenabled)
2403 f = RSurf_FogVertex(vertex3f);
2404 VectorScale(color4f, f, color4f);
2408 VectorClear(color4f);
2413 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2414 if (VectorLength2(diffusecolor) > 0)
2416 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, normal3f = rsurface.batchnormal3f + 3*firstvertex, color4f = rsurface.array_passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, normal3f += 3, color4f += 4)
2418 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2419 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2421 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2422 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2423 if ((dot = DotProduct(n, v)) < 0)
2425 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2426 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2427 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2428 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2432 color4f[0] = ambientcolor[0] * distintensity;
2433 color4f[1] = ambientcolor[1] * distintensity;
2434 color4f[2] = ambientcolor[2] * distintensity;
2436 if (r_refdef.fogenabled)
2439 f = RSurf_FogVertex(vertex3f);
2440 VectorScale(color4f, f, color4f);
2444 VectorClear(color4f);
2450 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.array_passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
2452 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2453 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2455 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2456 color4f[0] = ambientcolor[0] * distintensity;
2457 color4f[1] = ambientcolor[1] * distintensity;
2458 color4f[2] = ambientcolor[2] * distintensity;
2459 if (r_refdef.fogenabled)
2462 f = RSurf_FogVertex(vertex3f);
2463 VectorScale(color4f, f, color4f);
2467 VectorClear(color4f);
2477 static void R_Shadow_RenderLighting_VisibleLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
2479 // used to display how many times a surface is lit for level design purposes
2480 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
2481 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
2485 static void R_Shadow_RenderLighting_Light_GLSL(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale, float specularscale)
2487 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2488 R_SetupShader_Surface(lightcolor, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT, texturenumsurfaces, texturesurfacelist, NULL);
2489 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2490 GL_DepthFunc(GL_EQUAL);
2492 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2493 GL_DepthFunc(GL_LEQUAL);
2496 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
2503 int newnumtriangles;
2507 int maxtriangles = 4096;
2508 static int newelements[4096*3];
2509 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, diffusecolor2, ambientcolor2);
2510 for (renders = 0;renders < 4;renders++)
2515 newnumtriangles = 0;
2517 // due to low fillrate on the cards this vertex lighting path is
2518 // designed for, we manually cull all triangles that do not
2519 // contain a lit vertex
2520 // this builds batches of triangles from multiple surfaces and
2521 // renders them at once
2522 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
2524 if (VectorLength2(rsurface.array_passcolor4f + e[0] * 4) + VectorLength2(rsurface.array_passcolor4f + e[1] * 4) + VectorLength2(rsurface.array_passcolor4f + e[2] * 4) >= 0.01)
2526 if (newnumtriangles)
2528 newfirstvertex = min(newfirstvertex, e[0]);
2529 newlastvertex = max(newlastvertex, e[0]);
2533 newfirstvertex = e[0];
2534 newlastvertex = e[0];
2536 newfirstvertex = min(newfirstvertex, e[1]);
2537 newlastvertex = max(newlastvertex, e[1]);
2538 newfirstvertex = min(newfirstvertex, e[2]);
2539 newlastvertex = max(newlastvertex, e[2]);
2545 if (newnumtriangles >= maxtriangles)
2547 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
2548 newnumtriangles = 0;
2554 if (newnumtriangles >= 1)
2556 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
2559 // if we couldn't find any lit triangles, exit early
2562 // now reduce the intensity for the next overbright pass
2563 // we have to clamp to 0 here incase the drivers have improper
2564 // handling of negative colors
2565 // (some old drivers even have improper handling of >1 color)
2567 for (i = 0, c = rsurface.array_passcolor4f + 4 * firstvertex;i < numvertices;i++, c += 4)
2569 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
2571 c[0] = max(0, c[0] - 1);
2572 c[1] = max(0, c[1] - 1);
2573 c[2] = max(0, c[2] - 1);
2585 static void R_Shadow_RenderLighting_Light_Vertex(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale)
2587 // OpenGL 1.1 path (anything)
2588 float ambientcolorbase[3], diffusecolorbase[3];
2589 float ambientcolorpants[3], diffusecolorpants[3];
2590 float ambientcolorshirt[3], diffusecolorshirt[3];
2591 const float *surfacecolor = rsurface.texture->dlightcolor;
2592 const float *surfacepants = rsurface.colormap_pantscolor;
2593 const float *surfaceshirt = rsurface.colormap_shirtcolor;
2594 rtexture_t *basetexture = rsurface.texture->basetexture;
2595 rtexture_t *pantstexture = rsurface.texture->pantstexture;
2596 rtexture_t *shirttexture = rsurface.texture->shirttexture;
2597 qboolean dopants = pantstexture && VectorLength2(surfacepants) >= (1.0f / 1048576.0f);
2598 qboolean doshirt = shirttexture && VectorLength2(surfaceshirt) >= (1.0f / 1048576.0f);
2599 ambientscale *= 2 * r_refdef.view.colorscale;
2600 diffusescale *= 2 * r_refdef.view.colorscale;
2601 ambientcolorbase[0] = lightcolor[0] * ambientscale * surfacecolor[0];ambientcolorbase[1] = lightcolor[1] * ambientscale * surfacecolor[1];ambientcolorbase[2] = lightcolor[2] * ambientscale * surfacecolor[2];
2602 diffusecolorbase[0] = lightcolor[0] * diffusescale * surfacecolor[0];diffusecolorbase[1] = lightcolor[1] * diffusescale * surfacecolor[1];diffusecolorbase[2] = lightcolor[2] * diffusescale * surfacecolor[2];
2603 ambientcolorpants[0] = ambientcolorbase[0] * surfacepants[0];ambientcolorpants[1] = ambientcolorbase[1] * surfacepants[1];ambientcolorpants[2] = ambientcolorbase[2] * surfacepants[2];
2604 diffusecolorpants[0] = diffusecolorbase[0] * surfacepants[0];diffusecolorpants[1] = diffusecolorbase[1] * surfacepants[1];diffusecolorpants[2] = diffusecolorbase[2] * surfacepants[2];
2605 ambientcolorshirt[0] = ambientcolorbase[0] * surfaceshirt[0];ambientcolorshirt[1] = ambientcolorbase[1] * surfaceshirt[1];ambientcolorshirt[2] = ambientcolorbase[2] * surfaceshirt[2];
2606 diffusecolorshirt[0] = diffusecolorbase[0] * surfaceshirt[0];diffusecolorshirt[1] = diffusecolorbase[1] * surfaceshirt[1];diffusecolorshirt[2] = diffusecolorbase[2] * surfaceshirt[2];
2607 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | (diffusescale > 0 ? BATCHNEED_ARRAY_NORMAL : 0) | BATCHNEED_ARRAY_TEXCOORD, texturenumsurfaces, texturesurfacelist);
2608 R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
2609 R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.array_passcolor4f, 0, 0);
2610 R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
2611 R_Mesh_TexBind(0, basetexture);
2612 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
2613 R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
2614 switch(r_shadow_rendermode)
2616 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2617 R_Mesh_TexBind(1, r_shadow_attenuation3dtexture);
2618 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
2619 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
2620 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
2622 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2623 R_Mesh_TexBind(2, r_shadow_attenuation2dtexture);
2624 R_Mesh_TexMatrix(2, &rsurface.entitytoattenuationz);
2625 R_Mesh_TexCombine(2, GL_MODULATE, GL_MODULATE, 1, 1);
2626 R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
2628 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2629 R_Mesh_TexBind(1, r_shadow_attenuation2dtexture);
2630 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
2631 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
2632 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
2634 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2639 //R_Mesh_TexBind(0, basetexture);
2640 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorbase, ambientcolorbase);
2643 R_Mesh_TexBind(0, pantstexture);
2644 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorpants, ambientcolorpants);
2648 R_Mesh_TexBind(0, shirttexture);
2649 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorshirt, ambientcolorshirt);
2653 extern cvar_t gl_lightmaps;
2654 void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
2656 float ambientscale, diffusescale, specularscale;
2658 float lightcolor[3];
2659 VectorCopy(rsurface.rtlight->currentcolor, lightcolor);
2660 ambientscale = rsurface.rtlight->ambientscale;
2661 diffusescale = rsurface.rtlight->diffusescale;
2662 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
2663 if (!r_shadow_usenormalmap.integer)
2665 ambientscale += 1.0f * diffusescale;
2669 if ((ambientscale + diffusescale) * VectorLength2(lightcolor) + specularscale * VectorLength2(lightcolor) < (1.0f / 1048576.0f))
2671 negated = (lightcolor[0] + lightcolor[1] + lightcolor[2] < 0) && vid.support.ext_blend_subtract;
2674 VectorNegate(lightcolor, lightcolor);
2675 switch(vid.renderpath)
2677 case RENDERPATH_GL11:
2678 case RENDERPATH_GL13:
2679 case RENDERPATH_GL20:
2680 case RENDERPATH_CGGL:
2681 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
2683 case RENDERPATH_D3D9:
2685 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_SUBTRACT);
2688 case RENDERPATH_D3D10:
2689 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2691 case RENDERPATH_D3D11:
2692 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2696 RSurf_SetupDepthAndCulling();
2697 switch (r_shadow_rendermode)
2699 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2700 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2701 R_Shadow_RenderLighting_VisibleLighting(texturenumsurfaces, texturesurfacelist);
2703 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2704 R_Shadow_RenderLighting_Light_GLSL(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale, specularscale);
2706 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2707 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2708 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2709 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2710 R_Shadow_RenderLighting_Light_Vertex(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale);
2713 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2718 switch(vid.renderpath)
2720 case RENDERPATH_GL11:
2721 case RENDERPATH_GL13:
2722 case RENDERPATH_GL20:
2723 case RENDERPATH_CGGL:
2724 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
2726 case RENDERPATH_D3D9:
2728 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_ADD);
2731 case RENDERPATH_D3D10:
2732 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2734 case RENDERPATH_D3D11:
2735 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2741 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)
2743 matrix4x4_t tempmatrix = *matrix;
2744 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
2746 // if this light has been compiled before, free the associated data
2747 R_RTLight_Uncompile(rtlight);
2749 // clear it completely to avoid any lingering data
2750 memset(rtlight, 0, sizeof(*rtlight));
2752 // copy the properties
2753 rtlight->matrix_lighttoworld = tempmatrix;
2754 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
2755 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
2756 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
2757 VectorCopy(color, rtlight->color);
2758 rtlight->cubemapname[0] = 0;
2759 if (cubemapname && cubemapname[0])
2760 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
2761 rtlight->shadow = shadow;
2762 rtlight->corona = corona;
2763 rtlight->style = style;
2764 rtlight->isstatic = isstatic;
2765 rtlight->coronasizescale = coronasizescale;
2766 rtlight->ambientscale = ambientscale;
2767 rtlight->diffusescale = diffusescale;
2768 rtlight->specularscale = specularscale;
2769 rtlight->flags = flags;
2771 // compute derived data
2772 //rtlight->cullradius = rtlight->radius;
2773 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2774 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2775 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2776 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2777 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2778 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2779 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2782 // compiles rtlight geometry
2783 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2784 void R_RTLight_Compile(rtlight_t *rtlight)
2787 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
2788 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
2789 entity_render_t *ent = r_refdef.scene.worldentity;
2790 dp_model_t *model = r_refdef.scene.worldmodel;
2791 unsigned char *data;
2794 // compile the light
2795 rtlight->compiled = true;
2796 rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
2797 rtlight->static_numleafs = 0;
2798 rtlight->static_numleafpvsbytes = 0;
2799 rtlight->static_leaflist = NULL;
2800 rtlight->static_leafpvs = NULL;
2801 rtlight->static_numsurfaces = 0;
2802 rtlight->static_surfacelist = NULL;
2803 rtlight->static_shadowmap_receivers = 0x3F;
2804 rtlight->static_shadowmap_casters = 0x3F;
2805 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2806 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2807 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2808 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2809 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2810 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2812 if (model && model->GetLightInfo)
2814 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
2815 r_shadow_compilingrtlight = rtlight;
2816 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);
2817 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2818 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
2819 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
2820 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
2821 rtlight->static_numsurfaces = numsurfaces;
2822 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
2823 rtlight->static_numleafs = numleafs;
2824 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
2825 rtlight->static_numleafpvsbytes = numleafpvsbytes;
2826 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
2827 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
2828 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
2829 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
2830 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
2831 if (rtlight->static_numsurfaces)
2832 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
2833 if (rtlight->static_numleafs)
2834 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
2835 if (rtlight->static_numleafpvsbytes)
2836 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
2837 if (rtlight->static_numshadowtrispvsbytes)
2838 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
2839 if (rtlight->static_numlighttrispvsbytes)
2840 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
2841 switch (rtlight->shadowmode)
2843 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2844 if (model->CompileShadowMap && rtlight->shadow)
2845 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2848 if (model->CompileShadowVolume && rtlight->shadow)
2849 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2852 // now we're done compiling the rtlight
2853 r_shadow_compilingrtlight = NULL;
2857 // use smallest available cullradius - box radius or light radius
2858 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2859 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2861 shadowzpasstris = 0;
2862 if (rtlight->static_meshchain_shadow_zpass)
2863 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
2864 shadowzpasstris += mesh->numtriangles;
2866 shadowzfailtris = 0;
2867 if (rtlight->static_meshchain_shadow_zfail)
2868 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
2869 shadowzfailtris += mesh->numtriangles;
2872 if (rtlight->static_numlighttrispvsbytes)
2873 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
2874 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
2878 if (rtlight->static_numlighttrispvsbytes)
2879 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
2880 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
2883 if (developer_extra.integer)
2884 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);
2887 void R_RTLight_Uncompile(rtlight_t *rtlight)
2889 if (rtlight->compiled)
2891 if (rtlight->static_meshchain_shadow_zpass)
2892 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
2893 rtlight->static_meshchain_shadow_zpass = NULL;
2894 if (rtlight->static_meshchain_shadow_zfail)
2895 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
2896 rtlight->static_meshchain_shadow_zfail = NULL;
2897 if (rtlight->static_meshchain_shadow_shadowmap)
2898 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
2899 rtlight->static_meshchain_shadow_shadowmap = NULL;
2900 // these allocations are grouped
2901 if (rtlight->static_surfacelist)
2902 Mem_Free(rtlight->static_surfacelist);
2903 rtlight->static_numleafs = 0;
2904 rtlight->static_numleafpvsbytes = 0;
2905 rtlight->static_leaflist = NULL;
2906 rtlight->static_leafpvs = NULL;
2907 rtlight->static_numsurfaces = 0;
2908 rtlight->static_surfacelist = NULL;
2909 rtlight->static_numshadowtrispvsbytes = 0;
2910 rtlight->static_shadowtrispvs = NULL;
2911 rtlight->static_numlighttrispvsbytes = 0;
2912 rtlight->static_lighttrispvs = NULL;
2913 rtlight->compiled = false;
2917 void R_Shadow_UncompileWorldLights(void)
2921 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
2922 for (lightindex = 0;lightindex < range;lightindex++)
2924 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2927 R_RTLight_Uncompile(&light->rtlight);
2931 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
2935 // reset the count of frustum planes
2936 // see rtlight->cached_frustumplanes definition for how much this array
2938 rtlight->cached_numfrustumplanes = 0;
2940 // haven't implemented a culling path for ortho rendering
2941 if (!r_refdef.view.useperspective)
2943 // check if the light is on screen and copy the 4 planes if it is
2944 for (i = 0;i < 4;i++)
2945 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
2948 for (i = 0;i < 4;i++)
2949 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
2954 // generate a deformed frustum that includes the light origin, this is
2955 // used to cull shadow casting surfaces that can not possibly cast a
2956 // shadow onto the visible light-receiving surfaces, which can be a
2959 // if the light origin is onscreen the result will be 4 planes exactly
2960 // if the light origin is offscreen on only one axis the result will
2961 // be exactly 5 planes (split-side case)
2962 // if the light origin is offscreen on two axes the result will be
2963 // exactly 4 planes (stretched corner case)
2964 for (i = 0;i < 4;i++)
2966 // quickly reject standard frustum planes that put the light
2967 // origin outside the frustum
2968 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
2971 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
2973 // if all the standard frustum planes were accepted, the light is onscreen
2974 // otherwise we need to generate some more planes below...
2975 if (rtlight->cached_numfrustumplanes < 4)
2977 // at least one of the stock frustum planes failed, so we need to
2978 // create one or two custom planes to enclose the light origin
2979 for (i = 0;i < 4;i++)
2981 // create a plane using the view origin and light origin, and a
2982 // single point from the frustum corner set
2983 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
2984 VectorNormalize(plane.normal);
2985 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
2986 // see if this plane is backwards and flip it if so
2987 for (j = 0;j < 4;j++)
2988 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
2992 VectorNegate(plane.normal, plane.normal);
2994 // flipped plane, test again to see if it is now valid
2995 for (j = 0;j < 4;j++)
2996 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
2998 // if the plane is still not valid, then it is dividing the
2999 // frustum and has to be rejected
3003 // we have created a valid plane, compute extra info
3004 PlaneClassify(&plane);
3006 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3008 // if we've found 5 frustum planes then we have constructed a
3009 // proper split-side case and do not need to keep searching for
3010 // planes to enclose the light origin
3011 if (rtlight->cached_numfrustumplanes == 5)
3019 for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
3021 plane = rtlight->cached_frustumplanes[i];
3022 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));
3027 // now add the light-space box planes if the light box is rotated, as any
3028 // caster outside the oriented light box is irrelevant (even if it passed
3029 // the worldspace light box, which is axial)
3030 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3032 for (i = 0;i < 6;i++)
3036 v[i >> 1] = (i & 1) ? -1 : 1;
3037 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3038 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3039 plane.dist = VectorNormalizeLength(plane.normal);
3040 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3041 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3047 // add the world-space reduced box planes
3048 for (i = 0;i < 6;i++)
3050 VectorClear(plane.normal);
3051 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3052 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
3053 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3062 // reduce all plane distances to tightly fit the rtlight cull box, which
3064 VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3065 VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3066 VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3067 VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3068 VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3069 VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3070 VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3071 VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3072 oldnum = rtlight->cached_numfrustumplanes;
3073 rtlight->cached_numfrustumplanes = 0;
3074 for (j = 0;j < oldnum;j++)
3076 // find the nearest point on the box to this plane
3077 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
3078 for (i = 1;i < 8;i++)
3080 dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
3081 if (bestdist > dist)
3084 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);
3085 // if the nearest point is near or behind the plane, we want this
3086 // plane, otherwise the plane is useless as it won't cull anything
3087 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
3089 PlaneClassify(&rtlight->cached_frustumplanes[j]);
3090 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
3097 void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
3101 RSurf_ActiveWorldEntity();
3103 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3106 GL_CullFace(GL_NONE);
3107 mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3108 for (;mesh;mesh = mesh->next)
3110 if (!mesh->sidetotals[r_shadow_shadowmapside])
3112 r_refdef.stats.lights_shadowtriangles += mesh->sidetotals[r_shadow_shadowmapside];
3113 R_Mesh_PrepareVertices_Position(mesh->numverts, mesh->vertexposition, mesh->vertexpositionbuffer);
3114 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);
3118 else if (r_refdef.scene.worldentity->model)
3119 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);
3121 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3124 void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3126 qboolean zpass = false;
3129 int surfacelistindex;
3130 msurface_t *surface;
3132 RSurf_ActiveWorldEntity();
3134 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3137 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
3139 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
3140 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
3142 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
3143 for (;mesh;mesh = mesh->next)
3145 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
3146 R_Mesh_PrepareVertices_Position(mesh->numverts, mesh->vertexposition, mesh->vertexpositionbuffer);
3147 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
3149 // increment stencil if frontface is infront of depthbuffer
3150 GL_CullFace(r_refdef.view.cullface_back);
3151 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
3152 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);
3153 // decrement stencil if backface is infront of depthbuffer
3154 GL_CullFace(r_refdef.view.cullface_front);
3155 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
3157 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
3159 // decrement stencil if backface is behind depthbuffer
3160 GL_CullFace(r_refdef.view.cullface_front);
3161 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
3162 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);
3163 // increment stencil if frontface is behind depthbuffer
3164 GL_CullFace(r_refdef.view.cullface_back);
3165 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
3167 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3i_indexbuffer, mesh->element3i_bufferoffset, mesh->element3s, mesh->element3s_indexbuffer, mesh->element3s_bufferoffset);
3171 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh)
3173 // use the shadow trispvs calculated earlier by GetLightInfo to cull world triangles on this dynamic light
3174 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
3175 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
3177 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
3178 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
3179 if (CHECKPVSBIT(trispvs, t))
3180 shadowmarklist[numshadowmark++] = t;
3182 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);
3184 else if (numsurfaces)
3185 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);
3187 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3190 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3192 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3193 vec_t relativeshadowradius;
3194 RSurf_ActiveModelEntity(ent, false, false, false);
3195 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3196 // we need to re-init the shader for each entity because the matrix changed
3197 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3198 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3199 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3200 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3201 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3202 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3203 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3204 switch (r_shadow_rendermode)
3206 case R_SHADOW_RENDERMODE_SHADOWMAP2D:
3207 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
3210 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3213 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3216 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3218 // set up properties for rendering light onto this entity
3219 RSurf_ActiveModelEntity(ent, true, true, false);
3220 GL_AlphaTest(false);
3221 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3222 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3223 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3224 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3227 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
3229 if (!r_refdef.scene.worldmodel->DrawLight)
3232 // set up properties for rendering light onto this entity
3233 RSurf_ActiveWorldEntity();
3234 GL_AlphaTest(false);
3235 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3236 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3237 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3238 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3240 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
3242 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3245 void R_Shadow_DrawEntityLight(entity_render_t *ent)
3247 dp_model_t *model = ent->model;
3248 if (!model->DrawLight)
3251 R_Shadow_SetupEntityLight(ent);
3253 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3255 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3258 void R_Shadow_PrepareLight(rtlight_t *rtlight)
3262 int numleafs, numsurfaces;
3263 int *leaflist, *surfacelist;
3264 unsigned char *leafpvs;
3265 unsigned char *shadowtrispvs;
3266 unsigned char *lighttrispvs;
3267 //unsigned char *surfacesides;
3268 int numlightentities;
3269 int numlightentities_noselfshadow;
3270 int numshadowentities;
3271 int numshadowentities_noselfshadow;
3272 static entity_render_t *lightentities[MAX_EDICTS];
3273 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3274 static entity_render_t *shadowentities[MAX_EDICTS];
3275 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3278 rtlight->draw = false;
3280 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3281 // skip lights that are basically invisible (color 0 0 0)
3282 nolight = VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f);
3284 // loading is done before visibility checks because loading should happen
3285 // all at once at the start of a level, not when it stalls gameplay.
3286 // (especially important to benchmarks)
3288 if (rtlight->isstatic && !nolight && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
3290 if (rtlight->compiled)
3291 R_RTLight_Uncompile(rtlight);
3292 R_RTLight_Compile(rtlight);
3296 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
3298 // look up the light style value at this time
3299 f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3300 VectorScale(rtlight->color, f, rtlight->currentcolor);
3302 if (rtlight->selected)
3304 f = 2 + sin(realtime * M_PI * 4.0);
3305 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3309 // if lightstyle is currently off, don't draw the light
3310 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3313 // skip processing on corona-only lights
3317 // if the light box is offscreen, skip it
3318 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3321 VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
3322 VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
3324 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3326 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3328 // compiled light, world available and can receive realtime lighting
3329 // retrieve leaf information
3330 numleafs = rtlight->static_numleafs;
3331 leaflist = rtlight->static_leaflist;
3332 leafpvs = rtlight->static_leafpvs;
3333 numsurfaces = rtlight->static_numsurfaces;
3334 surfacelist = rtlight->static_surfacelist;
3335 //surfacesides = NULL;
3336 shadowtrispvs = rtlight->static_shadowtrispvs;
3337 lighttrispvs = rtlight->static_lighttrispvs;
3339 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3341 // dynamic light, world available and can receive realtime lighting
3342 // calculate lit surfaces and leafs
3343 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);
3344 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3345 leaflist = r_shadow_buffer_leaflist;
3346 leafpvs = r_shadow_buffer_leafpvs;
3347 surfacelist = r_shadow_buffer_surfacelist;
3348 //surfacesides = r_shadow_buffer_surfacesides;
3349 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3350 lighttrispvs = r_shadow_buffer_lighttrispvs;
3351 // if the reduced leaf bounds are offscreen, skip it
3352 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3363 //surfacesides = NULL;
3364 shadowtrispvs = NULL;
3365 lighttrispvs = NULL;
3367 // check if light is illuminating any visible leafs
3370 for (i = 0;i < numleafs;i++)
3371 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3377 // make a list of lit entities and shadow casting entities
3378 numlightentities = 0;
3379 numlightentities_noselfshadow = 0;
3380 numshadowentities = 0;
3381 numshadowentities_noselfshadow = 0;
3383 // add dynamic entities that are lit by the light
3384 for (i = 0;i < r_refdef.scene.numentities;i++)
3387 entity_render_t *ent = r_refdef.scene.entities[i];
3389 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3391 // skip the object entirely if it is not within the valid
3392 // shadow-casting region (which includes the lit region)
3393 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
3395 if (!(model = ent->model))
3397 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
3399 // this entity wants to receive light, is visible, and is
3400 // inside the light box
3401 // TODO: check if the surfaces in the model can receive light
3402 // so now check if it's in a leaf seen by the light
3403 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))
3405 if (ent->flags & RENDER_NOSELFSHADOW)
3406 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
3408 lightentities[numlightentities++] = ent;
3409 // since it is lit, it probably also casts a shadow...
3410 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3411 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3412 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3414 // note: exterior models without the RENDER_NOSELFSHADOW
3415 // flag still create a RENDER_NOSELFSHADOW shadow but
3416 // are lit normally, this means that they are
3417 // self-shadowing but do not shadow other
3418 // RENDER_NOSELFSHADOW entities such as the gun
3419 // (very weird, but keeps the player shadow off the gun)
3420 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3421 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3423 shadowentities[numshadowentities++] = ent;
3426 else if (ent->flags & RENDER_SHADOW)
3428 // this entity is not receiving light, but may still need to
3430 // TODO: check if the surfaces in the model can cast shadow
3431 // now check if it is in a leaf seen by the light
3432 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))
3434 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3435 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3436 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3438 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3439 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3441 shadowentities[numshadowentities++] = ent;
3446 // return if there's nothing at all to light
3447 if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
3450 // count this light in the r_speeds
3451 r_refdef.stats.lights++;
3453 // flag it as worth drawing later
3454 rtlight->draw = true;
3456 // cache all the animated entities that cast a shadow but are not visible
3457 for (i = 0;i < numshadowentities;i++)
3458 if (!shadowentities[i]->animcache_vertex3f)
3459 R_AnimCache_GetEntity(shadowentities[i], false, false);
3460 for (i = 0;i < numshadowentities_noselfshadow;i++)
3461 if (!shadowentities_noselfshadow[i]->animcache_vertex3f)
3462 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
3464 // allocate some temporary memory for rendering this light later in the frame
3465 // reusable buffers need to be copied, static data can be used as-is
3466 rtlight->cached_numlightentities = numlightentities;
3467 rtlight->cached_numlightentities_noselfshadow = numlightentities_noselfshadow;
3468 rtlight->cached_numshadowentities = numshadowentities;
3469 rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
3470 rtlight->cached_numsurfaces = numsurfaces;
3471 rtlight->cached_lightentities = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
3472 rtlight->cached_lightentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
3473 rtlight->cached_shadowentities = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
3474 rtlight->cached_shadowentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
3475 if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
3477 int numshadowtrispvsbytes = (((r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles) + 7) >> 3);
3478 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
3479 rtlight->cached_shadowtrispvs = (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
3480 rtlight->cached_lighttrispvs = (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
3481 rtlight->cached_surfacelist = (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
3485 // compiled light data
3486 rtlight->cached_shadowtrispvs = shadowtrispvs;
3487 rtlight->cached_lighttrispvs = lighttrispvs;
3488 rtlight->cached_surfacelist = surfacelist;
3492 void R_Shadow_DrawLight(rtlight_t *rtlight)
3496 unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
3497 int numlightentities;
3498 int numlightentities_noselfshadow;
3499 int numshadowentities;
3500 int numshadowentities_noselfshadow;
3501 entity_render_t **lightentities;
3502 entity_render_t **lightentities_noselfshadow;
3503 entity_render_t **shadowentities;
3504 entity_render_t **shadowentities_noselfshadow;
3506 static unsigned char entitysides[MAX_EDICTS];
3507 static unsigned char entitysides_noselfshadow[MAX_EDICTS];
3508 vec3_t nearestpoint;
3510 qboolean castshadows;
3513 // check if we cached this light this frame (meaning it is worth drawing)
3517 // if R_FrameData_Store ran out of space we skip anything dependent on it
3518 if (r_framedata_failed)
3521 numlightentities = rtlight->cached_numlightentities;
3522 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
3523 numshadowentities = rtlight->cached_numshadowentities;
3524 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
3525 numsurfaces = rtlight->cached_numsurfaces;
3526 lightentities = rtlight->cached_lightentities;
3527 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
3528 shadowentities = rtlight->cached_shadowentities;
3529 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
3530 shadowtrispvs = rtlight->cached_shadowtrispvs;
3531 lighttrispvs = rtlight->cached_lighttrispvs;
3532 surfacelist = rtlight->cached_surfacelist;
3534 // set up a scissor rectangle for this light
3535 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3538 // don't let sound skip if going slow
3539 if (r_refdef.scene.extraupdate)
3542 // make this the active rtlight for rendering purposes
3543 R_Shadow_RenderMode_ActiveLight(rtlight);
3545 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
3547 // optionally draw visible shape of the shadow volumes
3548 // for performance analysis by level designers
3549 R_Shadow_RenderMode_VisibleShadowVolumes();
3551 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
3552 for (i = 0;i < numshadowentities;i++)
3553 R_Shadow_DrawEntityShadow(shadowentities[i]);
3554 for (i = 0;i < numshadowentities_noselfshadow;i++)
3555 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3556 R_Shadow_RenderMode_VisibleLighting(false, false);
3559 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
3561 // optionally draw the illuminated areas
3562 // for performance analysis by level designers
3563 R_Shadow_RenderMode_VisibleLighting(false, false);
3565 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3566 for (i = 0;i < numlightentities;i++)
3567 R_Shadow_DrawEntityLight(lightentities[i]);
3568 for (i = 0;i < numlightentities_noselfshadow;i++)
3569 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3572 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
3574 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
3575 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
3576 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
3577 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
3579 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance/rtlight->radius));
3580 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
3581 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
3583 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
3589 int receivermask = 0;
3590 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
3591 Matrix4x4_Abs(&radiustolight);
3593 r_shadow_shadowmaplod = 0;
3594 for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
3595 if ((r_shadow_shadowmapmaxsize >> i) > lodlinear)
3596 r_shadow_shadowmaplod = i;
3598 size = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
3600 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
3602 surfacesides = NULL;
3605 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3607 castermask = rtlight->static_shadowmap_casters;
3608 receivermask = rtlight->static_shadowmap_receivers;
3612 surfacesides = r_shadow_buffer_surfacesides;
3613 for(i = 0;i < numsurfaces;i++)
3615 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
3616 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3617 castermask |= surfacesides[i];
3618 receivermask |= surfacesides[i];
3622 if (receivermask < 0x3F)
3624 for (i = 0;i < numlightentities;i++)
3625 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3626 if (receivermask < 0x3F)
3627 for(i = 0; i < numlightentities_noselfshadow;i++)
3628 receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3631 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
3635 for (i = 0;i < numshadowentities;i++)
3636 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3637 for (i = 0;i < numshadowentities_noselfshadow;i++)
3638 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3641 //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
3643 // render shadow casters into 6 sided depth texture
3644 for (side = 0;side < 6;side++) if (receivermask & (1 << side))
3646 R_Shadow_RenderMode_ShadowMap(side, receivermask, size);
3647 if (! (castermask & (1 << side))) continue;
3649 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
3650 for (i = 0;i < numshadowentities;i++) if (entitysides[i] & (1 << side))
3651 R_Shadow_DrawEntityShadow(shadowentities[i]);
3654 if (numlightentities_noselfshadow)
3656 // render lighting using the depth texture as shadowmap
3657 // draw lighting in the unmasked areas
3658 R_Shadow_RenderMode_Lighting(false, false, true);
3659 for (i = 0;i < numlightentities_noselfshadow;i++)
3660 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3663 // render shadow casters into 6 sided depth texture
3664 if (numshadowentities_noselfshadow)
3666 for (side = 0;side < 6;side++) if ((receivermask & castermask) & (1 << side))
3668 R_Shadow_RenderMode_ShadowMap(side, 0, size);
3669 for (i = 0;i < numshadowentities_noselfshadow;i++) if (entitysides_noselfshadow[i] & (1 << side))
3670 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3674 // render lighting using the depth texture as shadowmap
3675 // draw lighting in the unmasked areas
3676 R_Shadow_RenderMode_Lighting(false, false, true);
3677 // draw lighting in the unmasked areas
3679 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3680 for (i = 0;i < numlightentities;i++)
3681 R_Shadow_DrawEntityLight(lightentities[i]);
3683 else if (castshadows && vid.stencil)
3685 // draw stencil shadow volumes to mask off pixels that are in shadow
3686 // so that they won't receive lighting
3687 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
3688 R_Shadow_ClearStencil();
3691 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
3692 for (i = 0;i < numshadowentities;i++)
3693 R_Shadow_DrawEntityShadow(shadowentities[i]);
3695 // draw lighting in the unmasked areas
3696 R_Shadow_RenderMode_Lighting(true, false, false);
3697 for (i = 0;i < numlightentities_noselfshadow;i++)
3698 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3700 for (i = 0;i < numshadowentities_noselfshadow;i++)
3701 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3703 // draw lighting in the unmasked areas
3704 R_Shadow_RenderMode_Lighting(true, false, false);
3706 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3707 for (i = 0;i < numlightentities;i++)
3708 R_Shadow_DrawEntityLight(lightentities[i]);
3712 // draw lighting in the unmasked areas
3713 R_Shadow_RenderMode_Lighting(false, false, false);
3715 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3716 for (i = 0;i < numlightentities;i++)
3717 R_Shadow_DrawEntityLight(lightentities[i]);
3718 for (i = 0;i < numlightentities_noselfshadow;i++)
3719 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3722 if (r_shadow_usingdeferredprepass)
3724 // when rendering deferred lighting, we simply rasterize the box
3725 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
3726 R_Shadow_RenderMode_DrawDeferredLight(false, true);
3727 else if (castshadows && vid.stencil)
3728 R_Shadow_RenderMode_DrawDeferredLight(true, false);
3730 R_Shadow_RenderMode_DrawDeferredLight(false, false);
3734 static void R_Shadow_FreeDeferred(void)
3736 R_Mesh_DestroyFramebufferObject(r_shadow_prepassgeometryfbo);
3737 r_shadow_prepassgeometryfbo = 0;
3739 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingfbo);
3740 r_shadow_prepasslightingfbo = 0;
3742 if (r_shadow_prepassgeometrydepthtexture)
3743 R_FreeTexture(r_shadow_prepassgeometrydepthtexture);
3744 r_shadow_prepassgeometrydepthtexture = NULL;
3746 if (r_shadow_prepassgeometrydepthcolortexture)
3747 R_FreeTexture(r_shadow_prepassgeometrydepthcolortexture);
3748 r_shadow_prepassgeometrydepthcolortexture = NULL;
3750 if (r_shadow_prepassgeometrynormalmaptexture)
3751 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
3752 r_shadow_prepassgeometrynormalmaptexture = NULL;
3754 if (r_shadow_prepasslightingdiffusetexture)
3755 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
3756 r_shadow_prepasslightingdiffusetexture = NULL;
3758 if (r_shadow_prepasslightingspeculartexture)
3759 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
3760 r_shadow_prepasslightingspeculartexture = NULL;
3763 void R_Shadow_DrawPrepass(void)
3771 entity_render_t *ent;
3772 float clearcolor[4];
3774 GL_AlphaTest(false);
3775 R_Mesh_ResetTextureState();
3777 GL_ColorMask(1,1,1,1);
3778 GL_BlendFunc(GL_ONE, GL_ZERO);
3781 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, r_shadow_prepassgeometrydepthcolortexture, NULL, NULL);
3782 Vector4Set(clearcolor, 0.5f,0.5f,0.5f,1.0f);
3783 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
3784 if (r_timereport_active)
3785 R_TimeReport("prepasscleargeom");
3787 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
3788 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
3789 if (r_timereport_active)
3790 R_TimeReport("prepassworld");
3792 for (i = 0;i < r_refdef.scene.numentities;i++)
3794 if (!r_refdef.viewcache.entityvisible[i])
3796 ent = r_refdef.scene.entities[i];
3797 if (ent->model && ent->model->DrawPrepass != NULL)
3798 ent->model->DrawPrepass(ent);
3801 if (r_timereport_active)
3802 R_TimeReport("prepassmodels");
3804 GL_DepthMask(false);
3805 GL_ColorMask(1,1,1,1);
3808 R_Mesh_SetRenderTargets(r_shadow_prepasslightingfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
3809 Vector4Set(clearcolor, 0, 0, 0, 0);
3810 GL_Clear(GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
3811 if (r_timereport_active)
3812 R_TimeReport("prepassclearlit");
3814 R_Shadow_RenderMode_Begin();
3816 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3817 if (r_shadow_debuglight.integer >= 0)
3819 lightindex = r_shadow_debuglight.integer;
3820 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3821 if (light && (light->flags & flag))
3822 R_Shadow_DrawLight(&light->rtlight);
3826 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3827 for (lightindex = 0;lightindex < range;lightindex++)
3829 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3830 if (light && (light->flags & flag))
3831 R_Shadow_DrawLight(&light->rtlight);
3834 if (r_refdef.scene.rtdlight)
3835 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
3836 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
3838 R_Mesh_ResetRenderTargets();
3840 R_Shadow_RenderMode_End();
3842 if (r_timereport_active)
3843 R_TimeReport("prepasslights");
3846 void R_Shadow_DrawLightSprites(void);
3847 void R_Shadow_PrepareLights(void)
3857 if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4) ||
3858 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
3859 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20) ||
3860 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
3861 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
3862 r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
3863 R_Shadow_FreeShadowMaps();
3865 r_shadow_usingshadowmaportho = false;
3867 switch (vid.renderpath)
3869 case RENDERPATH_GL20:
3870 case RENDERPATH_CGGL:
3871 case RENDERPATH_D3D9:
3872 case RENDERPATH_D3D10:
3873 case RENDERPATH_D3D11:
3874 if (!r_shadow_deferred.integer || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_STENCIL || !vid.support.ext_framebuffer_object || vid.maxdrawbuffers < 2)
3876 r_shadow_usingdeferredprepass = false;
3877 if (r_shadow_prepass_width)
3878 R_Shadow_FreeDeferred();
3879 r_shadow_prepass_width = r_shadow_prepass_height = 0;
3883 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
3885 R_Shadow_FreeDeferred();
3887 r_shadow_usingdeferredprepass = true;
3888 r_shadow_prepass_width = vid.width;
3889 r_shadow_prepass_height = vid.height;
3890 r_shadow_prepassgeometrydepthtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "prepassgeometrydepthmap", vid.width, vid.height, 24, false);
3891 switch (vid.renderpath)
3893 case RENDERPATH_D3D9:
3894 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);
3899 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);
3900 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);
3901 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);
3903 // set up the geometry pass fbo (depth + normalmap)
3904 r_shadow_prepassgeometryfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
3905 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, r_shadow_prepassgeometrydepthcolortexture, NULL, NULL);
3906 // render depth into one texture and normalmap into the other
3907 if (qglDrawBuffersARB)
3909 qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);CHECKGLERROR
3910 qglReadBuffer(GL_NONE);CHECKGLERROR
3911 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
3912 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
3914 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
3915 Cvar_SetValueQuick(&r_shadow_deferred, 0);
3916 r_shadow_usingdeferredprepass = false;
3920 // set up the lighting pass fbo (diffuse + specular)
3921 r_shadow_prepasslightingfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
3922 R_Mesh_SetRenderTargets(r_shadow_prepasslightingfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
3923 // render diffuse into one texture and specular into another,
3924 // with depth and normalmap bound as textures,
3925 // with depth bound as attachment as well
3926 if (qglDrawBuffersARB)
3928 qglDrawBuffersARB(2, r_shadow_prepasslightingdrawbuffers);CHECKGLERROR
3929 qglReadBuffer(GL_NONE);CHECKGLERROR
3930 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
3931 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
3933 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
3934 Cvar_SetValueQuick(&r_shadow_deferred, 0);
3935 r_shadow_usingdeferredprepass = false;
3940 case RENDERPATH_GL13:
3941 case RENDERPATH_GL11:
3942 r_shadow_usingdeferredprepass = false;
3946 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);
3948 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3949 if (r_shadow_debuglight.integer >= 0)
3951 lightindex = r_shadow_debuglight.integer;
3952 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3953 if (light && (light->flags & flag))
3954 R_Shadow_PrepareLight(&light->rtlight);
3958 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3959 for (lightindex = 0;lightindex < range;lightindex++)
3961 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3962 if (light && (light->flags & flag))
3963 R_Shadow_PrepareLight(&light->rtlight);
3966 if (r_refdef.scene.rtdlight)
3968 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
3969 R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
3971 else if(gl_flashblend.integer)
3973 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
3975 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
3976 f = (rtlight->style >= 0 ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3977 VectorScale(rtlight->color, f, rtlight->currentcolor);
3981 if (r_editlights.integer)
3982 R_Shadow_DrawLightSprites();
3985 void R_Shadow_DrawLights(void)
3993 R_Shadow_RenderMode_Begin();
3995 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3996 if (r_shadow_debuglight.integer >= 0)
3998 lightindex = r_shadow_debuglight.integer;
3999 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4000 if (light && (light->flags & flag))
4001 R_Shadow_DrawLight(&light->rtlight);
4005 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4006 for (lightindex = 0;lightindex < range;lightindex++)
4008 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4009 if (light && (light->flags & flag))
4010 R_Shadow_DrawLight(&light->rtlight);
4013 if (r_refdef.scene.rtdlight)
4014 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4015 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4017 R_Shadow_RenderMode_End();
4020 extern const float r_screenvertex3f[12];
4021 extern void R_SetupView(qboolean allowwaterclippingplane);
4022 extern void R_ResetViewRendering3D(void);
4023 extern void R_ResetViewRendering2D(void);
4024 extern cvar_t r_shadows;
4025 extern cvar_t r_shadows_darken;
4026 extern cvar_t r_shadows_drawafterrtlighting;
4027 extern cvar_t r_shadows_castfrombmodels;
4028 extern cvar_t r_shadows_throwdistance;
4029 extern cvar_t r_shadows_throwdirection;
4030 extern cvar_t r_shadows_focus;
4031 extern cvar_t r_shadows_shadowmapscale;
4033 void R_Shadow_PrepareModelShadows(void)
4036 float scale, size, radius, dot1, dot2;
4037 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
4038 entity_render_t *ent;
4040 if (!r_refdef.scene.numentities)
4043 switch (r_shadow_shadowmode)
4045 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4046 if (r_shadows.integer >= 2)
4049 case R_SHADOW_SHADOWMODE_STENCIL:
4050 for (i = 0;i < r_refdef.scene.numentities;i++)
4052 ent = r_refdef.scene.entities[i];
4053 if (!ent->animcache_vertex3f && ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4054 R_AnimCache_GetEntity(ent, false, false);
4061 size = 2*r_shadow_shadowmapmaxsize;
4062 scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
4063 radius = 0.5f * size / scale;
4065 Math_atov(r_shadows_throwdirection.string, shadowdir);
4066 VectorNormalize(shadowdir);
4067 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4068 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4069 if (fabs(dot1) <= fabs(dot2))
4070 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4072 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4073 VectorNormalize(shadowforward);
4074 CrossProduct(shadowdir, shadowforward, shadowright);
4075 Math_atov(r_shadows_focus.string, shadowfocus);
4076 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4077 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4078 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4079 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4080 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4082 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4084 shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4085 shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4086 shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4087 shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4088 shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4089 shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4091 for (i = 0;i < r_refdef.scene.numentities;i++)
4093 ent = r_refdef.scene.entities[i];
4094 if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
4096 // cast shadows from anything of the map (submodels are optional)
4097 if (!ent->animcache_vertex3f && ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4098 R_AnimCache_GetEntity(ent, false, false);
4102 void R_DrawModelShadowMaps(void)
4105 float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
4106 entity_render_t *ent;
4107 vec3_t relativelightorigin;
4108 vec3_t relativelightdirection, relativeforward, relativeright;
4109 vec3_t relativeshadowmins, relativeshadowmaxs;
4110 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
4112 matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
4113 r_viewport_t viewport;
4115 float clearcolor[4];
4117 if (!r_refdef.scene.numentities)
4120 switch (r_shadow_shadowmode)
4122 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4128 R_ResetViewRendering3D();
4129 R_Shadow_RenderMode_Begin();
4130 R_Shadow_RenderMode_ActiveLight(NULL);
4132 switch (r_shadow_shadowmode)
4134 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4135 if (!r_shadow_shadowmap2dtexture)
4136 R_Shadow_MakeShadowMap(0, r_shadow_shadowmapmaxsize);
4137 fbo = r_shadow_fbo2d;
4138 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
4139 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
4140 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
4146 size = 2*r_shadow_shadowmapmaxsize;
4147 scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
4148 radius = 0.5f / scale;
4149 nearclip = -r_shadows_throwdistance.value;
4150 farclip = r_shadows_throwdistance.value;
4151 bias = r_shadow_shadowmapping_bias.value * r_shadow_shadowmapping_nearclip.value / (2 * r_shadows_throwdistance.value) * (1024.0f / size);
4153 r_shadow_shadowmap_parameters[0] = size;
4154 r_shadow_shadowmap_parameters[1] = size;
4155 r_shadow_shadowmap_parameters[2] = 1.0;
4156 r_shadow_shadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
4158 Math_atov(r_shadows_throwdirection.string, shadowdir);
4159 VectorNormalize(shadowdir);
4160 Math_atov(r_shadows_focus.string, shadowfocus);
4161 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4162 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4163 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4164 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4165 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4166 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4167 if (fabs(dot1) <= fabs(dot2))
4168 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4170 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4171 VectorNormalize(shadowforward);
4172 VectorM(scale, shadowforward, &m[0]);
4173 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4175 m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
4176 CrossProduct(shadowdir, shadowforward, shadowright);
4177 VectorM(scale, shadowright, &m[4]);
4178 m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
4179 VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
4180 m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
4181 Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
4182 Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
4183 R_Viewport_InitOrtho(&viewport, &cameramatrix, 0, 0, size, size, 0, 0, 1, 1, 0, -1, NULL);
4185 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4187 R_Mesh_SetRenderTargets(fbo, r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
4188 R_SetupShader_DepthOrShadow();
4189 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
4192 R_SetViewport(&viewport);
4193 GL_Scissor(viewport.x, viewport.y, min(viewport.width + r_shadow_shadowmapborder, 2*r_shadow_shadowmapmaxsize), viewport.height + r_shadow_shadowmapborder);
4194 Vector4Set(clearcolor, 1,1,1,1);
4195 // in D3D9 we have to render to a color texture shadowmap
4196 // in GL we render directly to a depth texture only
4197 if (r_shadow_shadowmap2dtexture)
4198 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4200 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4201 // render into a slightly restricted region so that the borders of the
4202 // shadowmap area fade away, rather than streaking across everything
4203 // outside the usable area
4204 GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
4208 R_Mesh_ResetRenderTargets();
4209 R_SetupShader_ShowDepth();
4210 GL_ColorMask(1,1,1,1);
4211 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4214 for (i = 0;i < r_refdef.scene.numentities;i++)
4216 ent = r_refdef.scene.entities[i];
4218 // cast shadows from anything of the map (submodels are optional)
4219 if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4221 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4222 Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
4223 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4224 Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
4225 Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
4226 relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4227 relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4228 relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4229 relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4230 relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4231 relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4232 RSurf_ActiveModelEntity(ent, false, false, false);
4233 ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
4234 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4241 unsigned char *rawpixels = Z_Malloc(viewport.width*viewport.height*4);
4243 qglReadPixels(viewport.x, viewport.y, viewport.width, viewport.height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, rawpixels);
4245 Image_WriteTGABGRA("r_shadows_2.tga", viewport.width, viewport.height, rawpixels);
4246 Cvar_SetValueQuick(&r_test, 0);
4251 R_Shadow_RenderMode_End();
4253 Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
4254 Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
4255 Matrix4x4_CreateScale3(&scalematrix, size, -size, 1);
4256 Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
4257 Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
4258 Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
4260 switch (vid.renderpath)
4262 case RENDERPATH_GL11:
4263 case RENDERPATH_GL13:
4264 case RENDERPATH_GL20:
4265 case RENDERPATH_CGGL:
4267 case RENDERPATH_D3D9:
4268 case RENDERPATH_D3D10:
4269 case RENDERPATH_D3D11:
4270 #ifdef OPENGL_ORIENTATION
4271 r_shadow_shadowmapmatrix.m[0][0] *= -1.0f;
4272 r_shadow_shadowmapmatrix.m[0][1] *= -1.0f;
4273 r_shadow_shadowmapmatrix.m[0][2] *= -1.0f;
4274 r_shadow_shadowmapmatrix.m[0][3] *= -1.0f;
4276 r_shadow_shadowmapmatrix.m[0][0] *= -1.0f;
4277 r_shadow_shadowmapmatrix.m[1][0] *= -1.0f;
4278 r_shadow_shadowmapmatrix.m[2][0] *= -1.0f;
4279 r_shadow_shadowmapmatrix.m[3][0] *= -1.0f;
4284 r_shadow_usingshadowmaportho = true;
4285 switch (r_shadow_shadowmode)
4287 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4288 r_shadow_usingshadowmap2d = true;
4295 void R_DrawModelShadows(void)
4298 float relativethrowdistance;
4299 entity_render_t *ent;
4300 vec3_t relativelightorigin;
4301 vec3_t relativelightdirection;
4302 vec3_t relativeshadowmins, relativeshadowmaxs;
4303 vec3_t tmp, shadowdir;
4305 if (!r_refdef.scene.numentities || !vid.stencil || (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL && r_shadows.integer != 1))
4308 R_ResetViewRendering3D();
4309 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4310 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4311 R_Shadow_RenderMode_Begin();
4312 R_Shadow_RenderMode_ActiveLight(NULL);
4313 r_shadow_lightscissor[0] = r_refdef.view.x;
4314 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
4315 r_shadow_lightscissor[2] = r_refdef.view.width;
4316 r_shadow_lightscissor[3] = r_refdef.view.height;
4317 R_Shadow_RenderMode_StencilShadowVolumes(false);
4320 if (r_shadows.integer == 2)
4322 Math_atov(r_shadows_throwdirection.string, shadowdir);
4323 VectorNormalize(shadowdir);
4326 R_Shadow_ClearStencil();
4328 for (i = 0;i < r_refdef.scene.numentities;i++)
4330 ent = r_refdef.scene.entities[i];
4332 // cast shadows from anything of the map (submodels are optional)
4333 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4335 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4336 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
4337 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
4338 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
4339 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4342 if(ent->entitynumber != 0)
4344 if(ent->entitynumber >= MAX_EDICTS) // csqc entity
4346 // FIXME handle this
4347 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4351 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
4352 int entnum, entnum2, recursion;
4353 entnum = entnum2 = ent->entitynumber;
4354 for(recursion = 32; recursion > 0; --recursion)
4356 entnum2 = cl.entities[entnum].state_current.tagentity;
4357 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
4362 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
4364 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
4365 // transform into modelspace of OUR entity
4366 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
4367 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
4370 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4374 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4377 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
4378 RSurf_ActiveModelEntity(ent, false, false, false);
4379 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4380 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4384 // not really the right mode, but this will disable any silly stencil features
4385 R_Shadow_RenderMode_End();
4387 // set up ortho view for rendering this pass
4388 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4389 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4390 //GL_ScissorTest(true);
4391 //R_EntityMatrix(&identitymatrix);
4392 //R_Mesh_ResetTextureState();
4393 R_ResetViewRendering2D();
4395 // set up a darkening blend on shadowed areas
4396 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4397 //GL_DepthRange(0, 1);
4398 //GL_DepthTest(false);
4399 //GL_DepthMask(false);
4400 //GL_PolygonOffset(0, 0);CHECKGLERROR
4401 GL_Color(0, 0, 0, r_shadows_darken.value);
4402 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4403 //GL_DepthFunc(GL_ALWAYS);
4404 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_NOTEQUAL, 128, 255);
4406 // apply the blend to the shadowed areas
4407 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, NULL);
4408 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
4409 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4411 // restore the viewport
4412 R_SetViewport(&r_refdef.view.viewport);
4414 // restore other state to normal
4415 //R_Shadow_RenderMode_End();
4418 void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4421 vec3_t centerorigin;
4423 // if it's too close, skip it
4424 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
4426 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4429 if (usequery && r_numqueries + 2 <= r_maxqueries)
4431 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4432 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4433 // 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
4434 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4436 switch(vid.renderpath)
4438 case RENDERPATH_GL20:
4439 case RENDERPATH_GL13:
4440 case RENDERPATH_GL11:
4441 case RENDERPATH_CGGL:
4443 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use GL_DepthFunc instead
4444 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
4445 GL_DepthFunc(GL_ALWAYS);
4446 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4447 R_Mesh_PrepareVertices_Position_Arrays(4, vertex3f);
4448 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4449 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4450 GL_DepthFunc(GL_LEQUAL);
4451 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
4452 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4453 R_Mesh_PrepareVertices_Position_Arrays(4, vertex3f);
4454 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4455 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4458 case RENDERPATH_D3D9:
4459 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4461 case RENDERPATH_D3D10:
4462 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4464 case RENDERPATH_D3D11:
4465 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4469 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4472 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
4474 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4477 GLint allpixels = 0, visiblepixels = 0;
4478 // now we have to check the query result
4479 if (rtlight->corona_queryindex_visiblepixels)
4481 switch(vid.renderpath)
4483 case RENDERPATH_GL20:
4484 case RENDERPATH_GL13:
4485 case RENDERPATH_GL11:
4486 case RENDERPATH_CGGL:
4488 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
4489 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
4492 case RENDERPATH_D3D9:
4493 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4495 case RENDERPATH_D3D10:
4496 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4498 case RENDERPATH_D3D11:
4499 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4502 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
4503 if (visiblepixels < 1 || allpixels < 1)
4505 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
4506 cscale *= rtlight->corona_visibility;
4510 // FIXME: these traces should scan all render entities instead of cl.world
4511 if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
4514 VectorScale(rtlight->currentcolor, cscale, color);
4515 if (VectorLength(color) > (1.0f / 256.0f))
4518 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
4521 VectorNegate(color, color);
4522 switch(vid.renderpath)
4524 case RENDERPATH_GL11:
4525 case RENDERPATH_GL13:
4526 case RENDERPATH_GL20:
4527 case RENDERPATH_CGGL:
4528 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
4530 case RENDERPATH_D3D9:
4532 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_SUBTRACT);
4535 case RENDERPATH_D3D10:
4536 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4538 case RENDERPATH_D3D11:
4539 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4543 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4544 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);
4545 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4548 switch(vid.renderpath)
4550 case RENDERPATH_GL11:
4551 case RENDERPATH_GL13:
4552 case RENDERPATH_GL20:
4553 case RENDERPATH_CGGL:
4554 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
4556 case RENDERPATH_D3D9:
4558 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_ADD);
4561 case RENDERPATH_D3D10:
4562 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4564 case RENDERPATH_D3D11:
4565 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4572 void R_Shadow_DrawCoronas(void)
4575 qboolean usequery = false;
4580 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4582 if (r_waterstate.renderingscene)
4584 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4585 R_EntityMatrix(&identitymatrix);
4587 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4589 // check occlusion of coronas
4590 // use GL_ARB_occlusion_query if available
4591 // otherwise use raytraces
4593 switch (vid.renderpath)
4595 case RENDERPATH_GL11:
4596 case RENDERPATH_GL13:
4597 case RENDERPATH_GL20:
4598 case RENDERPATH_CGGL:
4599 usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
4602 GL_ColorMask(0,0,0,0);
4603 if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
4604 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
4607 r_maxqueries = (range + r_refdef.scene.numlights) * 4;
4608 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
4610 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
4613 RSurf_ActiveWorldEntity();
4614 GL_BlendFunc(GL_ONE, GL_ZERO);
4615 GL_CullFace(GL_NONE);
4616 GL_DepthMask(false);
4617 GL_DepthRange(0, 1);
4618 GL_PolygonOffset(0, 0);
4620 R_Mesh_ResetTextureState();
4621 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
4624 case RENDERPATH_D3D9:
4626 //Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4628 case RENDERPATH_D3D10:
4629 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4631 case RENDERPATH_D3D11:
4632 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4635 for (lightindex = 0;lightindex < range;lightindex++)
4637 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4640 rtlight = &light->rtlight;
4641 rtlight->corona_visibility = 0;
4642 rtlight->corona_queryindex_visiblepixels = 0;
4643 rtlight->corona_queryindex_allpixels = 0;
4644 if (!(rtlight->flags & flag))
4646 if (rtlight->corona <= 0)
4648 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4650 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4652 for (i = 0;i < r_refdef.scene.numlights;i++)
4654 rtlight = r_refdef.scene.lights[i];
4655 rtlight->corona_visibility = 0;
4656 rtlight->corona_queryindex_visiblepixels = 0;
4657 rtlight->corona_queryindex_allpixels = 0;
4658 if (!(rtlight->flags & flag))
4660 if (rtlight->corona <= 0)
4662 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4665 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4667 // now draw the coronas using the query data for intensity info
4668 for (lightindex = 0;lightindex < range;lightindex++)
4670 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4673 rtlight = &light->rtlight;
4674 if (rtlight->corona_visibility <= 0)
4676 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4678 for (i = 0;i < r_refdef.scene.numlights;i++)
4680 rtlight = r_refdef.scene.lights[i];
4681 if (rtlight->corona_visibility <= 0)
4683 if (gl_flashblend.integer)
4684 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4686 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4692 dlight_t *R_Shadow_NewWorldLight(void)
4694 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4697 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)
4700 // validate parameters
4701 if (style < 0 || style >= MAX_LIGHTSTYLES)
4703 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
4709 // copy to light properties
4710 VectorCopy(origin, light->origin);
4711 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4712 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4713 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4715 light->color[0] = max(color[0], 0);
4716 light->color[1] = max(color[1], 0);
4717 light->color[2] = max(color[2], 0);
4719 light->color[0] = color[0];
4720 light->color[1] = color[1];
4721 light->color[2] = color[2];
4722 light->radius = max(radius, 0);
4723 light->style = style;
4724 light->shadow = shadowenable;
4725 light->corona = corona;
4726 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4727 light->coronasizescale = coronasizescale;
4728 light->ambientscale = ambientscale;
4729 light->diffusescale = diffusescale;
4730 light->specularscale = specularscale;
4731 light->flags = flags;
4733 // update renderable light data
4734 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4735 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);
4738 void R_Shadow_FreeWorldLight(dlight_t *light)
4740 if (r_shadow_selectedlight == light)
4741 r_shadow_selectedlight = NULL;
4742 R_RTLight_Uncompile(&light->rtlight);
4743 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4746 void R_Shadow_ClearWorldLights(void)
4750 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4751 for (lightindex = 0;lightindex < range;lightindex++)
4753 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4755 R_Shadow_FreeWorldLight(light);
4757 r_shadow_selectedlight = NULL;
4760 void R_Shadow_SelectLight(dlight_t *light)
4762 if (r_shadow_selectedlight)
4763 r_shadow_selectedlight->selected = false;
4764 r_shadow_selectedlight = light;
4765 if (r_shadow_selectedlight)
4766 r_shadow_selectedlight->selected = true;
4769 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4771 // this is never batched (there can be only one)
4773 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
4774 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4775 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4778 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4783 skinframe_t *skinframe;
4786 // this is never batched (due to the ent parameter changing every time)
4787 // so numsurfaces == 1 and surfacelist[0] == lightnumber
4788 const dlight_t *light = (dlight_t *)ent;
4791 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
4794 VectorScale(light->color, intensity, spritecolor);
4795 if (VectorLength(spritecolor) < 0.1732f)
4796 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
4797 if (VectorLength(spritecolor) > 1.0f)
4798 VectorNormalize(spritecolor);
4800 // draw light sprite
4801 if (light->cubemapname[0] && !light->shadow)
4802 skinframe = r_editlights_sprcubemapnoshadowlight;
4803 else if (light->cubemapname[0])
4804 skinframe = r_editlights_sprcubemaplight;
4805 else if (!light->shadow)
4806 skinframe = r_editlights_sprnoshadowlight;
4808 skinframe = r_editlights_sprlight;
4810 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);
4811 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4813 // draw selection sprite if light is selected
4814 if (light->selected)
4816 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4817 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4818 // VorteX todo: add normalmode/realtime mode light overlay sprites?
4822 void R_Shadow_DrawLightSprites(void)
4826 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4827 for (lightindex = 0;lightindex < range;lightindex++)
4829 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4831 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
4833 if (!r_editlights_lockcursor)
4834 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
4837 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
4842 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
4843 if (lightindex >= range)
4845 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4848 rtlight = &light->rtlight;
4849 //if (!(rtlight->flags & flag))
4851 VectorCopy(rtlight->shadoworigin, origin);
4852 *radius = rtlight->radius;
4853 VectorCopy(rtlight->color, color);
4857 void R_Shadow_SelectLightInView(void)
4859 float bestrating, rating, temp[3];
4863 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4867 if (r_editlights_lockcursor)
4869 for (lightindex = 0;lightindex < range;lightindex++)
4871 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4874 VectorSubtract(light->origin, r_refdef.view.origin, temp);
4875 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
4878 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
4879 if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1.0f)
4881 bestrating = rating;
4886 R_Shadow_SelectLight(best);
4889 void R_Shadow_LoadWorldLights(void)
4891 int n, a, style, shadow, flags;
4892 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
4893 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
4894 if (cl.worldmodel == NULL)
4896 Con_Print("No map loaded.\n");
4899 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
4900 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4910 for (;COM_Parse(t, true) && strcmp(
4911 if (COM_Parse(t, true))
4913 if (com_token[0] == '!')
4916 origin[0] = atof(com_token+1);
4919 origin[0] = atof(com_token);
4924 while (*s && *s != '\n' && *s != '\r')
4930 // check for modifier flags
4937 #if _MSC_VER >= 1400
4938 #define sscanf sscanf_s
4940 cubemapname[sizeof(cubemapname)-1] = 0;
4941 #if MAX_QPATH != 128
4942 #error update this code if MAX_QPATH changes
4944 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
4945 #if _MSC_VER >= 1400
4946 , sizeof(cubemapname)
4948 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
4951 flags = LIGHTFLAG_REALTIMEMODE;
4959 coronasizescale = 0.25f;
4961 VectorClear(angles);
4964 if (a < 9 || !strcmp(cubemapname, "\"\""))
4966 // remove quotes on cubemapname
4967 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
4970 namelen = strlen(cubemapname) - 2;
4971 memmove(cubemapname, cubemapname + 1, namelen);
4972 cubemapname[namelen] = '\0';
4976 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);
4979 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4987 Con_Printf("invalid rtlights file \"%s\"\n", name);
4988 Mem_Free(lightsstring);
4992 void R_Shadow_SaveWorldLights(void)
4996 size_t bufchars, bufmaxchars;
4998 char name[MAX_QPATH];
4999 char line[MAX_INPUTLINE];
5000 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
5001 // I hate lines which are 3 times my screen size :( --blub
5004 if (cl.worldmodel == NULL)
5006 Con_Print("No map loaded.\n");
5009 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
5010 bufchars = bufmaxchars = 0;
5012 for (lightindex = 0;lightindex < range;lightindex++)
5014 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5017 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
5018 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);
5019 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
5020 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]);
5022 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);
5023 if (bufchars + strlen(line) > bufmaxchars)
5025 bufmaxchars = bufchars + strlen(line) + 2048;
5027 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
5031 memcpy(buf, oldbuf, bufchars);
5037 memcpy(buf + bufchars, line, strlen(line));
5038 bufchars += strlen(line);
5042 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
5047 void R_Shadow_LoadLightsFile(void)
5050 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
5051 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
5052 if (cl.worldmodel == NULL)
5054 Con_Print("No map loaded.\n");
5057 dpsnprintf(name, sizeof(name), "%s.lights", cl.worldnamenoextension);
5058 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5066 while (*s && *s != '\n' && *s != '\r')
5072 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);
5076 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);
5079 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
5080 radius = bound(15, radius, 4096);
5081 VectorScale(color, (2.0f / (8388608.0f)), color);
5082 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5090 Con_Printf("invalid lights file \"%s\"\n", name);
5091 Mem_Free(lightsstring);
5095 // tyrlite/hmap2 light types in the delay field
5096 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
5098 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
5110 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
5111 char key[256], value[MAX_INPUTLINE];
5113 if (cl.worldmodel == NULL)
5115 Con_Print("No map loaded.\n");
5118 // try to load a .ent file first
5119 dpsnprintf(key, sizeof(key), "%s.ent", cl.worldnamenoextension);
5120 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
5121 // and if that is not found, fall back to the bsp file entity string
5123 data = cl.worldmodel->brush.entities;
5126 for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
5128 type = LIGHTTYPE_MINUSX;
5129 origin[0] = origin[1] = origin[2] = 0;
5130 originhack[0] = originhack[1] = originhack[2] = 0;
5131 angles[0] = angles[1] = angles[2] = 0;
5132 color[0] = color[1] = color[2] = 1;
5133 light[0] = light[1] = light[2] = 1;light[3] = 300;
5134 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
5144 if (!COM_ParseToken_Simple(&data, false, false))
5146 if (com_token[0] == '}')
5147 break; // end of entity
5148 if (com_token[0] == '_')
5149 strlcpy(key, com_token + 1, sizeof(key));
5151 strlcpy(key, com_token, sizeof(key));
5152 while (key[strlen(key)-1] == ' ') // remove trailing spaces
5153 key[strlen(key)-1] = 0;
5154 if (!COM_ParseToken_Simple(&data, false, false))
5156 strlcpy(value, com_token, sizeof(value));
5158 // now that we have the key pair worked out...
5159 if (!strcmp("light", key))
5161 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5165 light[0] = vec[0] * (1.0f / 256.0f);
5166 light[1] = vec[0] * (1.0f / 256.0f);
5167 light[2] = vec[0] * (1.0f / 256.0f);
5173 light[0] = vec[0] * (1.0f / 255.0f);
5174 light[1] = vec[1] * (1.0f / 255.0f);
5175 light[2] = vec[2] * (1.0f / 255.0f);
5179 else if (!strcmp("delay", key))
5181 else if (!strcmp("origin", key))
5182 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5183 else if (!strcmp("angle", key))
5184 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5185 else if (!strcmp("angles", key))
5186 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5187 else if (!strcmp("color", key))
5188 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5189 else if (!strcmp("wait", key))
5190 fadescale = atof(value);
5191 else if (!strcmp("classname", key))
5193 if (!strncmp(value, "light", 5))
5196 if (!strcmp(value, "light_fluoro"))
5201 overridecolor[0] = 1;
5202 overridecolor[1] = 1;
5203 overridecolor[2] = 1;
5205 if (!strcmp(value, "light_fluorospark"))
5210 overridecolor[0] = 1;
5211 overridecolor[1] = 1;
5212 overridecolor[2] = 1;
5214 if (!strcmp(value, "light_globe"))
5219 overridecolor[0] = 1;
5220 overridecolor[1] = 0.8;
5221 overridecolor[2] = 0.4;
5223 if (!strcmp(value, "light_flame_large_yellow"))
5228 overridecolor[0] = 1;
5229 overridecolor[1] = 0.5;
5230 overridecolor[2] = 0.1;
5232 if (!strcmp(value, "light_flame_small_yellow"))
5237 overridecolor[0] = 1;
5238 overridecolor[1] = 0.5;
5239 overridecolor[2] = 0.1;
5241 if (!strcmp(value, "light_torch_small_white"))
5246 overridecolor[0] = 1;
5247 overridecolor[1] = 0.5;
5248 overridecolor[2] = 0.1;
5250 if (!strcmp(value, "light_torch_small_walltorch"))
5255 overridecolor[0] = 1;
5256 overridecolor[1] = 0.5;
5257 overridecolor[2] = 0.1;
5261 else if (!strcmp("style", key))
5262 style = atoi(value);
5263 else if (!strcmp("skin", key))
5264 skin = (int)atof(value);
5265 else if (!strcmp("pflags", key))
5266 pflags = (int)atof(value);
5267 //else if (!strcmp("effects", key))
5268 // effects = (int)atof(value);
5269 else if (cl.worldmodel->type == mod_brushq3)
5271 if (!strcmp("scale", key))
5272 lightscale = atof(value);
5273 if (!strcmp("fade", key))
5274 fadescale = atof(value);
5279 if (lightscale <= 0)
5283 if (color[0] == color[1] && color[0] == color[2])
5285 color[0] *= overridecolor[0];
5286 color[1] *= overridecolor[1];
5287 color[2] *= overridecolor[2];
5289 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5290 color[0] = color[0] * light[0];
5291 color[1] = color[1] * light[1];
5292 color[2] = color[2] * light[2];
5295 case LIGHTTYPE_MINUSX:
5297 case LIGHTTYPE_RECIPX:
5299 VectorScale(color, (1.0f / 16.0f), color);
5301 case LIGHTTYPE_RECIPXX:
5303 VectorScale(color, (1.0f / 16.0f), color);
5306 case LIGHTTYPE_NONE:
5310 case LIGHTTYPE_MINUSXX:
5313 VectorAdd(origin, originhack, origin);
5315 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);
5318 Mem_Free(entfiledata);
5322 void R_Shadow_SetCursorLocationForView(void)
5325 vec3_t dest, endpos;
5327 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5328 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
5329 if (trace.fraction < 1)
5331 dist = trace.fraction * r_editlights_cursordistance.value;
5332 push = r_editlights_cursorpushback.value;
5336 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5337 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5341 VectorClear( endpos );
5343 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5344 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5345 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5348 void R_Shadow_UpdateWorldLightSelection(void)
5350 if (r_editlights.integer)
5352 R_Shadow_SetCursorLocationForView();
5353 R_Shadow_SelectLightInView();
5356 R_Shadow_SelectLight(NULL);
5359 void R_Shadow_EditLights_Clear_f(void)
5361 R_Shadow_ClearWorldLights();
5364 void R_Shadow_EditLights_Reload_f(void)
5368 strlcpy(r_shadow_mapname, cl.worldname, sizeof(r_shadow_mapname));
5369 R_Shadow_ClearWorldLights();
5370 R_Shadow_LoadWorldLights();
5371 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5373 R_Shadow_LoadLightsFile();
5374 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5375 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5379 void R_Shadow_EditLights_Save_f(void)
5383 R_Shadow_SaveWorldLights();
5386 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
5388 R_Shadow_ClearWorldLights();
5389 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5392 void R_Shadow_EditLights_ImportLightsFile_f(void)
5394 R_Shadow_ClearWorldLights();
5395 R_Shadow_LoadLightsFile();
5398 void R_Shadow_EditLights_Spawn_f(void)
5401 if (!r_editlights.integer)
5403 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5406 if (Cmd_Argc() != 1)
5408 Con_Print("r_editlights_spawn does not take parameters\n");
5411 color[0] = color[1] = color[2] = 1;
5412 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5415 void R_Shadow_EditLights_Edit_f(void)
5417 vec3_t origin, angles, color;
5418 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5419 int style, shadows, flags, normalmode, realtimemode;
5420 char cubemapname[MAX_INPUTLINE];
5421 if (!r_editlights.integer)
5423 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5426 if (!r_shadow_selectedlight)
5428 Con_Print("No selected light.\n");
5431 VectorCopy(r_shadow_selectedlight->origin, origin);
5432 VectorCopy(r_shadow_selectedlight->angles, angles);
5433 VectorCopy(r_shadow_selectedlight->color, color);
5434 radius = r_shadow_selectedlight->radius;
5435 style = r_shadow_selectedlight->style;
5436 if (r_shadow_selectedlight->cubemapname)
5437 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5440 shadows = r_shadow_selectedlight->shadow;
5441 corona = r_shadow_selectedlight->corona;
5442 coronasizescale = r_shadow_selectedlight->coronasizescale;
5443 ambientscale = r_shadow_selectedlight->ambientscale;
5444 diffusescale = r_shadow_selectedlight->diffusescale;
5445 specularscale = r_shadow_selectedlight->specularscale;
5446 flags = r_shadow_selectedlight->flags;
5447 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5448 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5449 if (!strcmp(Cmd_Argv(1), "origin"))
5451 if (Cmd_Argc() != 5)
5453 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5456 origin[0] = atof(Cmd_Argv(2));
5457 origin[1] = atof(Cmd_Argv(3));
5458 origin[2] = atof(Cmd_Argv(4));
5460 else if (!strcmp(Cmd_Argv(1), "originx"))
5462 if (Cmd_Argc() != 3)
5464 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5467 origin[0] = atof(Cmd_Argv(2));
5469 else if (!strcmp(Cmd_Argv(1), "originy"))
5471 if (Cmd_Argc() != 3)
5473 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5476 origin[1] = atof(Cmd_Argv(2));
5478 else if (!strcmp(Cmd_Argv(1), "originz"))
5480 if (Cmd_Argc() != 3)
5482 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5485 origin[2] = atof(Cmd_Argv(2));
5487 else if (!strcmp(Cmd_Argv(1), "move"))
5489 if (Cmd_Argc() != 5)
5491 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5494 origin[0] += atof(Cmd_Argv(2));
5495 origin[1] += atof(Cmd_Argv(3));
5496 origin[2] += atof(Cmd_Argv(4));
5498 else if (!strcmp(Cmd_Argv(1), "movex"))
5500 if (Cmd_Argc() != 3)
5502 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5505 origin[0] += atof(Cmd_Argv(2));
5507 else if (!strcmp(Cmd_Argv(1), "movey"))
5509 if (Cmd_Argc() != 3)
5511 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5514 origin[1] += atof(Cmd_Argv(2));
5516 else if (!strcmp(Cmd_Argv(1), "movez"))
5518 if (Cmd_Argc() != 3)
5520 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5523 origin[2] += atof(Cmd_Argv(2));
5525 else if (!strcmp(Cmd_Argv(1), "angles"))
5527 if (Cmd_Argc() != 5)
5529 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5532 angles[0] = atof(Cmd_Argv(2));
5533 angles[1] = atof(Cmd_Argv(3));
5534 angles[2] = atof(Cmd_Argv(4));
5536 else if (!strcmp(Cmd_Argv(1), "anglesx"))
5538 if (Cmd_Argc() != 3)
5540 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5543 angles[0] = atof(Cmd_Argv(2));
5545 else if (!strcmp(Cmd_Argv(1), "anglesy"))
5547 if (Cmd_Argc() != 3)
5549 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5552 angles[1] = atof(Cmd_Argv(2));
5554 else if (!strcmp(Cmd_Argv(1), "anglesz"))
5556 if (Cmd_Argc() != 3)
5558 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5561 angles[2] = atof(Cmd_Argv(2));
5563 else if (!strcmp(Cmd_Argv(1), "color"))
5565 if (Cmd_Argc() != 5)
5567 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
5570 color[0] = atof(Cmd_Argv(2));
5571 color[1] = atof(Cmd_Argv(3));
5572 color[2] = atof(Cmd_Argv(4));
5574 else if (!strcmp(Cmd_Argv(1), "radius"))
5576 if (Cmd_Argc() != 3)
5578 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5581 radius = atof(Cmd_Argv(2));
5583 else if (!strcmp(Cmd_Argv(1), "colorscale"))
5585 if (Cmd_Argc() == 3)
5587 double scale = atof(Cmd_Argv(2));
5594 if (Cmd_Argc() != 5)
5596 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
5599 color[0] *= atof(Cmd_Argv(2));
5600 color[1] *= atof(Cmd_Argv(3));
5601 color[2] *= atof(Cmd_Argv(4));
5604 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
5606 if (Cmd_Argc() != 3)
5608 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5611 radius *= atof(Cmd_Argv(2));
5613 else if (!strcmp(Cmd_Argv(1), "style"))
5615 if (Cmd_Argc() != 3)
5617 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5620 style = atoi(Cmd_Argv(2));
5622 else if (!strcmp(Cmd_Argv(1), "cubemap"))
5626 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5629 if (Cmd_Argc() == 3)
5630 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
5634 else if (!strcmp(Cmd_Argv(1), "shadows"))
5636 if (Cmd_Argc() != 3)
5638 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5641 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5643 else if (!strcmp(Cmd_Argv(1), "corona"))
5645 if (Cmd_Argc() != 3)
5647 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5650 corona = atof(Cmd_Argv(2));
5652 else if (!strcmp(Cmd_Argv(1), "coronasize"))
5654 if (Cmd_Argc() != 3)
5656 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5659 coronasizescale = atof(Cmd_Argv(2));
5661 else if (!strcmp(Cmd_Argv(1), "ambient"))
5663 if (Cmd_Argc() != 3)
5665 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5668 ambientscale = atof(Cmd_Argv(2));
5670 else if (!strcmp(Cmd_Argv(1), "diffuse"))
5672 if (Cmd_Argc() != 3)
5674 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5677 diffusescale = atof(Cmd_Argv(2));
5679 else if (!strcmp(Cmd_Argv(1), "specular"))
5681 if (Cmd_Argc() != 3)
5683 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5686 specularscale = atof(Cmd_Argv(2));
5688 else if (!strcmp(Cmd_Argv(1), "normalmode"))
5690 if (Cmd_Argc() != 3)
5692 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5695 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5697 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
5699 if (Cmd_Argc() != 3)
5701 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5704 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5708 Con_Print("usage: r_editlights_edit [property] [value]\n");
5709 Con_Print("Selected light's properties:\n");
5710 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5711 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5712 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5713 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
5714 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
5715 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
5716 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5717 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
5718 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
5719 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
5720 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
5721 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
5722 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5723 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5726 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5727 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5730 void R_Shadow_EditLights_EditAll_f(void)
5733 dlight_t *light, *oldselected;
5736 if (!r_editlights.integer)
5738 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5742 oldselected = r_shadow_selectedlight;
5743 // EditLights doesn't seem to have a "remove" command or something so:
5744 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5745 for (lightindex = 0;lightindex < range;lightindex++)
5747 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5750 R_Shadow_SelectLight(light);
5751 R_Shadow_EditLights_Edit_f();
5753 // return to old selected (to not mess editing once selection is locked)
5754 R_Shadow_SelectLight(oldselected);
5757 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
5759 int lightnumber, lightcount;
5760 size_t lightindex, range;
5764 if (!r_editlights.integer)
5766 x = vid_conwidth.value - 240;
5768 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
5771 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5772 for (lightindex = 0;lightindex < range;lightindex++)
5774 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5777 if (light == r_shadow_selectedlight)
5778 lightnumber = lightindex;
5781 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;
5782 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;
5784 if (r_shadow_selectedlight == NULL)
5786 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;
5787 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;
5788 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;
5789 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;
5790 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;
5791 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;
5792 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;
5793 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;
5794 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;
5795 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;
5796 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;
5797 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;
5798 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;
5799 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;
5800 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;
5803 void R_Shadow_EditLights_ToggleShadow_f(void)
5805 if (!r_editlights.integer)
5807 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5810 if (!r_shadow_selectedlight)
5812 Con_Print("No selected light.\n");
5815 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);
5818 void R_Shadow_EditLights_ToggleCorona_f(void)
5820 if (!r_editlights.integer)
5822 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5825 if (!r_shadow_selectedlight)
5827 Con_Print("No selected light.\n");
5830 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);
5833 void R_Shadow_EditLights_Remove_f(void)
5835 if (!r_editlights.integer)
5837 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
5840 if (!r_shadow_selectedlight)
5842 Con_Print("No selected light.\n");
5845 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
5846 r_shadow_selectedlight = NULL;
5849 void R_Shadow_EditLights_Help_f(void)
5852 "Documentation on r_editlights system:\n"
5854 "r_editlights : enable/disable editing mode\n"
5855 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
5856 "r_editlights_cursorpushback : push back cursor this far from surface\n"
5857 "r_editlights_cursorpushoff : push cursor off surface this far\n"
5858 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
5859 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
5861 "r_editlights_help : this help\n"
5862 "r_editlights_clear : remove all lights\n"
5863 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
5864 "r_editlights_lock : lock selection to current light, if already locked - unlock\n"
5865 "r_editlights_save : save to .rtlights file\n"
5866 "r_editlights_spawn : create a light with default settings\n"
5867 "r_editlights_edit command : edit selected light - more documentation below\n"
5868 "r_editlights_remove : remove selected light\n"
5869 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
5870 "r_editlights_importlightentitiesfrommap : reload light entities\n"
5871 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
5873 "origin x y z : set light location\n"
5874 "originx x: set x component of light location\n"
5875 "originy y: set y component of light location\n"
5876 "originz z: set z component of light location\n"
5877 "move x y z : adjust light location\n"
5878 "movex x: adjust x component of light location\n"
5879 "movey y: adjust y component of light location\n"
5880 "movez z: adjust z component of light location\n"
5881 "angles x y z : set light angles\n"
5882 "anglesx x: set x component of light angles\n"
5883 "anglesy y: set y component of light angles\n"
5884 "anglesz z: set z component of light angles\n"
5885 "color r g b : set color of light (can be brighter than 1 1 1)\n"
5886 "radius radius : set radius (size) of light\n"
5887 "colorscale grey : multiply color of light (1 does nothing)\n"
5888 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
5889 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
5890 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
5891 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
5892 "cubemap basename : set filter cubemap of light (not yet supported)\n"
5893 "shadows 1/0 : turn on/off shadows\n"
5894 "corona n : set corona intensity\n"
5895 "coronasize n : set corona size (0-1)\n"
5896 "ambient n : set ambient intensity (0-1)\n"
5897 "diffuse n : set diffuse intensity (0-1)\n"
5898 "specular n : set specular intensity (0-1)\n"
5899 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
5900 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
5901 "<nothing> : print light properties to console\n"
5905 void R_Shadow_EditLights_CopyInfo_f(void)
5907 if (!r_editlights.integer)
5909 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
5912 if (!r_shadow_selectedlight)
5914 Con_Print("No selected light.\n");
5917 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
5918 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
5919 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
5920 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
5921 if (r_shadow_selectedlight->cubemapname)
5922 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
5924 r_shadow_bufferlight.cubemapname[0] = 0;
5925 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
5926 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
5927 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
5928 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
5929 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
5930 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
5931 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
5934 void R_Shadow_EditLights_PasteInfo_f(void)
5936 if (!r_editlights.integer)
5938 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
5941 if (!r_shadow_selectedlight)
5943 Con_Print("No selected light.\n");
5946 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);
5949 void R_Shadow_EditLights_Lock_f(void)
5951 if (!r_editlights.integer)
5953 Con_Print("Cannot lock on light when not in editing mode. Set r_editlights to 1.\n");
5956 if (r_editlights_lockcursor)
5958 r_editlights_lockcursor = false;
5961 if (!r_shadow_selectedlight)
5963 Con_Print("No selected light to lock on.\n");
5966 r_editlights_lockcursor = true;
5969 void R_Shadow_EditLights_Init(void)
5971 Cvar_RegisterVariable(&r_editlights);
5972 Cvar_RegisterVariable(&r_editlights_cursordistance);
5973 Cvar_RegisterVariable(&r_editlights_cursorpushback);
5974 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
5975 Cvar_RegisterVariable(&r_editlights_cursorgrid);
5976 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
5977 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
5978 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
5979 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)");
5980 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
5981 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
5982 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
5983 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)");
5984 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
5985 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
5986 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
5987 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
5988 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
5989 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
5990 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)");
5991 Cmd_AddCommand("r_editlights_lock", R_Shadow_EditLights_Lock_f, "lock selection to current light, if already locked - unlock");
5997 =============================================================================
6001 =============================================================================
6004 void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, qboolean dynamic, qboolean rtworld)
6006 VectorClear(diffusecolor);
6007 VectorClear(diffusenormal);
6009 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
6011 ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_refdef.scene.ambient;
6012 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
6015 VectorSet(ambientcolor, 1, 1, 1);
6019 int i, numlights, flag;
6027 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
6028 numlights = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
6029 for (i = 0; i < numlights; i++)
6031 dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
6034 light = &dlight->rtlight;
6035 if (!(light->flags & flag))
6037 Matrix4x4_Transform(&light->matrix_worldtolight, p, v);
6038 f = 1 - VectorLength2(v);
6041 if (!light->shadow || CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
6042 VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);
6047 for (i = 0;i < r_refdef.scene.numlights;i++)
6049 light = r_refdef.scene.lights[i];
6050 Matrix4x4_Transform(&light->matrix_worldtolight, p, v);
6051 f = (1 - VectorLength2(v)) * r_refdef.scene.rtlightstylevalue[light->style];
6054 if (!light->shadow || CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
6055 VectorMA(ambientcolor, f, light->color, ambientcolor);