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,
167 R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE,
168 R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE,
170 r_shadow_rendermode_t;
172 typedef enum r_shadow_shadowmode_e
174 R_SHADOW_SHADOWMODE_STENCIL,
175 R_SHADOW_SHADOWMODE_SHADOWMAP2D,
176 R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE,
177 R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE
179 r_shadow_shadowmode_t;
181 r_shadow_rendermode_t r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
182 r_shadow_rendermode_t r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_NONE;
183 r_shadow_rendermode_t r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_NONE;
184 r_shadow_rendermode_t r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_NONE;
185 qboolean r_shadow_usingshadowmaprect;
186 qboolean r_shadow_usingshadowmap2d;
187 qboolean r_shadow_usingshadowmapcube;
188 qboolean r_shadow_usingshadowmaportho;
189 int r_shadow_shadowmapside;
190 float r_shadow_shadowmap_texturescale[2];
191 float r_shadow_shadowmap_parameters[4];
193 int r_shadow_drawbuffer;
194 int r_shadow_readbuffer;
196 int r_shadow_cullface_front, r_shadow_cullface_back;
197 GLuint r_shadow_fborectangle;
198 GLuint r_shadow_fbocubeside[R_SHADOW_SHADOWMAP_NUMCUBEMAPS];
199 GLuint r_shadow_fbo2d;
200 r_shadow_shadowmode_t r_shadow_shadowmode;
201 int r_shadow_shadowmapfilterquality;
202 int r_shadow_shadowmaptexturetype;
203 int r_shadow_shadowmapdepthbits;
204 int r_shadow_shadowmapmaxsize;
205 qboolean r_shadow_shadowmapvsdct;
206 qboolean r_shadow_shadowmapsampler;
207 int r_shadow_shadowmappcf;
208 int r_shadow_shadowmapborder;
209 matrix4x4_t r_shadow_shadowmapmatrix;
210 int r_shadow_lightscissor[4];
211 qboolean r_shadow_usingdeferredprepass;
213 int maxshadowtriangles;
216 int maxshadowvertices;
217 float *shadowvertex3f;
227 unsigned char *shadowsides;
228 int *shadowsideslist;
235 int r_shadow_buffer_numleafpvsbytes;
236 unsigned char *r_shadow_buffer_visitingleafpvs;
237 unsigned char *r_shadow_buffer_leafpvs;
238 int *r_shadow_buffer_leaflist;
240 int r_shadow_buffer_numsurfacepvsbytes;
241 unsigned char *r_shadow_buffer_surfacepvs;
242 int *r_shadow_buffer_surfacelist;
243 unsigned char *r_shadow_buffer_surfacesides;
245 int r_shadow_buffer_numshadowtrispvsbytes;
246 unsigned char *r_shadow_buffer_shadowtrispvs;
247 int r_shadow_buffer_numlighttrispvsbytes;
248 unsigned char *r_shadow_buffer_lighttrispvs;
250 rtexturepool_t *r_shadow_texturepool;
251 rtexture_t *r_shadow_attenuationgradienttexture;
252 rtexture_t *r_shadow_attenuation2dtexture;
253 rtexture_t *r_shadow_attenuation3dtexture;
254 skinframe_t *r_shadow_lightcorona;
255 rtexture_t *r_shadow_shadowmaprectangletexture;
256 rtexture_t *r_shadow_shadowmap2dtexture;
257 rtexture_t *r_shadow_shadowmapcubetexture[R_SHADOW_SHADOWMAP_NUMCUBEMAPS];
258 rtexture_t *r_shadow_shadowmap2dcolortexture;
259 rtexture_t *r_shadow_shadowmapvsdcttexture;
260 int r_shadow_shadowmapsize; // changes for each light based on distance
261 int r_shadow_shadowmaplod; // changes for each light based on distance
263 GLuint r_shadow_prepassgeometryfbo;
264 GLuint r_shadow_prepasslightingfbo;
265 int r_shadow_prepass_width;
266 int r_shadow_prepass_height;
267 rtexture_t *r_shadow_prepassgeometrydepthtexture;
268 rtexture_t *r_shadow_prepassgeometrynormalmaptexture;
269 rtexture_t *r_shadow_prepasslightingdiffusetexture;
270 rtexture_t *r_shadow_prepasslightingspeculartexture;
272 // lights are reloaded when this changes
273 char r_shadow_mapname[MAX_QPATH];
275 // used only for light filters (cubemaps)
276 rtexturepool_t *r_shadow_filters_texturepool;
278 static const GLenum r_shadow_prepasslightingdrawbuffers[2] = {GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT};
280 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"};
281 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"};
282 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
283 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"};
284 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)"};
285 //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"};
286 cvar_t r_shadow_usenormalmap = {CVAR_SAVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"};
287 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)"};
288 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"};
289 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
290 cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
291 cvar_t r_shadow_gloss2exponent = {0, "r_shadow_gloss2exponent", "32", "same as r_shadow_glossexponent but for forced gloss (gloss 2) surfaces"};
292 cvar_t r_shadow_glossexact = {0, "r_shadow_glossexact", "0", "use exact reflection math for gloss (slightly slower, but should look a tad better)"};
293 cvar_t r_shadow_lightattenuationdividebias = {0, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"};
294 cvar_t r_shadow_lightattenuationlinearscale = {0, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"};
295 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
296 cvar_t r_shadow_lightradiusscale = {0, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
297 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "0", "how far to cast shadows"};
298 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)"};
299 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
300 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
301 cvar_t r_shadow_realtime_dlight_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
302 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
303 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)"};
304 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"};
305 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
306 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
307 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"};
308 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)"};
309 cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "0", "enables portal-based culling optimization during compilation (overrides compilesvbsp)"};
310 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)"};
311 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"};
312 cvar_t r_shadow_shadowmapping_texturetype = {CVAR_SAVE, "r_shadow_shadowmapping_texturetype", "-1", "shadowmap texture types: -1 = auto-select, 0 = 2D, 1 = rectangle, 2 = cubemap"};
313 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)"};
314 cvar_t r_shadow_shadowmapping_depthbits = {CVAR_SAVE, "r_shadow_shadowmapping_depthbits", "24", "requested minimum shadowmap texture depth bits"};
315 cvar_t r_shadow_shadowmapping_vsdct = {CVAR_SAVE, "r_shadow_shadowmapping_vsdct", "1", "enables use of virtual shadow depth cube texture"};
316 cvar_t r_shadow_shadowmapping_minsize = {CVAR_SAVE, "r_shadow_shadowmapping_minsize", "32", "shadowmap size limit"};
317 cvar_t r_shadow_shadowmapping_maxsize = {CVAR_SAVE, "r_shadow_shadowmapping_maxsize", "512", "shadowmap size limit"};
318 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"};
319 //cvar_t r_shadow_shadowmapping_lod_bias = {CVAR_SAVE, "r_shadow_shadowmapping_lod_bias", "16", "shadowmap size bias"};
320 //cvar_t r_shadow_shadowmapping_lod_scale = {CVAR_SAVE, "r_shadow_shadowmapping_lod_scale", "128", "shadowmap size scaling parameter"};
321 cvar_t r_shadow_shadowmapping_bordersize = {CVAR_SAVE, "r_shadow_shadowmapping_bordersize", "4", "shadowmap size bias for filtering"};
322 cvar_t r_shadow_shadowmapping_nearclip = {CVAR_SAVE, "r_shadow_shadowmapping_nearclip", "1", "shadowmap nearclip in world units"};
323 cvar_t r_shadow_shadowmapping_bias = {CVAR_SAVE, "r_shadow_shadowmapping_bias", "0.03", "shadowmap bias parameter (this is multiplied by nearclip * 1024 / lodsize)"};
324 cvar_t r_shadow_shadowmapping_polygonfactor = {CVAR_SAVE, "r_shadow_shadowmapping_polygonfactor", "2", "slope-dependent shadowmapping bias"};
325 cvar_t r_shadow_shadowmapping_polygonoffset = {CVAR_SAVE, "r_shadow_shadowmapping_polygonoffset", "0", "constant shadowmapping bias"};
326 cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
327 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)"};
328 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)"};
329 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "1", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
330 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"};
331 cvar_t r_coronas_occlusionquery = {CVAR_SAVE, "r_coronas_occlusionquery", "1", "use GL_ARB_occlusion_query extension if supported (fades coronas according to visibility)"};
332 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
333 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
334 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
335 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
336 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
337 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
338 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
339 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
340 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
342 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
343 #define ATTENTABLESIZE 256
344 // 1D gradient, 2D circle and 3D sphere attenuation textures
345 #define ATTEN1DSIZE 32
346 #define ATTEN2DSIZE 64
347 #define ATTEN3DSIZE 32
349 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
350 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
351 static float r_shadow_attentable[ATTENTABLESIZE+1];
353 rtlight_t *r_shadow_compilingrtlight;
354 static memexpandablearray_t r_shadow_worldlightsarray;
355 dlight_t *r_shadow_selectedlight;
356 dlight_t r_shadow_bufferlight;
357 vec3_t r_editlights_cursorlocation;
358 qboolean r_editlights_lockcursor;
360 extern int con_vislines;
362 void R_Shadow_UncompileWorldLights(void);
363 void R_Shadow_ClearWorldLights(void);
364 void R_Shadow_SaveWorldLights(void);
365 void R_Shadow_LoadWorldLights(void);
366 void R_Shadow_LoadLightsFile(void);
367 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
368 void R_Shadow_EditLights_Reload_f(void);
369 void R_Shadow_ValidateCvars(void);
370 static void R_Shadow_MakeTextures(void);
372 #define EDLIGHTSPRSIZE 8
373 skinframe_t *r_editlights_sprcursor;
374 skinframe_t *r_editlights_sprlight;
375 skinframe_t *r_editlights_sprnoshadowlight;
376 skinframe_t *r_editlights_sprcubemaplight;
377 skinframe_t *r_editlights_sprcubemapnoshadowlight;
378 skinframe_t *r_editlights_sprselection;
380 void R_Shadow_SetShadowMode(void)
382 r_shadow_shadowmapmaxsize = bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4);
383 r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer != 0;
384 r_shadow_shadowmapfilterquality = r_shadow_shadowmapping_filterquality.integer;
385 r_shadow_shadowmaptexturetype = r_shadow_shadowmapping_texturetype.integer;
386 r_shadow_shadowmapdepthbits = r_shadow_shadowmapping_depthbits.integer;
387 r_shadow_shadowmapborder = bound(0, r_shadow_shadowmapping_bordersize.integer, 16);
388 r_shadow_shadowmaplod = -1;
389 r_shadow_shadowmapsize = 0;
390 r_shadow_shadowmapsampler = false;
391 r_shadow_shadowmappcf = 0;
392 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
393 if ((r_shadow_shadowmapping.integer || r_shadow_deferred.integer) && vid.support.ext_framebuffer_object)
395 switch(vid.renderpath)
397 case RENDERPATH_GL20:
398 if(r_shadow_shadowmapfilterquality < 0)
400 if(vid.support.amd_texture_texture4 || vid.support.arb_texture_gather)
401 r_shadow_shadowmappcf = 1;
402 else if(strstr(gl_vendor, "NVIDIA") || strstr(gl_renderer, "Radeon HD"))
404 r_shadow_shadowmapsampler = vid.support.arb_shadow;
405 r_shadow_shadowmappcf = 1;
407 else if(strstr(gl_vendor, "ATI"))
408 r_shadow_shadowmappcf = 1;
410 r_shadow_shadowmapsampler = vid.support.arb_shadow;
414 switch (r_shadow_shadowmapfilterquality)
417 r_shadow_shadowmapsampler = vid.support.arb_shadow;
420 r_shadow_shadowmapsampler = vid.support.arb_shadow;
421 r_shadow_shadowmappcf = 1;
424 r_shadow_shadowmappcf = 1;
427 r_shadow_shadowmappcf = 2;
431 switch (r_shadow_shadowmaptexturetype)
434 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
437 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE;
440 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE;
443 if((vid.support.amd_texture_texture4 || vid.support.arb_texture_gather) && r_shadow_shadowmappcf && !r_shadow_shadowmapsampler)
444 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
445 else if(vid.support.arb_texture_rectangle)
446 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE;
448 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
451 // Cg has very little choice in depth texture sampling
454 r_shadow_shadowmapsampler = false;
455 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
458 case RENDERPATH_CGGL:
459 case RENDERPATH_D3D9:
460 case RENDERPATH_D3D10:
461 case RENDERPATH_D3D11:
462 r_shadow_shadowmapsampler = false;
463 r_shadow_shadowmappcf = 1;
464 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
466 case RENDERPATH_GL13:
468 case RENDERPATH_GL11:
474 qboolean R_Shadow_ShadowMappingEnabled(void)
476 switch (r_shadow_shadowmode)
478 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
479 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
480 case R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE:
487 void R_Shadow_FreeShadowMaps(void)
491 R_Shadow_SetShadowMode();
493 R_Mesh_DestroyFramebufferObject(r_shadow_fborectangle);
495 R_Mesh_DestroyFramebufferObject(r_shadow_fbo2d);
496 for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
497 R_Mesh_DestroyFramebufferObject(r_shadow_fbocubeside[i]);
499 r_shadow_fborectangle = 0;
501 memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
503 if (r_shadow_shadowmaprectangletexture)
504 R_FreeTexture(r_shadow_shadowmaprectangletexture);
505 r_shadow_shadowmaprectangletexture = NULL;
507 if (r_shadow_shadowmap2dtexture)
508 R_FreeTexture(r_shadow_shadowmap2dtexture);
509 r_shadow_shadowmap2dtexture = NULL;
511 for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
512 if (r_shadow_shadowmapcubetexture[i])
513 R_FreeTexture(r_shadow_shadowmapcubetexture[i]);
514 memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
516 if (r_shadow_shadowmap2dcolortexture)
517 R_FreeTexture(r_shadow_shadowmap2dcolortexture);
518 r_shadow_shadowmap2dcolortexture = NULL;
520 if (r_shadow_shadowmapvsdcttexture)
521 R_FreeTexture(r_shadow_shadowmapvsdcttexture);
522 r_shadow_shadowmapvsdcttexture = NULL;
525 void r_shadow_start(void)
527 // allocate vertex processing arrays
528 r_shadow_attenuationgradienttexture = NULL;
529 r_shadow_attenuation2dtexture = NULL;
530 r_shadow_attenuation3dtexture = NULL;
531 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
532 r_shadow_shadowmaprectangletexture = NULL;
533 r_shadow_shadowmap2dtexture = NULL;
534 memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
535 r_shadow_shadowmap2dcolortexture = NULL;
536 r_shadow_shadowmapvsdcttexture = NULL;
537 r_shadow_shadowmapmaxsize = 0;
538 r_shadow_shadowmapsize = 0;
539 r_shadow_shadowmaplod = 0;
540 r_shadow_shadowmapfilterquality = -1;
541 r_shadow_shadowmaptexturetype = -1;
542 r_shadow_shadowmapdepthbits = 0;
543 r_shadow_shadowmapvsdct = false;
544 r_shadow_shadowmapsampler = false;
545 r_shadow_shadowmappcf = 0;
546 r_shadow_fborectangle = 0;
548 memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
550 R_Shadow_FreeShadowMaps();
552 r_shadow_texturepool = NULL;
553 r_shadow_filters_texturepool = NULL;
554 R_Shadow_ValidateCvars();
555 R_Shadow_MakeTextures();
556 maxshadowtriangles = 0;
557 shadowelements = NULL;
558 maxshadowvertices = 0;
559 shadowvertex3f = NULL;
567 shadowmarklist = NULL;
572 shadowsideslist = NULL;
573 r_shadow_buffer_numleafpvsbytes = 0;
574 r_shadow_buffer_visitingleafpvs = NULL;
575 r_shadow_buffer_leafpvs = NULL;
576 r_shadow_buffer_leaflist = NULL;
577 r_shadow_buffer_numsurfacepvsbytes = 0;
578 r_shadow_buffer_surfacepvs = NULL;
579 r_shadow_buffer_surfacelist = NULL;
580 r_shadow_buffer_surfacesides = NULL;
581 r_shadow_buffer_numshadowtrispvsbytes = 0;
582 r_shadow_buffer_shadowtrispvs = NULL;
583 r_shadow_buffer_numlighttrispvsbytes = 0;
584 r_shadow_buffer_lighttrispvs = NULL;
586 r_shadow_usingdeferredprepass = false;
587 r_shadow_prepass_width = r_shadow_prepass_height = 0;
590 static void R_Shadow_FreeDeferred(void);
591 void r_shadow_shutdown(void)
594 R_Shadow_UncompileWorldLights();
596 R_Shadow_FreeShadowMaps();
598 r_shadow_usingdeferredprepass = false;
599 if (r_shadow_prepass_width)
600 R_Shadow_FreeDeferred();
601 r_shadow_prepass_width = r_shadow_prepass_height = 0;
604 r_shadow_attenuationgradienttexture = NULL;
605 r_shadow_attenuation2dtexture = NULL;
606 r_shadow_attenuation3dtexture = NULL;
607 R_FreeTexturePool(&r_shadow_texturepool);
608 R_FreeTexturePool(&r_shadow_filters_texturepool);
609 maxshadowtriangles = 0;
611 Mem_Free(shadowelements);
612 shadowelements = NULL;
614 Mem_Free(shadowvertex3f);
615 shadowvertex3f = NULL;
618 Mem_Free(vertexupdate);
621 Mem_Free(vertexremap);
627 Mem_Free(shadowmark);
630 Mem_Free(shadowmarklist);
631 shadowmarklist = NULL;
636 Mem_Free(shadowsides);
639 Mem_Free(shadowsideslist);
640 shadowsideslist = NULL;
641 r_shadow_buffer_numleafpvsbytes = 0;
642 if (r_shadow_buffer_visitingleafpvs)
643 Mem_Free(r_shadow_buffer_visitingleafpvs);
644 r_shadow_buffer_visitingleafpvs = NULL;
645 if (r_shadow_buffer_leafpvs)
646 Mem_Free(r_shadow_buffer_leafpvs);
647 r_shadow_buffer_leafpvs = NULL;
648 if (r_shadow_buffer_leaflist)
649 Mem_Free(r_shadow_buffer_leaflist);
650 r_shadow_buffer_leaflist = NULL;
651 r_shadow_buffer_numsurfacepvsbytes = 0;
652 if (r_shadow_buffer_surfacepvs)
653 Mem_Free(r_shadow_buffer_surfacepvs);
654 r_shadow_buffer_surfacepvs = NULL;
655 if (r_shadow_buffer_surfacelist)
656 Mem_Free(r_shadow_buffer_surfacelist);
657 r_shadow_buffer_surfacelist = NULL;
658 if (r_shadow_buffer_surfacesides)
659 Mem_Free(r_shadow_buffer_surfacesides);
660 r_shadow_buffer_surfacesides = NULL;
661 r_shadow_buffer_numshadowtrispvsbytes = 0;
662 if (r_shadow_buffer_shadowtrispvs)
663 Mem_Free(r_shadow_buffer_shadowtrispvs);
664 r_shadow_buffer_numlighttrispvsbytes = 0;
665 if (r_shadow_buffer_lighttrispvs)
666 Mem_Free(r_shadow_buffer_lighttrispvs);
669 void r_shadow_newmap(void)
671 if (r_shadow_lightcorona) R_SkinFrame_MarkUsed(r_shadow_lightcorona);
672 if (r_editlights_sprcursor) R_SkinFrame_MarkUsed(r_editlights_sprcursor);
673 if (r_editlights_sprlight) R_SkinFrame_MarkUsed(r_editlights_sprlight);
674 if (r_editlights_sprnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprnoshadowlight);
675 if (r_editlights_sprcubemaplight) R_SkinFrame_MarkUsed(r_editlights_sprcubemaplight);
676 if (r_editlights_sprcubemapnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprcubemapnoshadowlight);
677 if (r_editlights_sprselection) R_SkinFrame_MarkUsed(r_editlights_sprselection);
678 if (strncmp(cl.worldname, r_shadow_mapname, sizeof(r_shadow_mapname)))
679 R_Shadow_EditLights_Reload_f();
682 void R_Shadow_Init(void)
684 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
685 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
686 Cvar_RegisterVariable(&r_shadow_usenormalmap);
687 Cvar_RegisterVariable(&r_shadow_debuglight);
688 Cvar_RegisterVariable(&r_shadow_deferred);
689 Cvar_RegisterVariable(&r_shadow_deferred_8bitrange);
690 // Cvar_RegisterVariable(&r_shadow_deferred_fp);
691 Cvar_RegisterVariable(&r_shadow_gloss);
692 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
693 Cvar_RegisterVariable(&r_shadow_glossintensity);
694 Cvar_RegisterVariable(&r_shadow_glossexponent);
695 Cvar_RegisterVariable(&r_shadow_gloss2exponent);
696 Cvar_RegisterVariable(&r_shadow_glossexact);
697 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
698 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
699 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
700 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
701 Cvar_RegisterVariable(&r_shadow_projectdistance);
702 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
703 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
704 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
705 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
706 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
707 Cvar_RegisterVariable(&r_shadow_realtime_world);
708 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
709 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
710 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
711 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
712 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
713 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
714 Cvar_RegisterVariable(&r_shadow_scissor);
715 Cvar_RegisterVariable(&r_shadow_shadowmapping);
716 Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
717 Cvar_RegisterVariable(&r_shadow_shadowmapping_texturetype);
718 Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
719 Cvar_RegisterVariable(&r_shadow_shadowmapping_depthbits);
720 Cvar_RegisterVariable(&r_shadow_shadowmapping_precision);
721 Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
722 Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
723 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
724 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
725 Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
726 Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
727 Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
728 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonfactor);
729 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonoffset);
730 Cvar_RegisterVariable(&r_shadow_polygonfactor);
731 Cvar_RegisterVariable(&r_shadow_polygonoffset);
732 Cvar_RegisterVariable(&r_shadow_texture3d);
733 Cvar_RegisterVariable(&r_coronas);
734 Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
735 Cvar_RegisterVariable(&r_coronas_occlusionquery);
736 Cvar_RegisterVariable(&gl_flashblend);
737 Cvar_RegisterVariable(&gl_ext_separatestencil);
738 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
739 if (gamemode == GAME_TENEBRAE)
741 Cvar_SetValue("r_shadow_gloss", 2);
742 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
744 R_Shadow_EditLights_Init();
745 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
746 maxshadowtriangles = 0;
747 shadowelements = NULL;
748 maxshadowvertices = 0;
749 shadowvertex3f = NULL;
757 shadowmarklist = NULL;
762 shadowsideslist = NULL;
763 r_shadow_buffer_numleafpvsbytes = 0;
764 r_shadow_buffer_visitingleafpvs = NULL;
765 r_shadow_buffer_leafpvs = NULL;
766 r_shadow_buffer_leaflist = NULL;
767 r_shadow_buffer_numsurfacepvsbytes = 0;
768 r_shadow_buffer_surfacepvs = NULL;
769 r_shadow_buffer_surfacelist = NULL;
770 r_shadow_buffer_surfacesides = NULL;
771 r_shadow_buffer_shadowtrispvs = NULL;
772 r_shadow_buffer_lighttrispvs = NULL;
773 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap, NULL, NULL);
776 matrix4x4_t matrix_attenuationxyz =
779 {0.5, 0.0, 0.0, 0.5},
780 {0.0, 0.5, 0.0, 0.5},
781 {0.0, 0.0, 0.5, 0.5},
786 matrix4x4_t matrix_attenuationz =
789 {0.0, 0.0, 0.5, 0.5},
790 {0.0, 0.0, 0.0, 0.5},
791 {0.0, 0.0, 0.0, 0.5},
796 void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles, int vertscale, int triscale)
798 numvertices = ((numvertices + 255) & ~255) * vertscale;
799 numtriangles = ((numtriangles + 255) & ~255) * triscale;
800 // make sure shadowelements is big enough for this volume
801 if (maxshadowtriangles < numtriangles)
803 maxshadowtriangles = numtriangles;
805 Mem_Free(shadowelements);
806 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[3]));
808 // make sure shadowvertex3f is big enough for this volume
809 if (maxshadowvertices < numvertices)
811 maxshadowvertices = numvertices;
813 Mem_Free(shadowvertex3f);
814 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[3]));
818 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
820 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
821 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
822 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
823 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
824 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
826 if (r_shadow_buffer_visitingleafpvs)
827 Mem_Free(r_shadow_buffer_visitingleafpvs);
828 if (r_shadow_buffer_leafpvs)
829 Mem_Free(r_shadow_buffer_leafpvs);
830 if (r_shadow_buffer_leaflist)
831 Mem_Free(r_shadow_buffer_leaflist);
832 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
833 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
834 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
835 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
837 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
839 if (r_shadow_buffer_surfacepvs)
840 Mem_Free(r_shadow_buffer_surfacepvs);
841 if (r_shadow_buffer_surfacelist)
842 Mem_Free(r_shadow_buffer_surfacelist);
843 if (r_shadow_buffer_surfacesides)
844 Mem_Free(r_shadow_buffer_surfacesides);
845 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
846 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
847 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
848 r_shadow_buffer_surfacesides = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
850 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
852 if (r_shadow_buffer_shadowtrispvs)
853 Mem_Free(r_shadow_buffer_shadowtrispvs);
854 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
855 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
857 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
859 if (r_shadow_buffer_lighttrispvs)
860 Mem_Free(r_shadow_buffer_lighttrispvs);
861 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
862 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
866 void R_Shadow_PrepareShadowMark(int numtris)
868 // make sure shadowmark is big enough for this volume
869 if (maxshadowmark < numtris)
871 maxshadowmark = numtris;
873 Mem_Free(shadowmark);
875 Mem_Free(shadowmarklist);
876 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
877 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
881 // if shadowmarkcount wrapped we clear the array and adjust accordingly
882 if (shadowmarkcount == 0)
885 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
890 void R_Shadow_PrepareShadowSides(int numtris)
892 if (maxshadowsides < numtris)
894 maxshadowsides = numtris;
896 Mem_Free(shadowsides);
898 Mem_Free(shadowsideslist);
899 shadowsides = (unsigned char *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsides));
900 shadowsideslist = (int *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsideslist));
905 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)
908 int outtriangles = 0, outvertices = 0;
911 float ratio, direction[3], projectvector[3];
913 if (projectdirection)
914 VectorScale(projectdirection, projectdistance, projectvector);
916 VectorClear(projectvector);
918 // create the vertices
919 if (projectdirection)
921 for (i = 0;i < numshadowmarktris;i++)
923 element = inelement3i + shadowmarktris[i] * 3;
924 for (j = 0;j < 3;j++)
926 if (vertexupdate[element[j]] != vertexupdatenum)
928 vertexupdate[element[j]] = vertexupdatenum;
929 vertexremap[element[j]] = outvertices;
930 vertex = invertex3f + element[j] * 3;
931 // project one copy of the vertex according to projectvector
932 VectorCopy(vertex, outvertex3f);
933 VectorAdd(vertex, projectvector, (outvertex3f + 3));
942 for (i = 0;i < numshadowmarktris;i++)
944 element = inelement3i + shadowmarktris[i] * 3;
945 for (j = 0;j < 3;j++)
947 if (vertexupdate[element[j]] != vertexupdatenum)
949 vertexupdate[element[j]] = vertexupdatenum;
950 vertexremap[element[j]] = outvertices;
951 vertex = invertex3f + element[j] * 3;
952 // project one copy of the vertex to the sphere radius of the light
953 // (FIXME: would projecting it to the light box be better?)
954 VectorSubtract(vertex, projectorigin, direction);
955 ratio = projectdistance / VectorLength(direction);
956 VectorCopy(vertex, outvertex3f);
957 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
965 if (r_shadow_frontsidecasting.integer)
967 for (i = 0;i < numshadowmarktris;i++)
969 int remappedelement[3];
971 const int *neighbortriangle;
973 markindex = shadowmarktris[i] * 3;
974 element = inelement3i + markindex;
975 neighbortriangle = inneighbor3i + markindex;
976 // output the front and back triangles
977 outelement3i[0] = vertexremap[element[0]];
978 outelement3i[1] = vertexremap[element[1]];
979 outelement3i[2] = vertexremap[element[2]];
980 outelement3i[3] = vertexremap[element[2]] + 1;
981 outelement3i[4] = vertexremap[element[1]] + 1;
982 outelement3i[5] = vertexremap[element[0]] + 1;
986 // output the sides (facing outward from this triangle)
987 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
989 remappedelement[0] = vertexremap[element[0]];
990 remappedelement[1] = vertexremap[element[1]];
991 outelement3i[0] = remappedelement[1];
992 outelement3i[1] = remappedelement[0];
993 outelement3i[2] = remappedelement[0] + 1;
994 outelement3i[3] = remappedelement[1];
995 outelement3i[4] = remappedelement[0] + 1;
996 outelement3i[5] = remappedelement[1] + 1;
1001 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1003 remappedelement[1] = vertexremap[element[1]];
1004 remappedelement[2] = vertexremap[element[2]];
1005 outelement3i[0] = remappedelement[2];
1006 outelement3i[1] = remappedelement[1];
1007 outelement3i[2] = remappedelement[1] + 1;
1008 outelement3i[3] = remappedelement[2];
1009 outelement3i[4] = remappedelement[1] + 1;
1010 outelement3i[5] = remappedelement[2] + 1;
1015 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1017 remappedelement[0] = vertexremap[element[0]];
1018 remappedelement[2] = vertexremap[element[2]];
1019 outelement3i[0] = remappedelement[0];
1020 outelement3i[1] = remappedelement[2];
1021 outelement3i[2] = remappedelement[2] + 1;
1022 outelement3i[3] = remappedelement[0];
1023 outelement3i[4] = remappedelement[2] + 1;
1024 outelement3i[5] = remappedelement[0] + 1;
1033 for (i = 0;i < numshadowmarktris;i++)
1035 int remappedelement[3];
1037 const int *neighbortriangle;
1039 markindex = shadowmarktris[i] * 3;
1040 element = inelement3i + markindex;
1041 neighbortriangle = inneighbor3i + markindex;
1042 // output the front and back triangles
1043 outelement3i[0] = vertexremap[element[2]];
1044 outelement3i[1] = vertexremap[element[1]];
1045 outelement3i[2] = vertexremap[element[0]];
1046 outelement3i[3] = vertexremap[element[0]] + 1;
1047 outelement3i[4] = vertexremap[element[1]] + 1;
1048 outelement3i[5] = vertexremap[element[2]] + 1;
1052 // output the sides (facing outward from this triangle)
1053 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
1055 remappedelement[0] = vertexremap[element[0]];
1056 remappedelement[1] = vertexremap[element[1]];
1057 outelement3i[0] = remappedelement[0];
1058 outelement3i[1] = remappedelement[1];
1059 outelement3i[2] = remappedelement[1] + 1;
1060 outelement3i[3] = remappedelement[0];
1061 outelement3i[4] = remappedelement[1] + 1;
1062 outelement3i[5] = remappedelement[0] + 1;
1067 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1069 remappedelement[1] = vertexremap[element[1]];
1070 remappedelement[2] = vertexremap[element[2]];
1071 outelement3i[0] = remappedelement[1];
1072 outelement3i[1] = remappedelement[2];
1073 outelement3i[2] = remappedelement[2] + 1;
1074 outelement3i[3] = remappedelement[1];
1075 outelement3i[4] = remappedelement[2] + 1;
1076 outelement3i[5] = remappedelement[1] + 1;
1081 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1083 remappedelement[0] = vertexremap[element[0]];
1084 remappedelement[2] = vertexremap[element[2]];
1085 outelement3i[0] = remappedelement[2];
1086 outelement3i[1] = remappedelement[0];
1087 outelement3i[2] = remappedelement[0] + 1;
1088 outelement3i[3] = remappedelement[2];
1089 outelement3i[4] = remappedelement[0] + 1;
1090 outelement3i[5] = remappedelement[2] + 1;
1098 *outnumvertices = outvertices;
1099 return outtriangles;
1102 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)
1105 int outtriangles = 0, outvertices = 0;
1107 const float *vertex;
1108 float ratio, direction[3], projectvector[3];
1111 if (projectdirection)
1112 VectorScale(projectdirection, projectdistance, projectvector);
1114 VectorClear(projectvector);
1116 for (i = 0;i < numshadowmarktris;i++)
1118 int remappedelement[3];
1120 const int *neighbortriangle;
1122 markindex = shadowmarktris[i] * 3;
1123 neighbortriangle = inneighbor3i + markindex;
1124 side[0] = shadowmark[neighbortriangle[0]] == shadowmarkcount;
1125 side[1] = shadowmark[neighbortriangle[1]] == shadowmarkcount;
1126 side[2] = shadowmark[neighbortriangle[2]] == shadowmarkcount;
1127 if (side[0] + side[1] + side[2] == 0)
1131 element = inelement3i + markindex;
1133 // create the vertices
1134 for (j = 0;j < 3;j++)
1136 if (side[j] + side[j+1] == 0)
1139 if (vertexupdate[k] != vertexupdatenum)
1141 vertexupdate[k] = vertexupdatenum;
1142 vertexremap[k] = outvertices;
1143 vertex = invertex3f + k * 3;
1144 VectorCopy(vertex, outvertex3f);
1145 if (projectdirection)
1147 // project one copy of the vertex according to projectvector
1148 VectorAdd(vertex, projectvector, (outvertex3f + 3));
1152 // project one copy of the vertex to the sphere radius of the light
1153 // (FIXME: would projecting it to the light box be better?)
1154 VectorSubtract(vertex, projectorigin, direction);
1155 ratio = projectdistance / VectorLength(direction);
1156 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1163 // output the sides (facing outward from this triangle)
1166 remappedelement[0] = vertexremap[element[0]];
1167 remappedelement[1] = vertexremap[element[1]];
1168 outelement3i[0] = remappedelement[1];
1169 outelement3i[1] = remappedelement[0];
1170 outelement3i[2] = remappedelement[0] + 1;
1171 outelement3i[3] = remappedelement[1];
1172 outelement3i[4] = remappedelement[0] + 1;
1173 outelement3i[5] = remappedelement[1] + 1;
1180 remappedelement[1] = vertexremap[element[1]];
1181 remappedelement[2] = vertexremap[element[2]];
1182 outelement3i[0] = remappedelement[2];
1183 outelement3i[1] = remappedelement[1];
1184 outelement3i[2] = remappedelement[1] + 1;
1185 outelement3i[3] = remappedelement[2];
1186 outelement3i[4] = remappedelement[1] + 1;
1187 outelement3i[5] = remappedelement[2] + 1;
1194 remappedelement[0] = vertexremap[element[0]];
1195 remappedelement[2] = vertexremap[element[2]];
1196 outelement3i[0] = remappedelement[0];
1197 outelement3i[1] = remappedelement[2];
1198 outelement3i[2] = remappedelement[2] + 1;
1199 outelement3i[3] = remappedelement[0];
1200 outelement3i[4] = remappedelement[2] + 1;
1201 outelement3i[5] = remappedelement[0] + 1;
1208 *outnumvertices = outvertices;
1209 return outtriangles;
1212 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)
1218 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1220 tend = firsttriangle + numtris;
1221 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1223 // surface box entirely inside light box, no box cull
1224 if (projectdirection)
1226 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1228 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
1229 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1230 shadowmarklist[numshadowmark++] = t;
1235 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1236 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
1237 shadowmarklist[numshadowmark++] = t;
1242 // surface box not entirely inside light box, cull each triangle
1243 if (projectdirection)
1245 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1247 v[0] = invertex3f + e[0] * 3;
1248 v[1] = invertex3f + e[1] * 3;
1249 v[2] = invertex3f + e[2] * 3;
1250 TriangleNormal(v[0], v[1], v[2], normal);
1251 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1252 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1253 shadowmarklist[numshadowmark++] = t;
1258 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1260 v[0] = invertex3f + e[0] * 3;
1261 v[1] = invertex3f + e[1] * 3;
1262 v[2] = invertex3f + e[2] * 3;
1263 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1264 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1265 shadowmarklist[numshadowmark++] = t;
1271 qboolean R_Shadow_UseZPass(vec3_t mins, vec3_t maxs)
1276 if (r_shadow_compilingrtlight || !r_shadow_frontsidecasting.integer || !r_shadow_usezpassifpossible.integer)
1278 // check if the shadow volume intersects the near plane
1280 // a ray between the eye and light origin may intersect the caster,
1281 // indicating that the shadow may touch the eye location, however we must
1282 // test the near plane (a polygon), not merely the eye location, so it is
1283 // easiest to enlarge the caster bounding shape slightly for this.
1289 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)
1291 int i, tris, outverts;
1292 if (projectdistance < 0.1)
1294 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
1297 if (!numverts || !nummarktris)
1299 // make sure shadowelements is big enough for this volume
1300 if (maxshadowtriangles < nummarktris*8 || maxshadowvertices < numverts*2)
1301 R_Shadow_ResizeShadowArrays(numverts, nummarktris, 2, 8);
1303 if (maxvertexupdate < numverts)
1305 maxvertexupdate = numverts;
1307 Mem_Free(vertexupdate);
1309 Mem_Free(vertexremap);
1310 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1311 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1312 vertexupdatenum = 0;
1315 if (vertexupdatenum == 0)
1317 vertexupdatenum = 1;
1318 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
1319 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
1322 for (i = 0;i < nummarktris;i++)
1323 shadowmark[marktris[i]] = shadowmarkcount;
1325 if (r_shadow_compilingrtlight)
1327 // if we're compiling an rtlight, capture the mesh
1328 //tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1329 //Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zpass, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1330 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1331 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zfail, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1333 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
1335 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1336 R_Mesh_PrepareVertices_Position_Arrays(outverts, shadowvertex3f);
1337 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1341 // decide which type of shadow to generate and set stencil mode
1342 R_Shadow_RenderMode_StencilShadowVolumes(R_Shadow_UseZPass(trismins, trismaxs));
1343 // generate the sides or a solid volume, depending on type
1344 if (r_shadow_rendermode >= R_SHADOW_RENDERMODE_ZPASS_STENCIL && r_shadow_rendermode <= R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE)
1345 tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1347 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1348 r_refdef.stats.lights_dynamicshadowtriangles += tris;
1349 r_refdef.stats.lights_shadowtriangles += tris;
1350 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
1352 // increment stencil if frontface is infront of depthbuffer
1353 GL_CullFace(r_refdef.view.cullface_front);
1354 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
1355 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1356 // decrement stencil if backface is infront of depthbuffer
1357 GL_CullFace(r_refdef.view.cullface_back);
1358 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
1360 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
1362 // decrement stencil if backface is behind depthbuffer
1363 GL_CullFace(r_refdef.view.cullface_front);
1364 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
1365 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1366 // increment stencil if frontface is behind depthbuffer
1367 GL_CullFace(r_refdef.view.cullface_back);
1368 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
1370 R_Mesh_PrepareVertices_Position_Arrays(outverts, shadowvertex3f);
1371 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1375 int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias)
1377 // p1, p2, p3 are in the cubemap's local coordinate system
1378 // bias = border/(size - border)
1381 float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1382 dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2),
1383 dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3);
1384 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1386 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1387 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1388 | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1389 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1391 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1392 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1393 | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1395 dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1396 dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2),
1397 dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3);
1398 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1400 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1401 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1402 | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1403 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1405 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1406 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1407 | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1409 dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1410 dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2),
1411 dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3);
1412 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1414 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1415 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1416 | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1417 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1419 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1420 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1421 | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1426 int R_Shadow_CalcBBoxSideMask(const vec3_t mins, const vec3_t maxs, const matrix4x4_t *worldtolight, const matrix4x4_t *radiustolight, float bias)
1428 vec3_t center, radius, lightcenter, lightradius, pmin, pmax;
1429 float dp1, dn1, ap1, an1, dp2, dn2, ap2, an2;
1432 VectorSubtract(maxs, mins, radius);
1433 VectorScale(radius, 0.5f, radius);
1434 VectorAdd(mins, radius, center);
1435 Matrix4x4_Transform(worldtolight, center, lightcenter);
1436 Matrix4x4_Transform3x3(radiustolight, radius, lightradius);
1437 VectorSubtract(lightcenter, lightradius, pmin);
1438 VectorAdd(lightcenter, lightradius, pmax);
1440 dp1 = pmax[0] + pmax[1], dn1 = pmax[0] - pmin[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1441 dp2 = pmin[0] + pmin[1], dn2 = pmin[0] - pmax[1], ap2 = fabs(dp2), an2 = fabs(dn2);
1442 if(ap1 > bias*an1 && ap2 > bias*an2)
1444 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1445 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1446 if(an1 > bias*ap1 && an2 > bias*ap2)
1448 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1449 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1451 dp1 = pmax[1] + pmax[2], dn1 = pmax[1] - pmin[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1452 dp2 = pmin[1] + pmin[2], dn2 = pmin[1] - pmax[2], ap2 = fabs(dp2), an2 = fabs(dn2);
1453 if(ap1 > bias*an1 && ap2 > bias*an2)
1455 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1456 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1457 if(an1 > bias*ap1 && an2 > bias*ap2)
1459 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1460 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1462 dp1 = pmax[2] + pmax[0], dn1 = pmax[2] - pmin[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1463 dp2 = pmin[2] + pmin[0], dn2 = pmin[2] - pmax[0], ap2 = fabs(dp2), an2 = fabs(dn2);
1464 if(ap1 > bias*an1 && ap2 > bias*an2)
1466 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1467 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1468 if(an1 > bias*ap1 && an2 > bias*ap2)
1470 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1471 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1476 #define R_Shadow_CalcEntitySideMask(ent, worldtolight, radiustolight, bias) R_Shadow_CalcBBoxSideMask((ent)->mins, (ent)->maxs, worldtolight, radiustolight, bias)
1478 int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
1480 // p is in the cubemap's local coordinate system
1481 // bias = border/(size - border)
1482 float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn);
1483 float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn);
1484 float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn);
1486 if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
1487 if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
1488 if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
1489 if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
1490 if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
1491 if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
1495 int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
1499 int sides = 0x3F, masks[6] = { 3<<4, 3<<4, 3<<0, 3<<0, 3<<2, 3<<2 };
1500 float scale = (size - 2*border)/size, len;
1501 float bias = border / (float)(size - border), dp, dn, ap, an;
1502 // check if cone enclosing side would cross frustum plane
1503 scale = 2 / (scale*scale + 2);
1504 for (i = 0;i < 5;i++)
1506 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) > -0.03125)
1508 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[i].normal, n);
1509 len = scale*VectorLength2(n);
1510 if(n[0]*n[0] > len) sides &= n[0] < 0 ? ~(1<<0) : ~(2 << 0);
1511 if(n[1]*n[1] > len) sides &= n[1] < 0 ? ~(1<<2) : ~(2 << 2);
1512 if(n[2]*n[2] > len) sides &= n[2] < 0 ? ~(1<<4) : ~(2 << 4);
1514 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[4]) >= r_refdef.farclip - r_refdef.nearclip + 0.03125)
1516 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[4].normal, n);
1517 len = scale*VectorLength(n);
1518 if(n[0]*n[0] > len) sides &= n[0] >= 0 ? ~(1<<0) : ~(2 << 0);
1519 if(n[1]*n[1] > len) sides &= n[1] >= 0 ? ~(1<<2) : ~(2 << 2);
1520 if(n[2]*n[2] > len) sides &= n[2] >= 0 ? ~(1<<4) : ~(2 << 4);
1522 // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results
1523 // check if frustum corners/origin cross plane sides
1525 // infinite version, assumes frustum corners merely give direction and extend to infinite distance
1526 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.origin, p);
1527 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1528 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1529 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1530 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1531 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1532 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1533 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1534 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1535 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1536 for (i = 0;i < 4;i++)
1538 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.frustumcorner[i], n);
1539 VectorSubtract(n, p, n);
1540 dp = n[0] + n[1], dn = n[0] - n[1], ap = fabs(dp), an = fabs(dn);
1541 if(ap > 0) masks[0] |= dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2);
1542 if(an > 0) masks[1] |= dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2);
1543 dp = n[1] + n[2], dn = n[1] - n[2], ap = fabs(dp), an = fabs(dn);
1544 if(ap > 0) masks[2] |= dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4);
1545 if(an > 0) masks[3] |= dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4);
1546 dp = n[2] + n[0], dn = n[2] - n[0], ap = fabs(dp), an = fabs(dn);
1547 if(ap > 0) masks[4] |= dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0);
1548 if(an > 0) masks[5] |= dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0);
1551 // finite version, assumes corners are a finite distance from origin dependent on far plane
1552 for (i = 0;i < 5;i++)
1554 Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p);
1555 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1556 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1557 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1558 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1559 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1560 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1561 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1562 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1563 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1566 return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5];
1569 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)
1577 int mask, surfacemask = 0;
1578 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1580 bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
1581 tend = firsttriangle + numtris;
1582 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1584 // surface box entirely inside light box, no box cull
1585 if (projectdirection)
1587 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1589 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1590 TriangleNormal(v[0], v[1], v[2], normal);
1591 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1593 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1594 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1595 surfacemask |= mask;
1598 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;
1599 shadowsides[numshadowsides] = mask;
1600 shadowsideslist[numshadowsides++] = t;
1607 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1609 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1610 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]))
1612 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1613 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1614 surfacemask |= mask;
1617 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;
1618 shadowsides[numshadowsides] = mask;
1619 shadowsideslist[numshadowsides++] = t;
1627 // surface box not entirely inside light box, cull each triangle
1628 if (projectdirection)
1630 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1632 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1633 TriangleNormal(v[0], v[1], v[2], normal);
1634 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1635 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1637 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1638 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1639 surfacemask |= mask;
1642 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;
1643 shadowsides[numshadowsides] = mask;
1644 shadowsideslist[numshadowsides++] = t;
1651 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1653 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1654 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1655 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1657 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1658 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1659 surfacemask |= mask;
1662 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;
1663 shadowsides[numshadowsides] = mask;
1664 shadowsideslist[numshadowsides++] = t;
1673 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)
1675 int i, j, outtriangles = 0;
1676 int *outelement3i[6];
1677 if (!numverts || !numsidetris || !r_shadow_compilingrtlight)
1679 outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5];
1680 // make sure shadowelements is big enough for this mesh
1681 if (maxshadowtriangles < outtriangles)
1682 R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1);
1684 // compute the offset and size of the separate index lists for each cubemap side
1686 for (i = 0;i < 6;i++)
1688 outelement3i[i] = shadowelements + outtriangles * 3;
1689 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles;
1690 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i];
1691 outtriangles += sidetotals[i];
1694 // gather up the (sparse) triangles into separate index lists for each cubemap side
1695 for (i = 0;i < numsidetris;i++)
1697 const int *element = elements + sidetris[i] * 3;
1698 for (j = 0;j < 6;j++)
1700 if (sides[i] & (1 << j))
1702 outelement3i[j][0] = element[0];
1703 outelement3i[j][1] = element[1];
1704 outelement3i[j][2] = element[2];
1705 outelement3i[j] += 3;
1710 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, outtriangles, shadowelements);
1713 static void R_Shadow_MakeTextures_MakeCorona(void)
1717 unsigned char pixels[32][32][4];
1718 for (y = 0;y < 32;y++)
1720 dy = (y - 15.5f) * (1.0f / 16.0f);
1721 for (x = 0;x < 32;x++)
1723 dx = (x - 15.5f) * (1.0f / 16.0f);
1724 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1725 a = bound(0, a, 255);
1726 pixels[y][x][0] = a;
1727 pixels[y][x][1] = a;
1728 pixels[y][x][2] = a;
1729 pixels[y][x][3] = 255;
1732 r_shadow_lightcorona = R_SkinFrame_LoadInternalBGRA("lightcorona", TEXF_FORCELINEAR, &pixels[0][0][0], 32, 32);
1735 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1737 float dist = sqrt(x*x+y*y+z*z);
1738 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1739 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1740 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1743 static void R_Shadow_MakeTextures(void)
1746 float intensity, dist;
1748 R_Shadow_FreeShadowMaps();
1749 R_FreeTexturePool(&r_shadow_texturepool);
1750 r_shadow_texturepool = R_AllocTexturePool();
1751 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1752 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1753 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1754 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1755 for (x = 0;x <= ATTENTABLESIZE;x++)
1757 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1758 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1759 r_shadow_attentable[x] = bound(0, intensity, 1);
1761 // 1D gradient texture
1762 for (x = 0;x < ATTEN1DSIZE;x++)
1763 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1764 r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1765 // 2D circle texture
1766 for (y = 0;y < ATTEN2DSIZE;y++)
1767 for (x = 0;x < ATTEN2DSIZE;x++)
1768 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);
1769 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1770 // 3D sphere texture
1771 if (r_shadow_texture3d.integer && vid.support.ext_texture_3d)
1773 for (z = 0;z < ATTEN3DSIZE;z++)
1774 for (y = 0;y < ATTEN3DSIZE;y++)
1775 for (x = 0;x < ATTEN3DSIZE;x++)
1776 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));
1777 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);
1780 r_shadow_attenuation3dtexture = NULL;
1783 R_Shadow_MakeTextures_MakeCorona();
1785 // Editor light sprites
1786 r_editlights_sprcursor = R_SkinFrame_LoadInternal8bit("gfx/editlights/cursor", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1803 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1804 r_editlights_sprlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/light", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1821 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1822 r_editlights_sprnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/noshadow", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1839 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1840 r_editlights_sprcubemaplight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemaplight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1857 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1858 r_editlights_sprcubemapnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemapnoshadowlight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1875 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1876 r_editlights_sprselection = R_SkinFrame_LoadInternal8bit("gfx/editlights/selection", TEXF_ALPHA | TEXF_CLAMP, (unsigned char *)
1893 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1896 void R_Shadow_ValidateCvars(void)
1898 if (r_shadow_texture3d.integer && !vid.support.ext_texture_3d)
1899 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1900 if (gl_ext_separatestencil.integer && !vid.support.ati_separate_stencil)
1901 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
1902 if (gl_ext_stenciltwoside.integer && !vid.support.ext_stencil_two_side)
1903 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1906 //static const r_vertexposition_t resetvertexposition[3] = {{0, 0, 0}};
1908 void R_Shadow_RenderMode_Begin(void)
1914 R_Shadow_ValidateCvars();
1916 if (!r_shadow_attenuation2dtexture
1917 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1918 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1919 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1920 R_Shadow_MakeTextures();
1923 R_Mesh_ResetTextureState();
1924 // R_Mesh_PrepareVertices_Position(0, resetvertexposition, NULL);
1925 GL_BlendFunc(GL_ONE, GL_ZERO);
1926 GL_DepthRange(0, 1);
1927 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1929 GL_DepthMask(false);
1930 GL_Color(0, 0, 0, 1);
1931 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1933 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1935 if (gl_ext_separatestencil.integer && vid.support.ati_separate_stencil)
1937 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
1938 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
1940 else if (gl_ext_stenciltwoside.integer && vid.support.ext_stencil_two_side)
1942 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
1943 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
1947 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
1948 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
1951 switch(vid.renderpath)
1953 case RENDERPATH_GL20:
1954 case RENDERPATH_CGGL:
1955 case RENDERPATH_D3D9:
1956 case RENDERPATH_D3D10:
1957 case RENDERPATH_D3D11:
1958 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1960 case RENDERPATH_GL13:
1961 case RENDERPATH_GL11:
1962 if (r_textureunits.integer >= 2 && vid.texunits >= 2 && r_shadow_texture3d.integer && r_shadow_attenuation3dtexture)
1963 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN;
1964 else if (r_textureunits.integer >= 3 && vid.texunits >= 3)
1965 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN;
1966 else if (r_textureunits.integer >= 2 && vid.texunits >= 2)
1967 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN;
1969 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1975 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
1976 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
1977 r_shadow_drawbuffer = drawbuffer;
1978 r_shadow_readbuffer = readbuffer;
1980 r_shadow_cullface_front = r_refdef.view.cullface_front;
1981 r_shadow_cullface_back = r_refdef.view.cullface_back;
1984 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
1986 rsurface.rtlight = rtlight;
1989 void R_Shadow_RenderMode_Reset(void)
1991 R_Mesh_ResetRenderTargets();
1992 R_SetViewport(&r_refdef.view.viewport);
1993 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
1994 R_Mesh_ResetTextureState();
1995 // R_Mesh_PrepareVertices_Position(0, resetvertexposition, NULL);
1996 GL_DepthRange(0, 1);
1998 GL_DepthMask(false);
1999 GL_DepthFunc(GL_LEQUAL);
2000 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
2001 r_refdef.view.cullface_front = r_shadow_cullface_front;
2002 r_refdef.view.cullface_back = r_shadow_cullface_back;
2003 GL_CullFace(r_refdef.view.cullface_back);
2004 GL_Color(1, 1, 1, 1);
2005 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
2006 GL_BlendFunc(GL_ONE, GL_ZERO);
2007 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
2008 r_shadow_usingshadowmaprect = false;
2009 r_shadow_usingshadowmapcube = false;
2010 r_shadow_usingshadowmap2d = false;
2011 r_shadow_usingshadowmaportho = false;
2012 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
2015 void R_Shadow_ClearStencil(void)
2017 GL_Clear(GL_STENCIL_BUFFER_BIT, NULL, 1.0f, 128);
2018 r_refdef.stats.lights_clears++;
2021 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
2023 r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
2024 if (r_shadow_rendermode == mode)
2026 R_Shadow_RenderMode_Reset();
2027 GL_DepthFunc(GL_LESS);
2028 GL_ColorMask(0, 0, 0, 0);
2029 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2030 GL_CullFace(GL_NONE);
2031 R_SetupShader_DepthOrShadow();
2032 r_shadow_rendermode = mode;
2037 case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
2038 case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
2039 R_SetStencilSeparate(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, GL_ALWAYS, 128, 255);
2041 case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
2042 case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
2043 R_SetStencilSeparate(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, GL_ALWAYS, 128, 255);
2048 static void R_Shadow_MakeVSDCT(void)
2050 // maps to a 2x3 texture rectangle with normalized coordinates
2055 // stores abs(dir.xy), offset.xy/2.5
2056 unsigned char data[4*6] =
2058 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
2059 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
2060 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
2061 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
2062 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
2063 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
2065 r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
2068 static void R_Shadow_MakeShadowMap(int side, int size)
2070 switch (r_shadow_shadowmode)
2072 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2073 if (r_shadow_shadowmap2dtexture) return;
2074 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);
2075 r_shadow_shadowmap2dcolortexture = NULL;
2076 switch(vid.renderpath)
2079 case RENDERPATH_D3D9:
2080 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);
2081 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
2085 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2dtexture, NULL, NULL, NULL, NULL);
2089 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
2090 if (r_shadow_shadowmaprectangletexture) return;
2091 r_shadow_shadowmaprectangletexture = R_LoadTextureShadowMapRectangle(r_shadow_texturepool, "shadowmap", size*2, size*3, r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
2092 r_shadow_fborectangle = R_Mesh_CreateFramebufferObject(r_shadow_shadowmaprectangletexture, NULL, NULL, NULL, NULL);
2094 case R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE:
2095 if (r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]) return;
2096 r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod] = R_LoadTextureShadowMapCube(r_shadow_texturepool, "shadowmapcube", size, r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
2097 // special trick to get an empty fbo we configure ourselves...
2098 r_shadow_fbocubeside[r_shadow_shadowmaplod] = R_Mesh_CreateFramebufferObject(NULL, NULL, NULL, NULL, NULL);
2099 R_Mesh_SetRenderTargets(r_shadow_fbocubeside[r_shadow_shadowmaplod], NULL, NULL, NULL, NULL, NULL);
2100 if (qglFramebufferTexture2DEXT)
2101 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + side, R_GetTexture(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]), 0);CHECKGLERROR
2107 // render depth into the fbo, do not render color at all
2108 // validate the fbo now
2112 qglDrawBuffer(GL_NONE);CHECKGLERROR
2113 qglReadBuffer(GL_NONE);CHECKGLERROR
2114 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2115 if (status != GL_FRAMEBUFFER_COMPLETE_EXT && (r_shadow_shadowmapping.integer || r_shadow_deferred.integer))
2117 Con_Printf("R_Shadow_MakeShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2118 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2119 Cvar_SetValueQuick(&r_shadow_deferred, 0);
2124 static float testcolor[4] = {0,1,0,1};
2125 void R_Shadow_RenderMode_ShadowMap(int side, int clear, int size)
2127 float nearclip, farclip, bias;
2128 r_viewport_t viewport;
2131 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
2133 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
2134 r_shadow_shadowmap_parameters[1] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
2135 r_shadow_shadowmap_parameters[3] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
2136 r_shadow_shadowmapside = side;
2137 r_shadow_shadowmapsize = size;
2138 switch (r_shadow_shadowmode)
2140 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2141 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2142 r_shadow_shadowmap_parameters[2] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2143 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
2144 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D) goto init_done;
2146 // complex unrolled cube approach (more flexible)
2147 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2148 R_Shadow_MakeVSDCT();
2149 if (!r_shadow_shadowmap2dtexture)
2150 R_Shadow_MakeShadowMap(side, r_shadow_shadowmapmaxsize);
2151 if (r_shadow_shadowmap2dtexture) fbo = r_shadow_fbo2d;
2152 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
2153 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
2154 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
2156 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
2157 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2158 r_shadow_shadowmap_parameters[2] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2159 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
2160 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE) goto init_done;
2162 // complex unrolled cube approach (more flexible)
2163 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2164 R_Shadow_MakeVSDCT();
2165 if (!r_shadow_shadowmaprectangletexture)
2166 R_Shadow_MakeShadowMap(side, r_shadow_shadowmapmaxsize);
2167 if(r_shadow_shadowmaprectangletexture) fbo = r_shadow_fborectangle;
2168 r_shadow_shadowmap_texturescale[0] = 1.0f;
2169 r_shadow_shadowmap_texturescale[1] = 1.0f;
2170 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE;
2172 case R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE:
2173 r_shadow_shadowmap_parameters[0] = 1.0f;
2174 r_shadow_shadowmap_parameters[2] = 1.0f;
2175 R_Viewport_InitCubeSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, nearclip, farclip, NULL);
2176 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE) goto init_done;
2178 // simple cube approach
2179 if (!r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod])
2180 R_Shadow_MakeShadowMap(side, size);
2181 if (r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]) fbo = r_shadow_fbocubeside[r_shadow_shadowmaplod];
2182 r_shadow_shadowmap_texturescale[0] = 0.0f;
2183 r_shadow_shadowmap_texturescale[1] = 0.0f;
2184 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE;
2190 R_Shadow_RenderMode_Reset();
2193 R_Mesh_SetRenderTargets(fbo, r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
2194 R_SetupShader_DepthOrShadow();
2197 R_SetupShader_ShowDepth();
2198 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
2203 R_SetViewport(&viewport);
2204 switch (r_shadow_rendermode)
2206 case R_SHADOW_RENDERMODE_SHADOWMAP2D:
2207 case R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE:
2208 flipped = (side & 1) ^ (side >> 2);
2209 r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
2210 r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
2211 switch(vid.renderpath)
2213 case RENDERPATH_GL11:
2214 case RENDERPATH_GL13:
2215 case RENDERPATH_GL20:
2216 case RENDERPATH_CGGL:
2217 GL_CullFace(r_refdef.view.cullface_back);
2218 // OpenGL lets us scissor larger than the viewport, so go ahead and clear all views at once
2219 if ((clear & ((2 << side) - 1)) == (1 << side)) // only clear if the side is the first in the mask
2221 // get tightest scissor rectangle that encloses all viewports in the clear mask
2222 int x1 = clear & 0x15 ? 0 : size;
2223 int x2 = clear & 0x2A ? 2 * size : size;
2224 int y1 = clear & 0x03 ? 0 : (clear & 0xC ? size : 2 * size);
2225 int y2 = clear & 0x30 ? 3 * size : (clear & 0xC ? 2 * size : size);
2226 GL_Scissor(x1, y1, x2 - x1, y2 - y1);
2227 GL_Clear(GL_DEPTH_BUFFER_BIT, NULL, 1.0f, 0);
2229 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2231 case RENDERPATH_D3D9:
2232 // completely different meaning than in OpenGL path
2233 r_shadow_shadowmap_parameters[1] = 0;
2234 r_shadow_shadowmap_parameters[3] = -bias;
2235 // we invert the cull mode because we flip the projection matrix
2236 // NOTE: this actually does nothing because the DrawShadowMap code sets it to doublesided...
2237 GL_CullFace(r_refdef.view.cullface_front);
2238 // D3D considers it an error to use a scissor larger than the viewport... clear just this view
2239 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2240 if (r_shadow_shadowmapsampler)
2242 GL_ColorMask(0,0,0,0);
2244 GL_Clear(GL_DEPTH_BUFFER_BIT, testcolor, 1.0f, 0);
2248 GL_ColorMask(1,1,1,1);
2250 GL_Clear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT, testcolor, 1.0f, 0);
2253 case RENDERPATH_D3D10:
2254 case RENDERPATH_D3D11:
2255 // D3D considers it an error to use a scissor larger than the viewport... clear just this view
2256 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2257 GL_ColorMask(0,0,0,0);
2259 GL_Clear(GL_DEPTH_BUFFER_BIT, NULL, 1.0f, 0);
2263 case R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE:
2264 if (qglFramebufferTexture2DEXT)
2265 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + side, R_GetTexture(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]), 0);CHECKGLERROR
2266 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2268 GL_Clear(GL_DEPTH_BUFFER_BIT, NULL, 1.0f, 0);
2275 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
2279 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2280 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2281 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2282 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2284 R_Shadow_RenderMode_Reset();
2285 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2287 GL_DepthFunc(GL_EQUAL);
2288 // do global setup needed for the chosen lighting mode
2289 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2290 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2293 switch (r_shadow_shadowmode)
2295 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2296 r_shadow_usingshadowmap2d = true;
2298 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
2299 r_shadow_usingshadowmaprect = true;
2301 case R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE:
2302 r_shadow_usingshadowmapcube = true;
2308 r_shadow_rendermode = r_shadow_lightingrendermode;
2309 // only draw light where this geometry was already rendered AND the
2310 // stencil is 128 (values other than this mean shadow)
2312 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2314 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
2317 static const unsigned short bboxelements[36] =
2327 static const float bboxpoints[8][3] =
2339 void R_Shadow_RenderMode_DrawDeferredLight(qboolean stenciltest, qboolean shadowmapping)
2342 float vertex3f[8*3];
2343 const matrix4x4_t *matrix = &rsurface.rtlight->matrix_lighttoworld;
2344 // do global setup needed for the chosen lighting mode
2345 R_Shadow_RenderMode_Reset();
2346 r_shadow_rendermode = r_shadow_lightingrendermode;
2347 R_EntityMatrix(&identitymatrix);
2348 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2349 // only draw light where this geometry was already rendered AND the
2350 // stencil is 128 (values other than this mean shadow)
2351 R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2352 R_Mesh_SetRenderTargets(r_shadow_prepasslightingfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
2356 switch (r_shadow_shadowmode)
2358 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2359 r_shadow_usingshadowmap2d = true;
2361 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
2362 r_shadow_usingshadowmaprect = true;
2364 case R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE:
2365 r_shadow_usingshadowmapcube = true;
2372 // render the lighting
2373 R_SetupShader_DeferredLight(rsurface.rtlight);
2374 for (i = 0;i < 8;i++)
2375 Matrix4x4_Transform(matrix, bboxpoints[i], vertex3f + i*3);
2376 GL_ColorMask(1,1,1,1);
2377 GL_DepthMask(false);
2378 GL_DepthRange(0, 1);
2379 GL_PolygonOffset(0, 0);
2381 GL_DepthFunc(GL_GREATER);
2382 GL_CullFace(r_refdef.view.cullface_back);
2383 R_Mesh_PrepareVertices_Position_Arrays(8, vertex3f);
2384 R_Mesh_Draw(0, 8, 0, 12, NULL, NULL, 0, bboxelements, NULL, 0);
2387 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
2389 R_Shadow_RenderMode_Reset();
2390 GL_BlendFunc(GL_ONE, GL_ONE);
2391 GL_DepthRange(0, 1);
2392 GL_DepthTest(r_showshadowvolumes.integer < 2);
2393 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
2394 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2395 GL_CullFace(GL_NONE);
2396 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
2399 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
2401 R_Shadow_RenderMode_Reset();
2402 GL_BlendFunc(GL_ONE, GL_ONE);
2403 GL_DepthRange(0, 1);
2404 GL_DepthTest(r_showlighting.integer < 2);
2405 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2407 GL_DepthFunc(GL_EQUAL);
2408 R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2409 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2412 void R_Shadow_RenderMode_End(void)
2414 R_Shadow_RenderMode_Reset();
2415 R_Shadow_RenderMode_ActiveLight(NULL);
2417 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2418 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2421 int bboxedges[12][2] =
2440 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2442 int i, ix1, iy1, ix2, iy2;
2443 float x1, y1, x2, y2;
2445 float vertex[20][3];
2454 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2455 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2456 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2457 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2459 if (!r_shadow_scissor.integer)
2462 // if view is inside the light box, just say yes it's visible
2463 if (BoxesOverlap(r_refdef.view.origin, r_refdef.view.origin, mins, maxs))
2466 x1 = y1 = x2 = y2 = 0;
2468 // transform all corners that are infront of the nearclip plane
2469 VectorNegate(r_refdef.view.frustum[4].normal, plane4f);
2470 plane4f[3] = r_refdef.view.frustum[4].dist;
2472 for (i = 0;i < 8;i++)
2474 Vector4Set(corner[i], (i & 1) ? maxs[0] : mins[0], (i & 2) ? maxs[1] : mins[1], (i & 4) ? maxs[2] : mins[2], 1);
2475 dist[i] = DotProduct4(corner[i], plane4f);
2476 sign[i] = dist[i] > 0;
2479 VectorCopy(corner[i], vertex[numvertices]);
2483 // if some points are behind the nearclip, add clipped edge points to make
2484 // sure that the scissor boundary is complete
2485 if (numvertices > 0 && numvertices < 8)
2487 // add clipped edge points
2488 for (i = 0;i < 12;i++)
2490 j = bboxedges[i][0];
2491 k = bboxedges[i][1];
2492 if (sign[j] != sign[k])
2494 f = dist[j] / (dist[j] - dist[k]);
2495 VectorLerp(corner[j], f, corner[k], vertex[numvertices]);
2501 // if we have no points to check, the light is behind the view plane
2505 // if we have some points to transform, check what screen area is covered
2506 x1 = y1 = x2 = y2 = 0;
2508 //Con_Printf("%i vertices to transform...\n", numvertices);
2509 for (i = 0;i < numvertices;i++)
2511 VectorCopy(vertex[i], v);
2512 R_Viewport_TransformToScreen(&r_refdef.view.viewport, v, v2);
2513 //Con_Printf("%.3f %.3f %.3f %.3f transformed to %.3f %.3f %.3f %.3f\n", v[0], v[1], v[2], v[3], v2[0], v2[1], v2[2], v2[3]);
2516 if (x1 > v2[0]) x1 = v2[0];
2517 if (x2 < v2[0]) x2 = v2[0];
2518 if (y1 > v2[1]) y1 = v2[1];
2519 if (y2 < v2[1]) y2 = v2[1];
2528 // now convert the scissor rectangle to integer screen coordinates
2529 ix1 = (int)(x1 - 1.0f);
2530 iy1 = vid.height - (int)(y2 - 1.0f);
2531 ix2 = (int)(x2 + 1.0f);
2532 iy2 = vid.height - (int)(y1 + 1.0f);
2533 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
2535 // clamp it to the screen
2536 if (ix1 < r_refdef.view.viewport.x) ix1 = r_refdef.view.viewport.x;
2537 if (iy1 < r_refdef.view.viewport.y) iy1 = r_refdef.view.viewport.y;
2538 if (ix2 > r_refdef.view.viewport.x + r_refdef.view.viewport.width) ix2 = r_refdef.view.viewport.x + r_refdef.view.viewport.width;
2539 if (iy2 > r_refdef.view.viewport.y + r_refdef.view.viewport.height) iy2 = r_refdef.view.viewport.y + r_refdef.view.viewport.height;
2541 // if it is inside out, it's not visible
2542 if (ix2 <= ix1 || iy2 <= iy1)
2545 // the light area is visible, set up the scissor rectangle
2546 r_shadow_lightscissor[0] = ix1;
2547 r_shadow_lightscissor[1] = iy1;
2548 r_shadow_lightscissor[2] = ix2 - ix1;
2549 r_shadow_lightscissor[3] = iy2 - iy1;
2551 // D3D Y coordinate is top to bottom, OpenGL is bottom to top, fix the D3D one
2552 switch(vid.renderpath)
2554 case RENDERPATH_D3D9:
2555 case RENDERPATH_D3D10:
2556 case RENDERPATH_D3D11:
2557 r_shadow_lightscissor[1] = vid.height - r_shadow_lightscissor[1] - r_shadow_lightscissor[3];
2559 case RENDERPATH_GL11:
2560 case RENDERPATH_GL13:
2561 case RENDERPATH_GL20:
2562 case RENDERPATH_CGGL:
2566 r_refdef.stats.lights_scissored++;
2570 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, const float *diffusecolor, const float *ambientcolor)
2573 const float *vertex3f;
2574 const float *normal3f;
2576 float dist, dot, distintensity, shadeintensity, v[3], n[3];
2577 switch (r_shadow_rendermode)
2579 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2580 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2581 if (VectorLength2(diffusecolor) > 0)
2583 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)
2585 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2586 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2587 if ((dot = DotProduct(n, v)) < 0)
2589 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2590 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
2593 VectorCopy(ambientcolor, color4f);
2594 if (r_refdef.fogenabled)
2597 f = RSurf_FogVertex(vertex3f);
2598 VectorScale(color4f, f, color4f);
2605 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.array_passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
2607 VectorCopy(ambientcolor, color4f);
2608 if (r_refdef.fogenabled)
2611 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2612 f = RSurf_FogVertex(vertex3f);
2613 VectorScale(color4f + 4*i, f, color4f);
2619 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2620 if (VectorLength2(diffusecolor) > 0)
2622 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)
2624 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2625 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2627 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2628 if ((dot = DotProduct(n, v)) < 0)
2630 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2631 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2632 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2633 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2637 color4f[0] = ambientcolor[0] * distintensity;
2638 color4f[1] = ambientcolor[1] * distintensity;
2639 color4f[2] = ambientcolor[2] * distintensity;
2641 if (r_refdef.fogenabled)
2644 f = RSurf_FogVertex(vertex3f);
2645 VectorScale(color4f, f, color4f);
2649 VectorClear(color4f);
2655 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.array_passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
2657 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2658 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2660 color4f[0] = ambientcolor[0] * distintensity;
2661 color4f[1] = ambientcolor[1] * distintensity;
2662 color4f[2] = ambientcolor[2] * distintensity;
2663 if (r_refdef.fogenabled)
2666 f = RSurf_FogVertex(vertex3f);
2667 VectorScale(color4f, f, color4f);
2671 VectorClear(color4f);
2676 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2677 if (VectorLength2(diffusecolor) > 0)
2679 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)
2681 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2682 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2684 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2685 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2686 if ((dot = DotProduct(n, v)) < 0)
2688 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2689 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2690 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2691 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2695 color4f[0] = ambientcolor[0] * distintensity;
2696 color4f[1] = ambientcolor[1] * distintensity;
2697 color4f[2] = ambientcolor[2] * distintensity;
2699 if (r_refdef.fogenabled)
2702 f = RSurf_FogVertex(vertex3f);
2703 VectorScale(color4f, f, color4f);
2707 VectorClear(color4f);
2713 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.array_passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
2715 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2716 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2718 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2719 color4f[0] = ambientcolor[0] * distintensity;
2720 color4f[1] = ambientcolor[1] * distintensity;
2721 color4f[2] = ambientcolor[2] * distintensity;
2722 if (r_refdef.fogenabled)
2725 f = RSurf_FogVertex(vertex3f);
2726 VectorScale(color4f, f, color4f);
2730 VectorClear(color4f);
2740 static void R_Shadow_RenderLighting_VisibleLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
2742 // used to display how many times a surface is lit for level design purposes
2743 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
2744 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
2748 static void R_Shadow_RenderLighting_Light_GLSL(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale, float specularscale)
2750 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2751 R_SetupShader_Surface(lightcolor, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT, texturenumsurfaces, texturesurfacelist, NULL);
2752 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2753 GL_DepthFunc(GL_EQUAL);
2755 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2756 GL_DepthFunc(GL_LEQUAL);
2759 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
2766 int newnumtriangles;
2770 int maxtriangles = 4096;
2771 static int newelements[4096*3];
2772 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, diffusecolor2, ambientcolor2);
2773 for (renders = 0;renders < 4;renders++)
2778 newnumtriangles = 0;
2780 // due to low fillrate on the cards this vertex lighting path is
2781 // designed for, we manually cull all triangles that do not
2782 // contain a lit vertex
2783 // this builds batches of triangles from multiple surfaces and
2784 // renders them at once
2785 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
2787 if (VectorLength2(rsurface.array_passcolor4f + e[0] * 4) + VectorLength2(rsurface.array_passcolor4f + e[1] * 4) + VectorLength2(rsurface.array_passcolor4f + e[2] * 4) >= 0.01)
2789 if (newnumtriangles)
2791 newfirstvertex = min(newfirstvertex, e[0]);
2792 newlastvertex = max(newlastvertex, e[0]);
2796 newfirstvertex = e[0];
2797 newlastvertex = e[0];
2799 newfirstvertex = min(newfirstvertex, e[1]);
2800 newlastvertex = max(newlastvertex, e[1]);
2801 newfirstvertex = min(newfirstvertex, e[2]);
2802 newlastvertex = max(newlastvertex, e[2]);
2808 if (newnumtriangles >= maxtriangles)
2810 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
2811 newnumtriangles = 0;
2817 if (newnumtriangles >= 1)
2819 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
2822 // if we couldn't find any lit triangles, exit early
2825 // now reduce the intensity for the next overbright pass
2826 // we have to clamp to 0 here incase the drivers have improper
2827 // handling of negative colors
2828 // (some old drivers even have improper handling of >1 color)
2830 for (i = 0, c = rsurface.array_passcolor4f + 4 * firstvertex;i < numvertices;i++, c += 4)
2832 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
2834 c[0] = max(0, c[0] - 1);
2835 c[1] = max(0, c[1] - 1);
2836 c[2] = max(0, c[2] - 1);
2848 static void R_Shadow_RenderLighting_Light_Vertex(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale)
2850 // OpenGL 1.1 path (anything)
2851 float ambientcolorbase[3], diffusecolorbase[3];
2852 float ambientcolorpants[3], diffusecolorpants[3];
2853 float ambientcolorshirt[3], diffusecolorshirt[3];
2854 const float *surfacecolor = rsurface.texture->dlightcolor;
2855 const float *surfacepants = rsurface.colormap_pantscolor;
2856 const float *surfaceshirt = rsurface.colormap_shirtcolor;
2857 rtexture_t *basetexture = rsurface.texture->basetexture;
2858 rtexture_t *pantstexture = rsurface.texture->pantstexture;
2859 rtexture_t *shirttexture = rsurface.texture->shirttexture;
2860 qboolean dopants = pantstexture && VectorLength2(surfacepants) >= (1.0f / 1048576.0f);
2861 qboolean doshirt = shirttexture && VectorLength2(surfaceshirt) >= (1.0f / 1048576.0f);
2862 ambientscale *= 2 * r_refdef.view.colorscale;
2863 diffusescale *= 2 * r_refdef.view.colorscale;
2864 ambientcolorbase[0] = lightcolor[0] * ambientscale * surfacecolor[0];ambientcolorbase[1] = lightcolor[1] * ambientscale * surfacecolor[1];ambientcolorbase[2] = lightcolor[2] * ambientscale * surfacecolor[2];
2865 diffusecolorbase[0] = lightcolor[0] * diffusescale * surfacecolor[0];diffusecolorbase[1] = lightcolor[1] * diffusescale * surfacecolor[1];diffusecolorbase[2] = lightcolor[2] * diffusescale * surfacecolor[2];
2866 ambientcolorpants[0] = ambientcolorbase[0] * surfacepants[0];ambientcolorpants[1] = ambientcolorbase[1] * surfacepants[1];ambientcolorpants[2] = ambientcolorbase[2] * surfacepants[2];
2867 diffusecolorpants[0] = diffusecolorbase[0] * surfacepants[0];diffusecolorpants[1] = diffusecolorbase[1] * surfacepants[1];diffusecolorpants[2] = diffusecolorbase[2] * surfacepants[2];
2868 ambientcolorshirt[0] = ambientcolorbase[0] * surfaceshirt[0];ambientcolorshirt[1] = ambientcolorbase[1] * surfaceshirt[1];ambientcolorshirt[2] = ambientcolorbase[2] * surfaceshirt[2];
2869 diffusecolorshirt[0] = diffusecolorbase[0] * surfaceshirt[0];diffusecolorshirt[1] = diffusecolorbase[1] * surfaceshirt[1];diffusecolorshirt[2] = diffusecolorbase[2] * surfaceshirt[2];
2870 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | (diffusescale > 0 ? BATCHNEED_ARRAY_NORMAL : 0) | BATCHNEED_ARRAY_TEXCOORD, texturenumsurfaces, texturesurfacelist);
2871 R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
2872 R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.array_passcolor4f, 0, 0);
2873 R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
2874 R_Mesh_TexBind(0, basetexture);
2875 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
2876 R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
2877 switch(r_shadow_rendermode)
2879 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2880 R_Mesh_TexBind(1, r_shadow_attenuation3dtexture);
2881 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
2882 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
2883 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
2885 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2886 R_Mesh_TexBind(2, r_shadow_attenuation2dtexture);
2887 R_Mesh_TexMatrix(2, &rsurface.entitytoattenuationz);
2888 R_Mesh_TexCombine(2, GL_MODULATE, GL_MODULATE, 1, 1);
2889 R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
2891 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2892 R_Mesh_TexBind(1, r_shadow_attenuation2dtexture);
2893 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
2894 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
2895 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
2897 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2902 //R_Mesh_TexBind(0, basetexture);
2903 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorbase, ambientcolorbase);
2906 R_Mesh_TexBind(0, pantstexture);
2907 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorpants, ambientcolorpants);
2911 R_Mesh_TexBind(0, shirttexture);
2912 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorshirt, ambientcolorshirt);
2916 extern cvar_t gl_lightmaps;
2917 void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
2919 float ambientscale, diffusescale, specularscale;
2921 float lightcolor[3];
2922 VectorCopy(rsurface.rtlight->currentcolor, lightcolor);
2923 ambientscale = rsurface.rtlight->ambientscale;
2924 diffusescale = rsurface.rtlight->diffusescale;
2925 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
2926 if (!r_shadow_usenormalmap.integer)
2928 ambientscale += 1.0f * diffusescale;
2932 if ((ambientscale + diffusescale) * VectorLength2(lightcolor) + specularscale * VectorLength2(lightcolor) < (1.0f / 1048576.0f))
2934 negated = (lightcolor[0] + lightcolor[1] + lightcolor[2] < 0) && vid.support.ext_blend_subtract;
2937 VectorNegate(lightcolor, lightcolor);
2938 switch(vid.renderpath)
2940 case RENDERPATH_GL11:
2941 case RENDERPATH_GL13:
2942 case RENDERPATH_GL20:
2943 case RENDERPATH_CGGL:
2944 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
2946 case RENDERPATH_D3D9:
2948 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_SUBTRACT);
2951 case RENDERPATH_D3D10:
2952 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2954 case RENDERPATH_D3D11:
2955 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2959 RSurf_SetupDepthAndCulling();
2960 switch (r_shadow_rendermode)
2962 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2963 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2964 R_Shadow_RenderLighting_VisibleLighting(texturenumsurfaces, texturesurfacelist);
2966 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2967 R_Shadow_RenderLighting_Light_GLSL(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale, specularscale);
2969 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2970 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2971 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2972 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2973 R_Shadow_RenderLighting_Light_Vertex(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale);
2976 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2981 switch(vid.renderpath)
2983 case RENDERPATH_GL11:
2984 case RENDERPATH_GL13:
2985 case RENDERPATH_GL20:
2986 case RENDERPATH_CGGL:
2987 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
2989 case RENDERPATH_D3D9:
2991 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_ADD);
2994 case RENDERPATH_D3D10:
2995 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2997 case RENDERPATH_D3D11:
2998 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
3004 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)
3006 matrix4x4_t tempmatrix = *matrix;
3007 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
3009 // if this light has been compiled before, free the associated data
3010 R_RTLight_Uncompile(rtlight);
3012 // clear it completely to avoid any lingering data
3013 memset(rtlight, 0, sizeof(*rtlight));
3015 // copy the properties
3016 rtlight->matrix_lighttoworld = tempmatrix;
3017 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
3018 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
3019 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
3020 VectorCopy(color, rtlight->color);
3021 rtlight->cubemapname[0] = 0;
3022 if (cubemapname && cubemapname[0])
3023 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
3024 rtlight->shadow = shadow;
3025 rtlight->corona = corona;
3026 rtlight->style = style;
3027 rtlight->isstatic = isstatic;
3028 rtlight->coronasizescale = coronasizescale;
3029 rtlight->ambientscale = ambientscale;
3030 rtlight->diffusescale = diffusescale;
3031 rtlight->specularscale = specularscale;
3032 rtlight->flags = flags;
3034 // compute derived data
3035 //rtlight->cullradius = rtlight->radius;
3036 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
3037 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3038 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3039 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3040 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3041 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3042 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3045 // compiles rtlight geometry
3046 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
3047 void R_RTLight_Compile(rtlight_t *rtlight)
3050 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
3051 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
3052 entity_render_t *ent = r_refdef.scene.worldentity;
3053 dp_model_t *model = r_refdef.scene.worldmodel;
3054 unsigned char *data;
3057 // compile the light
3058 rtlight->compiled = true;
3059 rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
3060 rtlight->static_numleafs = 0;
3061 rtlight->static_numleafpvsbytes = 0;
3062 rtlight->static_leaflist = NULL;
3063 rtlight->static_leafpvs = NULL;
3064 rtlight->static_numsurfaces = 0;
3065 rtlight->static_surfacelist = NULL;
3066 rtlight->static_shadowmap_receivers = 0x3F;
3067 rtlight->static_shadowmap_casters = 0x3F;
3068 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3069 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3070 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3071 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3072 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3073 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3075 if (model && model->GetLightInfo)
3077 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
3078 r_shadow_compilingrtlight = rtlight;
3079 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);
3080 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
3081 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
3082 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3083 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
3084 rtlight->static_numsurfaces = numsurfaces;
3085 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
3086 rtlight->static_numleafs = numleafs;
3087 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
3088 rtlight->static_numleafpvsbytes = numleafpvsbytes;
3089 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
3090 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
3091 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
3092 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
3093 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3094 if (rtlight->static_numsurfaces)
3095 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3096 if (rtlight->static_numleafs)
3097 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3098 if (rtlight->static_numleafpvsbytes)
3099 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3100 if (rtlight->static_numshadowtrispvsbytes)
3101 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3102 if (rtlight->static_numlighttrispvsbytes)
3103 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3104 switch (rtlight->shadowmode)
3106 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
3107 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
3108 case R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE:
3109 if (model->CompileShadowMap && rtlight->shadow)
3110 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3113 if (model->CompileShadowVolume && rtlight->shadow)
3114 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3117 // now we're done compiling the rtlight
3118 r_shadow_compilingrtlight = NULL;
3122 // use smallest available cullradius - box radius or light radius
3123 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3124 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3126 shadowzpasstris = 0;
3127 if (rtlight->static_meshchain_shadow_zpass)
3128 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
3129 shadowzpasstris += mesh->numtriangles;
3131 shadowzfailtris = 0;
3132 if (rtlight->static_meshchain_shadow_zfail)
3133 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
3134 shadowzfailtris += mesh->numtriangles;
3137 if (rtlight->static_numlighttrispvsbytes)
3138 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3139 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3143 if (rtlight->static_numlighttrispvsbytes)
3144 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3145 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3148 if (developer_extra.integer)
3149 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);
3152 void R_RTLight_Uncompile(rtlight_t *rtlight)
3154 if (rtlight->compiled)
3156 if (rtlight->static_meshchain_shadow_zpass)
3157 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
3158 rtlight->static_meshchain_shadow_zpass = NULL;
3159 if (rtlight->static_meshchain_shadow_zfail)
3160 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
3161 rtlight->static_meshchain_shadow_zfail = NULL;
3162 if (rtlight->static_meshchain_shadow_shadowmap)
3163 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
3164 rtlight->static_meshchain_shadow_shadowmap = NULL;
3165 // these allocations are grouped
3166 if (rtlight->static_surfacelist)
3167 Mem_Free(rtlight->static_surfacelist);
3168 rtlight->static_numleafs = 0;
3169 rtlight->static_numleafpvsbytes = 0;
3170 rtlight->static_leaflist = NULL;
3171 rtlight->static_leafpvs = NULL;
3172 rtlight->static_numsurfaces = 0;
3173 rtlight->static_surfacelist = NULL;
3174 rtlight->static_numshadowtrispvsbytes = 0;
3175 rtlight->static_shadowtrispvs = NULL;
3176 rtlight->static_numlighttrispvsbytes = 0;
3177 rtlight->static_lighttrispvs = NULL;
3178 rtlight->compiled = false;
3182 void R_Shadow_UncompileWorldLights(void)
3186 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3187 for (lightindex = 0;lightindex < range;lightindex++)
3189 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3192 R_RTLight_Uncompile(&light->rtlight);
3196 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3200 // reset the count of frustum planes
3201 // see rtlight->cached_frustumplanes definition for how much this array
3203 rtlight->cached_numfrustumplanes = 0;
3205 // haven't implemented a culling path for ortho rendering
3206 if (!r_refdef.view.useperspective)
3208 // check if the light is on screen and copy the 4 planes if it is
3209 for (i = 0;i < 4;i++)
3210 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3213 for (i = 0;i < 4;i++)
3214 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3219 // generate a deformed frustum that includes the light origin, this is
3220 // used to cull shadow casting surfaces that can not possibly cast a
3221 // shadow onto the visible light-receiving surfaces, which can be a
3224 // if the light origin is onscreen the result will be 4 planes exactly
3225 // if the light origin is offscreen on only one axis the result will
3226 // be exactly 5 planes (split-side case)
3227 // if the light origin is offscreen on two axes the result will be
3228 // exactly 4 planes (stretched corner case)
3229 for (i = 0;i < 4;i++)
3231 // quickly reject standard frustum planes that put the light
3232 // origin outside the frustum
3233 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3236 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3238 // if all the standard frustum planes were accepted, the light is onscreen
3239 // otherwise we need to generate some more planes below...
3240 if (rtlight->cached_numfrustumplanes < 4)
3242 // at least one of the stock frustum planes failed, so we need to
3243 // create one or two custom planes to enclose the light origin
3244 for (i = 0;i < 4;i++)
3246 // create a plane using the view origin and light origin, and a
3247 // single point from the frustum corner set
3248 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3249 VectorNormalize(plane.normal);
3250 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3251 // see if this plane is backwards and flip it if so
3252 for (j = 0;j < 4;j++)
3253 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3257 VectorNegate(plane.normal, plane.normal);
3259 // flipped plane, test again to see if it is now valid
3260 for (j = 0;j < 4;j++)
3261 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3263 // if the plane is still not valid, then it is dividing the
3264 // frustum and has to be rejected
3268 // we have created a valid plane, compute extra info
3269 PlaneClassify(&plane);
3271 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3273 // if we've found 5 frustum planes then we have constructed a
3274 // proper split-side case and do not need to keep searching for
3275 // planes to enclose the light origin
3276 if (rtlight->cached_numfrustumplanes == 5)
3284 for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
3286 plane = rtlight->cached_frustumplanes[i];
3287 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));
3292 // now add the light-space box planes if the light box is rotated, as any
3293 // caster outside the oriented light box is irrelevant (even if it passed
3294 // the worldspace light box, which is axial)
3295 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3297 for (i = 0;i < 6;i++)
3301 v[i >> 1] = (i & 1) ? -1 : 1;
3302 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3303 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3304 plane.dist = VectorNormalizeLength(plane.normal);
3305 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3306 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3312 // add the world-space reduced box planes
3313 for (i = 0;i < 6;i++)
3315 VectorClear(plane.normal);
3316 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3317 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
3318 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3327 // reduce all plane distances to tightly fit the rtlight cull box, which
3329 VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3330 VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3331 VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3332 VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3333 VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3334 VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3335 VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3336 VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3337 oldnum = rtlight->cached_numfrustumplanes;
3338 rtlight->cached_numfrustumplanes = 0;
3339 for (j = 0;j < oldnum;j++)
3341 // find the nearest point on the box to this plane
3342 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
3343 for (i = 1;i < 8;i++)
3345 dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
3346 if (bestdist > dist)
3349 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);
3350 // if the nearest point is near or behind the plane, we want this
3351 // plane, otherwise the plane is useless as it won't cull anything
3352 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
3354 PlaneClassify(&rtlight->cached_frustumplanes[j]);
3355 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
3362 void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
3366 RSurf_ActiveWorldEntity();
3368 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3371 GL_CullFace(GL_NONE);
3372 mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3373 for (;mesh;mesh = mesh->next)
3375 if (!mesh->sidetotals[r_shadow_shadowmapside])
3377 r_refdef.stats.lights_shadowtriangles += mesh->sidetotals[r_shadow_shadowmapside];
3378 R_Mesh_PrepareVertices_Position(mesh->numverts, mesh->vertexposition, mesh->vertexpositionbuffer);
3379 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);
3383 else if (r_refdef.scene.worldentity->model)
3384 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);
3386 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3389 void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3391 qboolean zpass = false;
3394 int surfacelistindex;
3395 msurface_t *surface;
3397 RSurf_ActiveWorldEntity();
3399 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3402 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
3404 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
3405 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
3407 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
3408 for (;mesh;mesh = mesh->next)
3410 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
3411 R_Mesh_PrepareVertices_Position(mesh->numverts, mesh->vertexposition, mesh->vertexpositionbuffer);
3412 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
3414 // increment stencil if frontface is infront of depthbuffer
3415 GL_CullFace(r_refdef.view.cullface_back);
3416 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
3417 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);
3418 // decrement stencil if backface is infront of depthbuffer
3419 GL_CullFace(r_refdef.view.cullface_front);
3420 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
3422 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
3424 // decrement stencil if backface is behind depthbuffer
3425 GL_CullFace(r_refdef.view.cullface_front);
3426 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
3427 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);
3428 // increment stencil if frontface is behind depthbuffer
3429 GL_CullFace(r_refdef.view.cullface_back);
3430 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
3432 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);
3436 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh)
3438 // use the shadow trispvs calculated earlier by GetLightInfo to cull world triangles on this dynamic light
3439 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
3440 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
3442 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
3443 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
3444 if (CHECKPVSBIT(trispvs, t))
3445 shadowmarklist[numshadowmark++] = t;
3447 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);
3449 else if (numsurfaces)
3450 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);
3452 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3455 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3457 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3458 vec_t relativeshadowradius;
3459 RSurf_ActiveModelEntity(ent, false, false, false);
3460 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3461 // we need to re-init the shader for each entity because the matrix changed
3462 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3463 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3464 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3465 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3466 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3467 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3468 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3469 switch (r_shadow_rendermode)
3471 case R_SHADOW_RENDERMODE_SHADOWMAP2D:
3472 case R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE:
3473 case R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE:
3474 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
3477 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3480 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3483 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3485 // set up properties for rendering light onto this entity
3486 RSurf_ActiveModelEntity(ent, true, true, false);
3487 GL_AlphaTest(false);
3488 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3489 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3490 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3491 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3494 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
3496 if (!r_refdef.scene.worldmodel->DrawLight)
3499 // set up properties for rendering light onto this entity
3500 RSurf_ActiveWorldEntity();
3501 GL_AlphaTest(false);
3502 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3503 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3504 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3505 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3507 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
3509 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3512 void R_Shadow_DrawEntityLight(entity_render_t *ent)
3514 dp_model_t *model = ent->model;
3515 if (!model->DrawLight)
3518 R_Shadow_SetupEntityLight(ent);
3520 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3522 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3525 void R_Shadow_PrepareLight(rtlight_t *rtlight)
3529 int numleafs, numsurfaces;
3530 int *leaflist, *surfacelist;
3531 unsigned char *leafpvs;
3532 unsigned char *shadowtrispvs;
3533 unsigned char *lighttrispvs;
3534 //unsigned char *surfacesides;
3535 int numlightentities;
3536 int numlightentities_noselfshadow;
3537 int numshadowentities;
3538 int numshadowentities_noselfshadow;
3539 static entity_render_t *lightentities[MAX_EDICTS];
3540 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3541 static entity_render_t *shadowentities[MAX_EDICTS];
3542 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3545 rtlight->draw = false;
3547 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3548 // skip lights that are basically invisible (color 0 0 0)
3549 nolight = VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f);
3551 // loading is done before visibility checks because loading should happen
3552 // all at once at the start of a level, not when it stalls gameplay.
3553 // (especially important to benchmarks)
3555 if (rtlight->isstatic && !nolight && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
3557 if (rtlight->compiled)
3558 R_RTLight_Uncompile(rtlight);
3559 R_RTLight_Compile(rtlight);
3563 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
3565 // look up the light style value at this time
3566 f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3567 VectorScale(rtlight->color, f, rtlight->currentcolor);
3569 if (rtlight->selected)
3571 f = 2 + sin(realtime * M_PI * 4.0);
3572 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3576 // if lightstyle is currently off, don't draw the light
3577 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3580 // skip processing on corona-only lights
3584 // if the light box is offscreen, skip it
3585 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3588 VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
3589 VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
3591 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3593 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3595 // compiled light, world available and can receive realtime lighting
3596 // retrieve leaf information
3597 numleafs = rtlight->static_numleafs;
3598 leaflist = rtlight->static_leaflist;
3599 leafpvs = rtlight->static_leafpvs;
3600 numsurfaces = rtlight->static_numsurfaces;
3601 surfacelist = rtlight->static_surfacelist;
3602 //surfacesides = NULL;
3603 shadowtrispvs = rtlight->static_shadowtrispvs;
3604 lighttrispvs = rtlight->static_lighttrispvs;
3606 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3608 // dynamic light, world available and can receive realtime lighting
3609 // calculate lit surfaces and leafs
3610 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);
3611 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3612 leaflist = r_shadow_buffer_leaflist;
3613 leafpvs = r_shadow_buffer_leafpvs;
3614 surfacelist = r_shadow_buffer_surfacelist;
3615 //surfacesides = r_shadow_buffer_surfacesides;
3616 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3617 lighttrispvs = r_shadow_buffer_lighttrispvs;
3618 // if the reduced leaf bounds are offscreen, skip it
3619 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3630 //surfacesides = NULL;
3631 shadowtrispvs = NULL;
3632 lighttrispvs = NULL;
3634 // check if light is illuminating any visible leafs
3637 for (i = 0;i < numleafs;i++)
3638 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3644 // make a list of lit entities and shadow casting entities
3645 numlightentities = 0;
3646 numlightentities_noselfshadow = 0;
3647 numshadowentities = 0;
3648 numshadowentities_noselfshadow = 0;
3650 // add dynamic entities that are lit by the light
3651 for (i = 0;i < r_refdef.scene.numentities;i++)
3654 entity_render_t *ent = r_refdef.scene.entities[i];
3656 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3658 // skip the object entirely if it is not within the valid
3659 // shadow-casting region (which includes the lit region)
3660 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
3662 if (!(model = ent->model))
3664 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
3666 // this entity wants to receive light, is visible, and is
3667 // inside the light box
3668 // TODO: check if the surfaces in the model can receive light
3669 // so now check if it's in a leaf seen by the light
3670 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))
3672 if (ent->flags & RENDER_NOSELFSHADOW)
3673 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
3675 lightentities[numlightentities++] = ent;
3676 // since it is lit, it probably also casts a shadow...
3677 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3678 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3679 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3681 // note: exterior models without the RENDER_NOSELFSHADOW
3682 // flag still create a RENDER_NOSELFSHADOW shadow but
3683 // are lit normally, this means that they are
3684 // self-shadowing but do not shadow other
3685 // RENDER_NOSELFSHADOW entities such as the gun
3686 // (very weird, but keeps the player shadow off the gun)
3687 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3688 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3690 shadowentities[numshadowentities++] = ent;
3693 else if (ent->flags & RENDER_SHADOW)
3695 // this entity is not receiving light, but may still need to
3697 // TODO: check if the surfaces in the model can cast shadow
3698 // now check if it is in a leaf seen by the light
3699 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))
3701 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3702 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3703 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3705 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3706 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3708 shadowentities[numshadowentities++] = ent;
3713 // return if there's nothing at all to light
3714 if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
3717 // count this light in the r_speeds
3718 r_refdef.stats.lights++;
3720 // flag it as worth drawing later
3721 rtlight->draw = true;
3723 // cache all the animated entities that cast a shadow but are not visible
3724 for (i = 0;i < numshadowentities;i++)
3725 if (!shadowentities[i]->animcache_vertex3f)
3726 R_AnimCache_GetEntity(shadowentities[i], false, false);
3727 for (i = 0;i < numshadowentities_noselfshadow;i++)
3728 if (!shadowentities_noselfshadow[i]->animcache_vertex3f)
3729 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
3731 // allocate some temporary memory for rendering this light later in the frame
3732 // reusable buffers need to be copied, static data can be used as-is
3733 rtlight->cached_numlightentities = numlightentities;
3734 rtlight->cached_numlightentities_noselfshadow = numlightentities_noselfshadow;
3735 rtlight->cached_numshadowentities = numshadowentities;
3736 rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
3737 rtlight->cached_numsurfaces = numsurfaces;
3738 rtlight->cached_lightentities = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
3739 rtlight->cached_lightentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
3740 rtlight->cached_shadowentities = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
3741 rtlight->cached_shadowentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
3742 if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
3744 int numshadowtrispvsbytes = (((r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles) + 7) >> 3);
3745 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
3746 rtlight->cached_shadowtrispvs = (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
3747 rtlight->cached_lighttrispvs = (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
3748 rtlight->cached_surfacelist = (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
3752 // compiled light data
3753 rtlight->cached_shadowtrispvs = shadowtrispvs;
3754 rtlight->cached_lighttrispvs = lighttrispvs;
3755 rtlight->cached_surfacelist = surfacelist;
3759 void R_Shadow_DrawLight(rtlight_t *rtlight)
3763 unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
3764 int numlightentities;
3765 int numlightentities_noselfshadow;
3766 int numshadowentities;
3767 int numshadowentities_noselfshadow;
3768 entity_render_t **lightentities;
3769 entity_render_t **lightentities_noselfshadow;
3770 entity_render_t **shadowentities;
3771 entity_render_t **shadowentities_noselfshadow;
3773 static unsigned char entitysides[MAX_EDICTS];
3774 static unsigned char entitysides_noselfshadow[MAX_EDICTS];
3775 vec3_t nearestpoint;
3777 qboolean castshadows;
3780 // check if we cached this light this frame (meaning it is worth drawing)
3784 // if R_FrameData_Store ran out of space we skip anything dependent on it
3785 if (r_framedata_failed)
3788 numlightentities = rtlight->cached_numlightentities;
3789 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
3790 numshadowentities = rtlight->cached_numshadowentities;
3791 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
3792 numsurfaces = rtlight->cached_numsurfaces;
3793 lightentities = rtlight->cached_lightentities;
3794 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
3795 shadowentities = rtlight->cached_shadowentities;
3796 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
3797 shadowtrispvs = rtlight->cached_shadowtrispvs;
3798 lighttrispvs = rtlight->cached_lighttrispvs;
3799 surfacelist = rtlight->cached_surfacelist;
3801 // set up a scissor rectangle for this light
3802 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3805 // don't let sound skip if going slow
3806 if (r_refdef.scene.extraupdate)
3809 // make this the active rtlight for rendering purposes
3810 R_Shadow_RenderMode_ActiveLight(rtlight);
3812 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
3814 // optionally draw visible shape of the shadow volumes
3815 // for performance analysis by level designers
3816 R_Shadow_RenderMode_VisibleShadowVolumes();
3818 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
3819 for (i = 0;i < numshadowentities;i++)
3820 R_Shadow_DrawEntityShadow(shadowentities[i]);
3821 for (i = 0;i < numshadowentities_noselfshadow;i++)
3822 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3823 R_Shadow_RenderMode_VisibleLighting(false, false);
3826 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
3828 // optionally draw the illuminated areas
3829 // for performance analysis by level designers
3830 R_Shadow_RenderMode_VisibleLighting(false, false);
3832 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3833 for (i = 0;i < numlightentities;i++)
3834 R_Shadow_DrawEntityLight(lightentities[i]);
3835 for (i = 0;i < numlightentities_noselfshadow;i++)
3836 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3839 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
3841 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
3842 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
3843 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
3844 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
3846 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance/rtlight->radius));
3847 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
3848 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
3850 if (castshadows && (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE))
3856 int receivermask = 0;
3857 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
3858 Matrix4x4_Abs(&radiustolight);
3860 r_shadow_shadowmaplod = 0;
3861 for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
3862 if ((r_shadow_shadowmapmaxsize >> i) > lodlinear)
3863 r_shadow_shadowmaplod = i;
3865 if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
3866 size = max(1, r_shadow_shadowmapmaxsize >> r_shadow_shadowmaplod);
3868 size = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
3870 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
3872 surfacesides = NULL;
3875 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3877 castermask = rtlight->static_shadowmap_casters;
3878 receivermask = rtlight->static_shadowmap_receivers;
3882 surfacesides = r_shadow_buffer_surfacesides;
3883 for(i = 0;i < numsurfaces;i++)
3885 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
3886 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3887 castermask |= surfacesides[i];
3888 receivermask |= surfacesides[i];
3892 if (receivermask < 0x3F)
3894 for (i = 0;i < numlightentities;i++)
3895 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3896 if (receivermask < 0x3F)
3897 for(i = 0; i < numlightentities_noselfshadow;i++)
3898 receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3901 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
3905 for (i = 0;i < numshadowentities;i++)
3906 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3907 for (i = 0;i < numshadowentities_noselfshadow;i++)
3908 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3911 //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
3913 // render shadow casters into 6 sided depth texture
3914 for (side = 0;side < 6;side++) if (receivermask & (1 << side))
3916 R_Shadow_RenderMode_ShadowMap(side, receivermask, size);
3917 if (! (castermask & (1 << side))) continue;
3919 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
3920 for (i = 0;i < numshadowentities;i++) if (entitysides[i] & (1 << side))
3921 R_Shadow_DrawEntityShadow(shadowentities[i]);
3924 if (numlightentities_noselfshadow)
3926 // render lighting using the depth texture as shadowmap
3927 // draw lighting in the unmasked areas
3928 R_Shadow_RenderMode_Lighting(false, false, true);
3929 for (i = 0;i < numlightentities_noselfshadow;i++)
3930 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3933 // render shadow casters into 6 sided depth texture
3934 if (numshadowentities_noselfshadow)
3936 for (side = 0;side < 6;side++) if ((receivermask & castermask) & (1 << side))
3938 R_Shadow_RenderMode_ShadowMap(side, 0, size);
3939 for (i = 0;i < numshadowentities_noselfshadow;i++) if (entitysides_noselfshadow[i] & (1 << side))
3940 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3944 // render lighting using the depth texture as shadowmap
3945 // draw lighting in the unmasked areas
3946 R_Shadow_RenderMode_Lighting(false, false, true);
3947 // draw lighting in the unmasked areas
3949 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3950 for (i = 0;i < numlightentities;i++)
3951 R_Shadow_DrawEntityLight(lightentities[i]);
3953 else if (castshadows && vid.stencil)
3955 // draw stencil shadow volumes to mask off pixels that are in shadow
3956 // so that they won't receive lighting
3957 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
3958 R_Shadow_ClearStencil();
3961 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
3962 for (i = 0;i < numshadowentities;i++)
3963 R_Shadow_DrawEntityShadow(shadowentities[i]);
3965 // draw lighting in the unmasked areas
3966 R_Shadow_RenderMode_Lighting(true, false, false);
3967 for (i = 0;i < numlightentities_noselfshadow;i++)
3968 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3970 for (i = 0;i < numshadowentities_noselfshadow;i++)
3971 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3973 // draw lighting in the unmasked areas
3974 R_Shadow_RenderMode_Lighting(true, false, false);
3976 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3977 for (i = 0;i < numlightentities;i++)
3978 R_Shadow_DrawEntityLight(lightentities[i]);
3982 // draw lighting in the unmasked areas
3983 R_Shadow_RenderMode_Lighting(false, false, false);
3985 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3986 for (i = 0;i < numlightentities;i++)
3987 R_Shadow_DrawEntityLight(lightentities[i]);
3988 for (i = 0;i < numlightentities_noselfshadow;i++)
3989 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3992 if (r_shadow_usingdeferredprepass)
3994 // when rendering deferred lighting, we simply rasterize the box
3995 if (castshadows && (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE))
3996 R_Shadow_RenderMode_DrawDeferredLight(false, true);
3997 else if (castshadows && vid.stencil)
3998 R_Shadow_RenderMode_DrawDeferredLight(true, false);
4000 R_Shadow_RenderMode_DrawDeferredLight(false, false);
4004 static void R_Shadow_FreeDeferred(void)
4006 R_Mesh_DestroyFramebufferObject(r_shadow_prepassgeometryfbo);
4007 r_shadow_prepassgeometryfbo = 0;
4009 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingfbo);
4010 r_shadow_prepasslightingfbo = 0;
4012 if (r_shadow_prepassgeometrydepthtexture)
4013 R_FreeTexture(r_shadow_prepassgeometrydepthtexture);
4014 r_shadow_prepassgeometrydepthtexture = NULL;
4016 if (r_shadow_prepassgeometrynormalmaptexture)
4017 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
4018 r_shadow_prepassgeometrynormalmaptexture = NULL;
4020 if (r_shadow_prepasslightingdiffusetexture)
4021 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
4022 r_shadow_prepasslightingdiffusetexture = NULL;
4024 if (r_shadow_prepasslightingspeculartexture)
4025 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
4026 r_shadow_prepasslightingspeculartexture = NULL;
4029 void R_Shadow_DrawPrepass(void)
4037 entity_render_t *ent;
4038 float clearcolor[4];
4040 GL_AlphaTest(false);
4041 R_Mesh_ResetTextureState();
4043 GL_ColorMask(1,1,1,1);
4044 GL_BlendFunc(GL_ONE, GL_ZERO);
4047 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4048 Vector4Set(clearcolor, 0.5f,0.5f,0.5f,1.0f);
4049 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, clearcolor, 1.0f, 0);
4050 if (r_timereport_active)
4051 R_TimeReport("prepasscleargeom");
4053 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
4054 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
4055 if (r_timereport_active)
4056 R_TimeReport("prepassworld");
4058 for (i = 0;i < r_refdef.scene.numentities;i++)
4060 if (!r_refdef.viewcache.entityvisible[i])
4062 ent = r_refdef.scene.entities[i];
4063 if (ent->model && ent->model->DrawPrepass != NULL)
4064 ent->model->DrawPrepass(ent);
4067 if (r_timereport_active)
4068 R_TimeReport("prepassmodels");
4070 GL_DepthMask(false);
4071 GL_ColorMask(1,1,1,1);
4074 R_Mesh_SetRenderTargets(r_shadow_prepasslightingfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4075 Vector4Set(clearcolor, 0, 0, 0, 0);
4076 GL_Clear(GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
4077 if (r_timereport_active)
4078 R_TimeReport("prepassclearlit");
4080 R_Shadow_RenderMode_Begin();
4082 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4083 if (r_shadow_debuglight.integer >= 0)
4085 lightindex = r_shadow_debuglight.integer;
4086 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4087 if (light && (light->flags & flag))
4088 R_Shadow_DrawLight(&light->rtlight);
4092 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4093 for (lightindex = 0;lightindex < range;lightindex++)
4095 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4096 if (light && (light->flags & flag))
4097 R_Shadow_DrawLight(&light->rtlight);
4100 if (r_refdef.scene.rtdlight)
4101 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4102 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4104 R_Mesh_ResetRenderTargets();
4106 R_Shadow_RenderMode_End();
4108 if (r_timereport_active)
4109 R_TimeReport("prepasslights");
4112 void R_Shadow_DrawLightSprites(void);
4113 void R_Shadow_PrepareLights(void)
4123 if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4) ||
4124 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
4125 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0) ||
4126 r_shadow_shadowmaptexturetype != r_shadow_shadowmapping_texturetype.integer ||
4127 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
4128 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
4129 r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
4130 R_Shadow_FreeShadowMaps();
4132 r_shadow_usingshadowmaportho = false;
4134 switch (vid.renderpath)
4136 case RENDERPATH_GL20:
4137 case RENDERPATH_CGGL:
4138 case RENDERPATH_D3D9:
4139 case RENDERPATH_D3D10:
4140 case RENDERPATH_D3D11:
4141 if (!r_shadow_deferred.integer || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_STENCIL || !vid.support.ext_framebuffer_object || vid.maxdrawbuffers < 2)
4143 r_shadow_usingdeferredprepass = false;
4144 if (r_shadow_prepass_width)
4145 R_Shadow_FreeDeferred();
4146 r_shadow_prepass_width = r_shadow_prepass_height = 0;
4150 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
4152 R_Shadow_FreeDeferred();
4154 r_shadow_usingdeferredprepass = true;
4155 r_shadow_prepass_width = vid.width;
4156 r_shadow_prepass_height = vid.height;
4157 r_shadow_prepassgeometrydepthtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "prepassgeometrydepthmap", vid.width, vid.height, 24, false);
4158 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);
4159 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);
4160 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);
4162 // set up the geometry pass fbo (depth + normalmap)
4163 r_shadow_prepassgeometryfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4164 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4165 // render depth into one texture and normalmap into the other
4166 if (qglDrawBuffersARB)
4168 qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);CHECKGLERROR
4169 qglReadBuffer(GL_NONE);CHECKGLERROR
4170 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4171 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4173 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4174 Cvar_SetValueQuick(&r_shadow_deferred, 0);
4175 r_shadow_usingdeferredprepass = false;
4179 // set up the lighting pass fbo (diffuse + specular)
4180 r_shadow_prepasslightingfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4181 R_Mesh_SetRenderTargets(r_shadow_prepasslightingfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4182 // render diffuse into one texture and specular into another,
4183 // with depth and normalmap bound as textures,
4184 // with depth bound as attachment as well
4185 if (qglDrawBuffersARB)
4187 qglDrawBuffersARB(2, r_shadow_prepasslightingdrawbuffers);CHECKGLERROR
4188 qglReadBuffer(GL_NONE);CHECKGLERROR
4189 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4190 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4192 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4193 Cvar_SetValueQuick(&r_shadow_deferred, 0);
4194 r_shadow_usingdeferredprepass = false;
4199 case RENDERPATH_GL13:
4200 case RENDERPATH_GL11:
4201 r_shadow_usingdeferredprepass = false;
4205 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);
4207 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4208 if (r_shadow_debuglight.integer >= 0)
4210 lightindex = r_shadow_debuglight.integer;
4211 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4212 if (light && (light->flags & flag))
4213 R_Shadow_PrepareLight(&light->rtlight);
4217 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4218 for (lightindex = 0;lightindex < range;lightindex++)
4220 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4221 if (light && (light->flags & flag))
4222 R_Shadow_PrepareLight(&light->rtlight);
4225 if (r_refdef.scene.rtdlight)
4227 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4228 R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
4230 else if(gl_flashblend.integer)
4232 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4234 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
4235 f = (rtlight->style >= 0 ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4236 VectorScale(rtlight->color, f, rtlight->currentcolor);
4240 if (r_editlights.integer)
4241 R_Shadow_DrawLightSprites();
4244 void R_Shadow_DrawLights(void)
4252 R_Shadow_RenderMode_Begin();
4254 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4255 if (r_shadow_debuglight.integer >= 0)
4257 lightindex = r_shadow_debuglight.integer;
4258 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4259 if (light && (light->flags & flag))
4260 R_Shadow_DrawLight(&light->rtlight);
4264 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4265 for (lightindex = 0;lightindex < range;lightindex++)
4267 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4268 if (light && (light->flags & flag))
4269 R_Shadow_DrawLight(&light->rtlight);
4272 if (r_refdef.scene.rtdlight)
4273 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4274 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4276 R_Shadow_RenderMode_End();
4279 extern const float r_screenvertex3f[12];
4280 extern void R_SetupView(qboolean allowwaterclippingplane);
4281 extern void R_ResetViewRendering3D(void);
4282 extern void R_ResetViewRendering2D(void);
4283 extern cvar_t r_shadows;
4284 extern cvar_t r_shadows_darken;
4285 extern cvar_t r_shadows_drawafterrtlighting;
4286 extern cvar_t r_shadows_castfrombmodels;
4287 extern cvar_t r_shadows_throwdistance;
4288 extern cvar_t r_shadows_throwdirection;
4289 extern cvar_t r_shadows_focus;
4290 extern cvar_t r_shadows_shadowmapscale;
4292 void R_Shadow_PrepareModelShadows(void)
4295 float scale, size, radius, dot1, dot2;
4296 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
4297 entity_render_t *ent;
4299 if (!r_refdef.scene.numentities)
4302 switch (r_shadow_shadowmode)
4304 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4305 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
4306 if (r_shadows.integer >= 2)
4309 case R_SHADOW_SHADOWMODE_STENCIL:
4310 for (i = 0;i < r_refdef.scene.numentities;i++)
4312 ent = r_refdef.scene.entities[i];
4313 if (!ent->animcache_vertex3f && ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4314 R_AnimCache_GetEntity(ent, false, false);
4321 size = 2*r_shadow_shadowmapmaxsize;
4322 scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
4323 radius = 0.5f * size / scale;
4325 Math_atov(r_shadows_throwdirection.string, shadowdir);
4326 VectorNormalize(shadowdir);
4327 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4328 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4329 if (fabs(dot1) <= fabs(dot2))
4330 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4332 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4333 VectorNormalize(shadowforward);
4334 CrossProduct(shadowdir, shadowforward, shadowright);
4335 Math_atov(r_shadows_focus.string, shadowfocus);
4336 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4337 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4338 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4339 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4340 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4342 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4344 shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4345 shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4346 shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4347 shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4348 shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4349 shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4351 for (i = 0;i < r_refdef.scene.numentities;i++)
4353 ent = r_refdef.scene.entities[i];
4354 if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
4356 // cast shadows from anything of the map (submodels are optional)
4357 if (!ent->animcache_vertex3f && ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4358 R_AnimCache_GetEntity(ent, false, false);
4362 void R_DrawModelShadowMaps(void)
4365 float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
4366 entity_render_t *ent;
4367 vec3_t relativelightorigin;
4368 vec3_t relativelightdirection, relativeforward, relativeright;
4369 vec3_t relativeshadowmins, relativeshadowmaxs;
4370 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
4372 matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
4373 r_viewport_t viewport;
4375 float clearcolor[4];
4377 if (!r_refdef.scene.numentities)
4380 switch (r_shadow_shadowmode)
4382 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4383 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
4389 R_ResetViewRendering3D();
4390 R_Shadow_RenderMode_Begin();
4391 R_Shadow_RenderMode_ActiveLight(NULL);
4393 switch (r_shadow_shadowmode)
4395 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4396 if (!r_shadow_shadowmap2dtexture)
4397 R_Shadow_MakeShadowMap(0, r_shadow_shadowmapmaxsize);
4398 fbo = r_shadow_fbo2d;
4399 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
4400 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
4401 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
4403 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
4404 if (!r_shadow_shadowmaprectangletexture)
4405 R_Shadow_MakeShadowMap(0, r_shadow_shadowmapmaxsize);
4406 fbo = r_shadow_fborectangle;
4407 r_shadow_shadowmap_texturescale[0] = 1.0f;
4408 r_shadow_shadowmap_texturescale[1] = 1.0f;
4409 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE;
4415 size = 2*r_shadow_shadowmapmaxsize;
4416 scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
4417 radius = 0.5f / scale;
4418 nearclip = -r_shadows_throwdistance.value;
4419 farclip = r_shadows_throwdistance.value;
4420 bias = r_shadow_shadowmapping_bias.value * r_shadow_shadowmapping_nearclip.value / (2 * r_shadows_throwdistance.value) * (1024.0f / size);
4422 r_shadow_shadowmap_parameters[0] = size;
4423 r_shadow_shadowmap_parameters[1] = size;
4424 r_shadow_shadowmap_parameters[2] = 1.0;
4425 r_shadow_shadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
4427 Math_atov(r_shadows_throwdirection.string, shadowdir);
4428 VectorNormalize(shadowdir);
4429 Math_atov(r_shadows_focus.string, shadowfocus);
4430 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4431 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4432 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4433 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4434 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4435 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4436 if (fabs(dot1) <= fabs(dot2))
4437 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4439 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4440 VectorNormalize(shadowforward);
4441 VectorM(scale, shadowforward, &m[0]);
4442 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4444 m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
4445 CrossProduct(shadowdir, shadowforward, shadowright);
4446 VectorM(scale, shadowright, &m[4]);
4447 m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
4448 VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
4449 m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
4450 Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
4451 Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
4452 R_Viewport_InitOrtho(&viewport, &cameramatrix, 0, 0, size, size, 0, 0, 1, 1, 0, -1, NULL);
4454 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4456 R_Mesh_SetRenderTargets(fbo, r_shadow_shadowmap2dtexture, NULL, NULL, NULL, NULL);
4457 R_SetupShader_DepthOrShadow();
4458 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
4461 R_SetViewport(&viewport);
4462 GL_Scissor(viewport.x, viewport.y, min(viewport.width + r_shadow_shadowmapborder, 2*r_shadow_shadowmapmaxsize), viewport.height + r_shadow_shadowmapborder);
4463 Vector4Set(clearcolor, 1,1,1,1);
4464 // in D3D9 we have to render to a color texture shadowmap
4465 // in GL we render directly to a depth texture only
4466 if (r_shadow_shadowmap2dtexture)
4467 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4469 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4470 // render into a slightly restricted region so that the borders of the
4471 // shadowmap area fade away, rather than streaking across everything
4472 // outside the usable area
4473 GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
4477 R_Mesh_ResetRenderTargets();
4478 R_SetupShader_ShowDepth();
4479 GL_ColorMask(1,1,1,1);
4480 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4483 for (i = 0;i < r_refdef.scene.numentities;i++)
4485 ent = r_refdef.scene.entities[i];
4487 // cast shadows from anything of the map (submodels are optional)
4488 if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4490 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4491 Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
4492 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4493 Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
4494 Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
4495 relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4496 relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4497 relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4498 relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4499 relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4500 relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4501 RSurf_ActiveModelEntity(ent, false, false, false);
4502 ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
4503 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4510 unsigned char *rawpixels = Z_Malloc(viewport.width*viewport.height*4);
4512 qglReadPixels(viewport.x, viewport.y, viewport.width, viewport.height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, rawpixels);
4514 Image_WriteTGABGRA("r_shadows_2.tga", viewport.width, viewport.height, rawpixels);
4515 Cvar_SetValueQuick(&r_test, 0);
4520 R_Shadow_RenderMode_End();
4522 Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
4523 Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
4524 Matrix4x4_CreateScale3(&scalematrix, size, -size, 1);
4525 Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
4526 Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
4527 Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
4529 r_shadow_usingshadowmaportho = true;
4530 switch (r_shadow_shadowmode)
4532 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4533 r_shadow_usingshadowmap2d = true;
4535 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
4536 r_shadow_usingshadowmaprect = true;
4543 void R_DrawModelShadows(void)
4546 float relativethrowdistance;
4547 entity_render_t *ent;
4548 vec3_t relativelightorigin;
4549 vec3_t relativelightdirection;
4550 vec3_t relativeshadowmins, relativeshadowmaxs;
4551 vec3_t tmp, shadowdir;
4553 if (!r_refdef.scene.numentities || !vid.stencil || (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL && r_shadows.integer != 1))
4556 R_ResetViewRendering3D();
4557 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4558 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4559 R_Shadow_RenderMode_Begin();
4560 R_Shadow_RenderMode_ActiveLight(NULL);
4561 r_shadow_lightscissor[0] = r_refdef.view.x;
4562 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
4563 r_shadow_lightscissor[2] = r_refdef.view.width;
4564 r_shadow_lightscissor[3] = r_refdef.view.height;
4565 R_Shadow_RenderMode_StencilShadowVolumes(false);
4568 if (r_shadows.integer == 2)
4570 Math_atov(r_shadows_throwdirection.string, shadowdir);
4571 VectorNormalize(shadowdir);
4574 R_Shadow_ClearStencil();
4576 for (i = 0;i < r_refdef.scene.numentities;i++)
4578 ent = r_refdef.scene.entities[i];
4580 // cast shadows from anything of the map (submodels are optional)
4581 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4583 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4584 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
4585 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
4586 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
4587 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4590 if(ent->entitynumber != 0)
4592 if(ent->entitynumber >= MAX_EDICTS) // csqc entity
4594 // FIXME handle this
4595 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4599 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
4600 int entnum, entnum2, recursion;
4601 entnum = entnum2 = ent->entitynumber;
4602 for(recursion = 32; recursion > 0; --recursion)
4604 entnum2 = cl.entities[entnum].state_current.tagentity;
4605 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
4610 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
4612 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
4613 // transform into modelspace of OUR entity
4614 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
4615 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
4618 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4622 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4625 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
4626 RSurf_ActiveModelEntity(ent, false, false, false);
4627 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4628 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4632 // not really the right mode, but this will disable any silly stencil features
4633 R_Shadow_RenderMode_End();
4635 // set up ortho view for rendering this pass
4636 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4637 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4638 //GL_ScissorTest(true);
4639 //R_EntityMatrix(&identitymatrix);
4640 //R_Mesh_ResetTextureState();
4641 R_ResetViewRendering2D();
4643 // set up a darkening blend on shadowed areas
4644 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4645 //GL_DepthRange(0, 1);
4646 //GL_DepthTest(false);
4647 //GL_DepthMask(false);
4648 //GL_PolygonOffset(0, 0);CHECKGLERROR
4649 GL_Color(0, 0, 0, r_shadows_darken.value);
4650 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4651 //GL_DepthFunc(GL_ALWAYS);
4652 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_NOTEQUAL, 128, 255);
4654 // apply the blend to the shadowed areas
4655 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, NULL);
4656 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
4657 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4659 // restore the viewport
4660 R_SetViewport(&r_refdef.view.viewport);
4662 // restore other state to normal
4663 //R_Shadow_RenderMode_End();
4666 void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4669 vec3_t centerorigin;
4671 // if it's too close, skip it
4672 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
4674 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4677 if (usequery && r_numqueries + 2 <= r_maxqueries)
4679 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4680 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4681 // 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
4682 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4684 switch(vid.renderpath)
4686 case RENDERPATH_GL20:
4687 case RENDERPATH_GL13:
4688 case RENDERPATH_GL11:
4689 case RENDERPATH_CGGL:
4691 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use GL_DepthFunc instead
4692 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
4693 GL_DepthFunc(GL_ALWAYS);
4694 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4695 R_Mesh_PrepareVertices_Position_Arrays(4, vertex3f);
4696 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4697 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4698 GL_DepthFunc(GL_LEQUAL);
4699 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
4700 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4701 R_Mesh_PrepareVertices_Position_Arrays(4, vertex3f);
4702 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4703 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4706 case RENDERPATH_D3D9:
4707 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4709 case RENDERPATH_D3D10:
4710 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4712 case RENDERPATH_D3D11:
4713 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4717 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4720 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
4722 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4725 GLint allpixels = 0, visiblepixels = 0;
4726 // now we have to check the query result
4727 if (rtlight->corona_queryindex_visiblepixels)
4729 switch(vid.renderpath)
4731 case RENDERPATH_GL20:
4732 case RENDERPATH_GL13:
4733 case RENDERPATH_GL11:
4734 case RENDERPATH_CGGL:
4736 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
4737 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
4740 case RENDERPATH_D3D9:
4741 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4743 case RENDERPATH_D3D10:
4744 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4746 case RENDERPATH_D3D11:
4747 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4750 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
4751 if (visiblepixels < 1 || allpixels < 1)
4753 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
4754 cscale *= rtlight->corona_visibility;
4758 // FIXME: these traces should scan all render entities instead of cl.world
4759 if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
4762 VectorScale(rtlight->currentcolor, cscale, color);
4763 if (VectorLength(color) > (1.0f / 256.0f))
4766 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
4769 VectorNegate(color, color);
4770 switch(vid.renderpath)
4772 case RENDERPATH_GL11:
4773 case RENDERPATH_GL13:
4774 case RENDERPATH_GL20:
4775 case RENDERPATH_CGGL:
4776 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
4778 case RENDERPATH_D3D9:
4780 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_SUBTRACT);
4783 case RENDERPATH_D3D10:
4784 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4786 case RENDERPATH_D3D11:
4787 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4791 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4792 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);
4793 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4796 switch(vid.renderpath)
4798 case RENDERPATH_GL11:
4799 case RENDERPATH_GL13:
4800 case RENDERPATH_GL20:
4801 case RENDERPATH_CGGL:
4802 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
4804 case RENDERPATH_D3D9:
4806 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_ADD);
4809 case RENDERPATH_D3D10:
4810 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4812 case RENDERPATH_D3D11:
4813 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4820 void R_Shadow_DrawCoronas(void)
4823 qboolean usequery = false;
4828 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4830 if (r_waterstate.renderingscene)
4832 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4833 R_EntityMatrix(&identitymatrix);
4835 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4837 // check occlusion of coronas
4838 // use GL_ARB_occlusion_query if available
4839 // otherwise use raytraces
4841 switch (vid.renderpath)
4843 case RENDERPATH_GL11:
4844 case RENDERPATH_GL13:
4845 case RENDERPATH_GL20:
4846 case RENDERPATH_CGGL:
4847 usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
4850 GL_ColorMask(0,0,0,0);
4851 if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
4852 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
4855 r_maxqueries = (range + r_refdef.scene.numlights) * 4;
4856 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
4858 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
4861 RSurf_ActiveWorldEntity();
4862 GL_BlendFunc(GL_ONE, GL_ZERO);
4863 GL_CullFace(GL_NONE);
4864 GL_DepthMask(false);
4865 GL_DepthRange(0, 1);
4866 GL_PolygonOffset(0, 0);
4868 R_Mesh_ResetTextureState();
4869 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
4872 case RENDERPATH_D3D9:
4874 //Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4876 case RENDERPATH_D3D10:
4877 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4879 case RENDERPATH_D3D11:
4880 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4883 for (lightindex = 0;lightindex < range;lightindex++)
4885 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4888 rtlight = &light->rtlight;
4889 rtlight->corona_visibility = 0;
4890 rtlight->corona_queryindex_visiblepixels = 0;
4891 rtlight->corona_queryindex_allpixels = 0;
4892 if (!(rtlight->flags & flag))
4894 if (rtlight->corona <= 0)
4896 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4898 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4900 for (i = 0;i < r_refdef.scene.numlights;i++)
4902 rtlight = r_refdef.scene.lights[i];
4903 rtlight->corona_visibility = 0;
4904 rtlight->corona_queryindex_visiblepixels = 0;
4905 rtlight->corona_queryindex_allpixels = 0;
4906 if (!(rtlight->flags & flag))
4908 if (rtlight->corona <= 0)
4910 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4913 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4915 // now draw the coronas using the query data for intensity info
4916 for (lightindex = 0;lightindex < range;lightindex++)
4918 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4921 rtlight = &light->rtlight;
4922 if (rtlight->corona_visibility <= 0)
4924 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4926 for (i = 0;i < r_refdef.scene.numlights;i++)
4928 rtlight = r_refdef.scene.lights[i];
4929 if (rtlight->corona_visibility <= 0)
4931 if (gl_flashblend.integer)
4932 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4934 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4940 dlight_t *R_Shadow_NewWorldLight(void)
4942 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4945 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)
4948 // validate parameters
4949 if (style < 0 || style >= MAX_LIGHTSTYLES)
4951 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
4957 // copy to light properties
4958 VectorCopy(origin, light->origin);
4959 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4960 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4961 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4963 light->color[0] = max(color[0], 0);
4964 light->color[1] = max(color[1], 0);
4965 light->color[2] = max(color[2], 0);
4967 light->color[0] = color[0];
4968 light->color[1] = color[1];
4969 light->color[2] = color[2];
4970 light->radius = max(radius, 0);
4971 light->style = style;
4972 light->shadow = shadowenable;
4973 light->corona = corona;
4974 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4975 light->coronasizescale = coronasizescale;
4976 light->ambientscale = ambientscale;
4977 light->diffusescale = diffusescale;
4978 light->specularscale = specularscale;
4979 light->flags = flags;
4981 // update renderable light data
4982 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4983 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);
4986 void R_Shadow_FreeWorldLight(dlight_t *light)
4988 if (r_shadow_selectedlight == light)
4989 r_shadow_selectedlight = NULL;
4990 R_RTLight_Uncompile(&light->rtlight);
4991 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4994 void R_Shadow_ClearWorldLights(void)
4998 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4999 for (lightindex = 0;lightindex < range;lightindex++)
5001 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5003 R_Shadow_FreeWorldLight(light);
5005 r_shadow_selectedlight = NULL;
5008 void R_Shadow_SelectLight(dlight_t *light)
5010 if (r_shadow_selectedlight)
5011 r_shadow_selectedlight->selected = false;
5012 r_shadow_selectedlight = light;
5013 if (r_shadow_selectedlight)
5014 r_shadow_selectedlight->selected = true;
5017 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
5019 // this is never batched (there can be only one)
5021 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
5022 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
5023 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5026 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
5031 skinframe_t *skinframe;
5034 // this is never batched (due to the ent parameter changing every time)
5035 // so numsurfaces == 1 and surfacelist[0] == lightnumber
5036 const dlight_t *light = (dlight_t *)ent;
5039 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
5042 VectorScale(light->color, intensity, spritecolor);
5043 if (VectorLength(spritecolor) < 0.1732f)
5044 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
5045 if (VectorLength(spritecolor) > 1.0f)
5046 VectorNormalize(spritecolor);
5048 // draw light sprite
5049 if (light->cubemapname[0] && !light->shadow)
5050 skinframe = r_editlights_sprcubemapnoshadowlight;
5051 else if (light->cubemapname[0])
5052 skinframe = r_editlights_sprcubemaplight;
5053 else if (!light->shadow)
5054 skinframe = r_editlights_sprnoshadowlight;
5056 skinframe = r_editlights_sprlight;
5058 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);
5059 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5061 // draw selection sprite if light is selected
5062 if (light->selected)
5064 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
5065 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5066 // VorteX todo: add normalmode/realtime mode light overlay sprites?
5070 void R_Shadow_DrawLightSprites(void)
5074 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5075 for (lightindex = 0;lightindex < range;lightindex++)
5077 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5079 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
5081 if (!r_editlights_lockcursor)
5082 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
5085 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
5090 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
5091 if (lightindex >= range)
5093 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5096 rtlight = &light->rtlight;
5097 //if (!(rtlight->flags & flag))
5099 VectorCopy(rtlight->shadoworigin, origin);
5100 *radius = rtlight->radius;
5101 VectorCopy(rtlight->color, color);
5105 void R_Shadow_SelectLightInView(void)
5107 float bestrating, rating, temp[3];
5111 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5115 if (r_editlights_lockcursor)
5117 for (lightindex = 0;lightindex < range;lightindex++)
5119 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5122 VectorSubtract(light->origin, r_refdef.view.origin, temp);
5123 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
5126 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
5127 if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1.0f)
5129 bestrating = rating;
5134 R_Shadow_SelectLight(best);
5137 void R_Shadow_LoadWorldLights(void)
5139 int n, a, style, shadow, flags;
5140 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
5141 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
5142 if (cl.worldmodel == NULL)
5144 Con_Print("No map loaded.\n");
5147 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
5148 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5158 for (;COM_Parse(t, true) && strcmp(
5159 if (COM_Parse(t, true))
5161 if (com_token[0] == '!')
5164 origin[0] = atof(com_token+1);
5167 origin[0] = atof(com_token);
5172 while (*s && *s != '\n' && *s != '\r')
5178 // check for modifier flags
5185 #if _MSC_VER >= 1400
5186 #define sscanf sscanf_s
5188 cubemapname[sizeof(cubemapname)-1] = 0;
5189 #if MAX_QPATH != 128
5190 #error update this code if MAX_QPATH changes
5192 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
5193 #if _MSC_VER >= 1400
5194 , sizeof(cubemapname)
5196 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
5199 flags = LIGHTFLAG_REALTIMEMODE;
5207 coronasizescale = 0.25f;
5209 VectorClear(angles);
5212 if (a < 9 || !strcmp(cubemapname, "\"\""))
5214 // remove quotes on cubemapname
5215 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
5218 namelen = strlen(cubemapname) - 2;
5219 memmove(cubemapname, cubemapname + 1, namelen);
5220 cubemapname[namelen] = '\0';
5224 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);
5227 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5235 Con_Printf("invalid rtlights file \"%s\"\n", name);
5236 Mem_Free(lightsstring);
5240 void R_Shadow_SaveWorldLights(void)
5244 size_t bufchars, bufmaxchars;
5246 char name[MAX_QPATH];
5247 char line[MAX_INPUTLINE];
5248 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
5249 // I hate lines which are 3 times my screen size :( --blub
5252 if (cl.worldmodel == NULL)
5254 Con_Print("No map loaded.\n");
5257 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
5258 bufchars = bufmaxchars = 0;
5260 for (lightindex = 0;lightindex < range;lightindex++)
5262 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5265 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
5266 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);
5267 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
5268 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]);
5270 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);
5271 if (bufchars + strlen(line) > bufmaxchars)
5273 bufmaxchars = bufchars + strlen(line) + 2048;
5275 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
5279 memcpy(buf, oldbuf, bufchars);
5285 memcpy(buf + bufchars, line, strlen(line));
5286 bufchars += strlen(line);
5290 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
5295 void R_Shadow_LoadLightsFile(void)
5298 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
5299 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
5300 if (cl.worldmodel == NULL)
5302 Con_Print("No map loaded.\n");
5305 dpsnprintf(name, sizeof(name), "%s.lights", cl.worldnamenoextension);
5306 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5314 while (*s && *s != '\n' && *s != '\r')
5320 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);
5324 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);
5327 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
5328 radius = bound(15, radius, 4096);
5329 VectorScale(color, (2.0f / (8388608.0f)), color);
5330 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5338 Con_Printf("invalid lights file \"%s\"\n", name);
5339 Mem_Free(lightsstring);
5343 // tyrlite/hmap2 light types in the delay field
5344 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
5346 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
5358 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
5359 char key[256], value[MAX_INPUTLINE];
5361 if (cl.worldmodel == NULL)
5363 Con_Print("No map loaded.\n");
5366 // try to load a .ent file first
5367 dpsnprintf(key, sizeof(key), "%s.ent", cl.worldnamenoextension);
5368 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
5369 // and if that is not found, fall back to the bsp file entity string
5371 data = cl.worldmodel->brush.entities;
5374 for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
5376 type = LIGHTTYPE_MINUSX;
5377 origin[0] = origin[1] = origin[2] = 0;
5378 originhack[0] = originhack[1] = originhack[2] = 0;
5379 angles[0] = angles[1] = angles[2] = 0;
5380 color[0] = color[1] = color[2] = 1;
5381 light[0] = light[1] = light[2] = 1;light[3] = 300;
5382 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
5392 if (!COM_ParseToken_Simple(&data, false, false))
5394 if (com_token[0] == '}')
5395 break; // end of entity
5396 if (com_token[0] == '_')
5397 strlcpy(key, com_token + 1, sizeof(key));
5399 strlcpy(key, com_token, sizeof(key));
5400 while (key[strlen(key)-1] == ' ') // remove trailing spaces
5401 key[strlen(key)-1] = 0;
5402 if (!COM_ParseToken_Simple(&data, false, false))
5404 strlcpy(value, com_token, sizeof(value));
5406 // now that we have the key pair worked out...
5407 if (!strcmp("light", key))
5409 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5413 light[0] = vec[0] * (1.0f / 256.0f);
5414 light[1] = vec[0] * (1.0f / 256.0f);
5415 light[2] = vec[0] * (1.0f / 256.0f);
5421 light[0] = vec[0] * (1.0f / 255.0f);
5422 light[1] = vec[1] * (1.0f / 255.0f);
5423 light[2] = vec[2] * (1.0f / 255.0f);
5427 else if (!strcmp("delay", key))
5429 else if (!strcmp("origin", key))
5430 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5431 else if (!strcmp("angle", key))
5432 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5433 else if (!strcmp("angles", key))
5434 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5435 else if (!strcmp("color", key))
5436 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5437 else if (!strcmp("wait", key))
5438 fadescale = atof(value);
5439 else if (!strcmp("classname", key))
5441 if (!strncmp(value, "light", 5))
5444 if (!strcmp(value, "light_fluoro"))
5449 overridecolor[0] = 1;
5450 overridecolor[1] = 1;
5451 overridecolor[2] = 1;
5453 if (!strcmp(value, "light_fluorospark"))
5458 overridecolor[0] = 1;
5459 overridecolor[1] = 1;
5460 overridecolor[2] = 1;
5462 if (!strcmp(value, "light_globe"))
5467 overridecolor[0] = 1;
5468 overridecolor[1] = 0.8;
5469 overridecolor[2] = 0.4;
5471 if (!strcmp(value, "light_flame_large_yellow"))
5476 overridecolor[0] = 1;
5477 overridecolor[1] = 0.5;
5478 overridecolor[2] = 0.1;
5480 if (!strcmp(value, "light_flame_small_yellow"))
5485 overridecolor[0] = 1;
5486 overridecolor[1] = 0.5;
5487 overridecolor[2] = 0.1;
5489 if (!strcmp(value, "light_torch_small_white"))
5494 overridecolor[0] = 1;
5495 overridecolor[1] = 0.5;
5496 overridecolor[2] = 0.1;
5498 if (!strcmp(value, "light_torch_small_walltorch"))
5503 overridecolor[0] = 1;
5504 overridecolor[1] = 0.5;
5505 overridecolor[2] = 0.1;
5509 else if (!strcmp("style", key))
5510 style = atoi(value);
5511 else if (!strcmp("skin", key))
5512 skin = (int)atof(value);
5513 else if (!strcmp("pflags", key))
5514 pflags = (int)atof(value);
5515 //else if (!strcmp("effects", key))
5516 // effects = (int)atof(value);
5517 else if (cl.worldmodel->type == mod_brushq3)
5519 if (!strcmp("scale", key))
5520 lightscale = atof(value);
5521 if (!strcmp("fade", key))
5522 fadescale = atof(value);
5527 if (lightscale <= 0)
5531 if (color[0] == color[1] && color[0] == color[2])
5533 color[0] *= overridecolor[0];
5534 color[1] *= overridecolor[1];
5535 color[2] *= overridecolor[2];
5537 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5538 color[0] = color[0] * light[0];
5539 color[1] = color[1] * light[1];
5540 color[2] = color[2] * light[2];
5543 case LIGHTTYPE_MINUSX:
5545 case LIGHTTYPE_RECIPX:
5547 VectorScale(color, (1.0f / 16.0f), color);
5549 case LIGHTTYPE_RECIPXX:
5551 VectorScale(color, (1.0f / 16.0f), color);
5554 case LIGHTTYPE_NONE:
5558 case LIGHTTYPE_MINUSXX:
5561 VectorAdd(origin, originhack, origin);
5563 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);
5566 Mem_Free(entfiledata);
5570 void R_Shadow_SetCursorLocationForView(void)
5573 vec3_t dest, endpos;
5575 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5576 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
5577 if (trace.fraction < 1)
5579 dist = trace.fraction * r_editlights_cursordistance.value;
5580 push = r_editlights_cursorpushback.value;
5584 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5585 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5589 VectorClear( endpos );
5591 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5592 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5593 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5596 void R_Shadow_UpdateWorldLightSelection(void)
5598 if (r_editlights.integer)
5600 R_Shadow_SetCursorLocationForView();
5601 R_Shadow_SelectLightInView();
5604 R_Shadow_SelectLight(NULL);
5607 void R_Shadow_EditLights_Clear_f(void)
5609 R_Shadow_ClearWorldLights();
5612 void R_Shadow_EditLights_Reload_f(void)
5616 strlcpy(r_shadow_mapname, cl.worldname, sizeof(r_shadow_mapname));
5617 R_Shadow_ClearWorldLights();
5618 R_Shadow_LoadWorldLights();
5619 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5621 R_Shadow_LoadLightsFile();
5622 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5623 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5627 void R_Shadow_EditLights_Save_f(void)
5631 R_Shadow_SaveWorldLights();
5634 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
5636 R_Shadow_ClearWorldLights();
5637 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5640 void R_Shadow_EditLights_ImportLightsFile_f(void)
5642 R_Shadow_ClearWorldLights();
5643 R_Shadow_LoadLightsFile();
5646 void R_Shadow_EditLights_Spawn_f(void)
5649 if (!r_editlights.integer)
5651 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5654 if (Cmd_Argc() != 1)
5656 Con_Print("r_editlights_spawn does not take parameters\n");
5659 color[0] = color[1] = color[2] = 1;
5660 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5663 void R_Shadow_EditLights_Edit_f(void)
5665 vec3_t origin, angles, color;
5666 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5667 int style, shadows, flags, normalmode, realtimemode;
5668 char cubemapname[MAX_INPUTLINE];
5669 if (!r_editlights.integer)
5671 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5674 if (!r_shadow_selectedlight)
5676 Con_Print("No selected light.\n");
5679 VectorCopy(r_shadow_selectedlight->origin, origin);
5680 VectorCopy(r_shadow_selectedlight->angles, angles);
5681 VectorCopy(r_shadow_selectedlight->color, color);
5682 radius = r_shadow_selectedlight->radius;
5683 style = r_shadow_selectedlight->style;
5684 if (r_shadow_selectedlight->cubemapname)
5685 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5688 shadows = r_shadow_selectedlight->shadow;
5689 corona = r_shadow_selectedlight->corona;
5690 coronasizescale = r_shadow_selectedlight->coronasizescale;
5691 ambientscale = r_shadow_selectedlight->ambientscale;
5692 diffusescale = r_shadow_selectedlight->diffusescale;
5693 specularscale = r_shadow_selectedlight->specularscale;
5694 flags = r_shadow_selectedlight->flags;
5695 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5696 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5697 if (!strcmp(Cmd_Argv(1), "origin"))
5699 if (Cmd_Argc() != 5)
5701 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5704 origin[0] = atof(Cmd_Argv(2));
5705 origin[1] = atof(Cmd_Argv(3));
5706 origin[2] = atof(Cmd_Argv(4));
5708 else if (!strcmp(Cmd_Argv(1), "originx"))
5710 if (Cmd_Argc() != 3)
5712 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5715 origin[0] = atof(Cmd_Argv(2));
5717 else if (!strcmp(Cmd_Argv(1), "originy"))
5719 if (Cmd_Argc() != 3)
5721 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5724 origin[1] = atof(Cmd_Argv(2));
5726 else if (!strcmp(Cmd_Argv(1), "originz"))
5728 if (Cmd_Argc() != 3)
5730 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5733 origin[2] = atof(Cmd_Argv(2));
5735 else if (!strcmp(Cmd_Argv(1), "move"))
5737 if (Cmd_Argc() != 5)
5739 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5742 origin[0] += atof(Cmd_Argv(2));
5743 origin[1] += atof(Cmd_Argv(3));
5744 origin[2] += atof(Cmd_Argv(4));
5746 else if (!strcmp(Cmd_Argv(1), "movex"))
5748 if (Cmd_Argc() != 3)
5750 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5753 origin[0] += atof(Cmd_Argv(2));
5755 else if (!strcmp(Cmd_Argv(1), "movey"))
5757 if (Cmd_Argc() != 3)
5759 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5762 origin[1] += atof(Cmd_Argv(2));
5764 else if (!strcmp(Cmd_Argv(1), "movez"))
5766 if (Cmd_Argc() != 3)
5768 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5771 origin[2] += atof(Cmd_Argv(2));
5773 else if (!strcmp(Cmd_Argv(1), "angles"))
5775 if (Cmd_Argc() != 5)
5777 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5780 angles[0] = atof(Cmd_Argv(2));
5781 angles[1] = atof(Cmd_Argv(3));
5782 angles[2] = atof(Cmd_Argv(4));
5784 else if (!strcmp(Cmd_Argv(1), "anglesx"))
5786 if (Cmd_Argc() != 3)
5788 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5791 angles[0] = atof(Cmd_Argv(2));
5793 else if (!strcmp(Cmd_Argv(1), "anglesy"))
5795 if (Cmd_Argc() != 3)
5797 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5800 angles[1] = atof(Cmd_Argv(2));
5802 else if (!strcmp(Cmd_Argv(1), "anglesz"))
5804 if (Cmd_Argc() != 3)
5806 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5809 angles[2] = atof(Cmd_Argv(2));
5811 else if (!strcmp(Cmd_Argv(1), "color"))
5813 if (Cmd_Argc() != 5)
5815 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
5818 color[0] = atof(Cmd_Argv(2));
5819 color[1] = atof(Cmd_Argv(3));
5820 color[2] = atof(Cmd_Argv(4));
5822 else if (!strcmp(Cmd_Argv(1), "radius"))
5824 if (Cmd_Argc() != 3)
5826 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5829 radius = atof(Cmd_Argv(2));
5831 else if (!strcmp(Cmd_Argv(1), "colorscale"))
5833 if (Cmd_Argc() == 3)
5835 double scale = atof(Cmd_Argv(2));
5842 if (Cmd_Argc() != 5)
5844 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
5847 color[0] *= atof(Cmd_Argv(2));
5848 color[1] *= atof(Cmd_Argv(3));
5849 color[2] *= atof(Cmd_Argv(4));
5852 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
5854 if (Cmd_Argc() != 3)
5856 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5859 radius *= atof(Cmd_Argv(2));
5861 else if (!strcmp(Cmd_Argv(1), "style"))
5863 if (Cmd_Argc() != 3)
5865 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5868 style = atoi(Cmd_Argv(2));
5870 else if (!strcmp(Cmd_Argv(1), "cubemap"))
5874 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5877 if (Cmd_Argc() == 3)
5878 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
5882 else if (!strcmp(Cmd_Argv(1), "shadows"))
5884 if (Cmd_Argc() != 3)
5886 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5889 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5891 else if (!strcmp(Cmd_Argv(1), "corona"))
5893 if (Cmd_Argc() != 3)
5895 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5898 corona = atof(Cmd_Argv(2));
5900 else if (!strcmp(Cmd_Argv(1), "coronasize"))
5902 if (Cmd_Argc() != 3)
5904 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5907 coronasizescale = atof(Cmd_Argv(2));
5909 else if (!strcmp(Cmd_Argv(1), "ambient"))
5911 if (Cmd_Argc() != 3)
5913 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5916 ambientscale = atof(Cmd_Argv(2));
5918 else if (!strcmp(Cmd_Argv(1), "diffuse"))
5920 if (Cmd_Argc() != 3)
5922 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5925 diffusescale = atof(Cmd_Argv(2));
5927 else if (!strcmp(Cmd_Argv(1), "specular"))
5929 if (Cmd_Argc() != 3)
5931 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5934 specularscale = atof(Cmd_Argv(2));
5936 else if (!strcmp(Cmd_Argv(1), "normalmode"))
5938 if (Cmd_Argc() != 3)
5940 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5943 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5945 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
5947 if (Cmd_Argc() != 3)
5949 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5952 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5956 Con_Print("usage: r_editlights_edit [property] [value]\n");
5957 Con_Print("Selected light's properties:\n");
5958 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5959 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5960 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5961 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
5962 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
5963 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
5964 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5965 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
5966 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
5967 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
5968 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
5969 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
5970 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5971 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5974 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5975 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5978 void R_Shadow_EditLights_EditAll_f(void)
5981 dlight_t *light, *oldselected;
5984 if (!r_editlights.integer)
5986 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5990 oldselected = r_shadow_selectedlight;
5991 // EditLights doesn't seem to have a "remove" command or something so:
5992 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5993 for (lightindex = 0;lightindex < range;lightindex++)
5995 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5998 R_Shadow_SelectLight(light);
5999 R_Shadow_EditLights_Edit_f();
6001 // return to old selected (to not mess editing once selection is locked)
6002 R_Shadow_SelectLight(oldselected);
6005 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
6007 int lightnumber, lightcount;
6008 size_t lightindex, range;
6012 if (!r_editlights.integer)
6014 x = vid_conwidth.value - 240;
6016 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
6019 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
6020 for (lightindex = 0;lightindex < range;lightindex++)
6022 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6025 if (light == r_shadow_selectedlight)
6026 lightnumber = lightindex;
6029 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;
6030 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;
6032 if (r_shadow_selectedlight == NULL)
6034 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;
6035 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;
6036 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;
6037 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;
6038 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;
6039 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;
6040 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;
6041 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;
6042 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;
6043 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;
6044 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;
6045 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;
6046 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;
6047 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;
6048 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;
6051 void R_Shadow_EditLights_ToggleShadow_f(void)
6053 if (!r_editlights.integer)
6055 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6058 if (!r_shadow_selectedlight)
6060 Con_Print("No selected light.\n");
6063 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);
6066 void R_Shadow_EditLights_ToggleCorona_f(void)
6068 if (!r_editlights.integer)
6070 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6073 if (!r_shadow_selectedlight)
6075 Con_Print("No selected light.\n");
6078 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);
6081 void R_Shadow_EditLights_Remove_f(void)
6083 if (!r_editlights.integer)
6085 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
6088 if (!r_shadow_selectedlight)
6090 Con_Print("No selected light.\n");
6093 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
6094 r_shadow_selectedlight = NULL;
6097 void R_Shadow_EditLights_Help_f(void)
6100 "Documentation on r_editlights system:\n"
6102 "r_editlights : enable/disable editing mode\n"
6103 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
6104 "r_editlights_cursorpushback : push back cursor this far from surface\n"
6105 "r_editlights_cursorpushoff : push cursor off surface this far\n"
6106 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
6107 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
6109 "r_editlights_help : this help\n"
6110 "r_editlights_clear : remove all lights\n"
6111 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
6112 "r_editlights_lock : lock selection to current light, if already locked - unlock\n"
6113 "r_editlights_save : save to .rtlights file\n"
6114 "r_editlights_spawn : create a light with default settings\n"
6115 "r_editlights_edit command : edit selected light - more documentation below\n"
6116 "r_editlights_remove : remove selected light\n"
6117 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
6118 "r_editlights_importlightentitiesfrommap : reload light entities\n"
6119 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
6121 "origin x y z : set light location\n"
6122 "originx x: set x component of light location\n"
6123 "originy y: set y component of light location\n"
6124 "originz z: set z component of light location\n"
6125 "move x y z : adjust light location\n"
6126 "movex x: adjust x component of light location\n"
6127 "movey y: adjust y component of light location\n"
6128 "movez z: adjust z component of light location\n"
6129 "angles x y z : set light angles\n"
6130 "anglesx x: set x component of light angles\n"
6131 "anglesy y: set y component of light angles\n"
6132 "anglesz z: set z component of light angles\n"
6133 "color r g b : set color of light (can be brighter than 1 1 1)\n"
6134 "radius radius : set radius (size) of light\n"
6135 "colorscale grey : multiply color of light (1 does nothing)\n"
6136 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
6137 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
6138 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
6139 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
6140 "cubemap basename : set filter cubemap of light (not yet supported)\n"
6141 "shadows 1/0 : turn on/off shadows\n"
6142 "corona n : set corona intensity\n"
6143 "coronasize n : set corona size (0-1)\n"
6144 "ambient n : set ambient intensity (0-1)\n"
6145 "diffuse n : set diffuse intensity (0-1)\n"
6146 "specular n : set specular intensity (0-1)\n"
6147 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
6148 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
6149 "<nothing> : print light properties to console\n"
6153 void R_Shadow_EditLights_CopyInfo_f(void)
6155 if (!r_editlights.integer)
6157 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
6160 if (!r_shadow_selectedlight)
6162 Con_Print("No selected light.\n");
6165 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
6166 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
6167 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
6168 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
6169 if (r_shadow_selectedlight->cubemapname)
6170 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
6172 r_shadow_bufferlight.cubemapname[0] = 0;
6173 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
6174 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
6175 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
6176 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
6177 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
6178 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
6179 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
6182 void R_Shadow_EditLights_PasteInfo_f(void)
6184 if (!r_editlights.integer)
6186 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
6189 if (!r_shadow_selectedlight)
6191 Con_Print("No selected light.\n");
6194 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);
6197 void R_Shadow_EditLights_Lock_f(void)
6199 if (!r_editlights.integer)
6201 Con_Print("Cannot lock on light when not in editing mode. Set r_editlights to 1.\n");
6204 if (r_editlights_lockcursor)
6206 r_editlights_lockcursor = false;
6209 if (!r_shadow_selectedlight)
6211 Con_Print("No selected light to lock on.\n");
6214 r_editlights_lockcursor = true;
6217 void R_Shadow_EditLights_Init(void)
6219 Cvar_RegisterVariable(&r_editlights);
6220 Cvar_RegisterVariable(&r_editlights_cursordistance);
6221 Cvar_RegisterVariable(&r_editlights_cursorpushback);
6222 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
6223 Cvar_RegisterVariable(&r_editlights_cursorgrid);
6224 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
6225 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
6226 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
6227 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)");
6228 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
6229 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
6230 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
6231 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)");
6232 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
6233 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
6234 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
6235 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
6236 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
6237 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
6238 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)");
6239 Cmd_AddCommand("r_editlights_lock", R_Shadow_EditLights_Lock_f, "lock selection to current light, if already locked - unlock");
6245 =============================================================================
6249 =============================================================================
6252 void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, int dynamic)
6254 VectorClear(diffusecolor);
6255 VectorClear(diffusenormal);
6257 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
6259 ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_refdef.scene.ambient;
6260 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
6263 VectorSet(ambientcolor, 1, 1, 1);
6270 for (i = 0;i < r_refdef.scene.numlights;i++)
6272 light = r_refdef.scene.lights[i];
6273 Matrix4x4_Transform(&light->matrix_worldtolight, p, v);
6274 f = 1 - VectorLength2(v);
6275 if (f > 0 && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
6276 VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);