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];
2561 r_refdef.stats.lights_scissored++;
2565 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, const float *diffusecolor, const float *ambientcolor)
2568 const float *vertex3f;
2569 const float *normal3f;
2571 float dist, dot, distintensity, shadeintensity, v[3], n[3];
2572 switch (r_shadow_rendermode)
2574 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2575 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2576 if (VectorLength2(diffusecolor) > 0)
2578 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)
2580 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2581 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2582 if ((dot = DotProduct(n, v)) < 0)
2584 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2585 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
2588 VectorCopy(ambientcolor, color4f);
2589 if (r_refdef.fogenabled)
2592 f = RSurf_FogVertex(vertex3f);
2593 VectorScale(color4f, f, color4f);
2600 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.array_passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
2602 VectorCopy(ambientcolor, color4f);
2603 if (r_refdef.fogenabled)
2606 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2607 f = RSurf_FogVertex(vertex3f);
2608 VectorScale(color4f + 4*i, f, color4f);
2614 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2615 if (VectorLength2(diffusecolor) > 0)
2617 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)
2619 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2620 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2622 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2623 if ((dot = DotProduct(n, v)) < 0)
2625 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2626 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2627 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2628 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2632 color4f[0] = ambientcolor[0] * distintensity;
2633 color4f[1] = ambientcolor[1] * distintensity;
2634 color4f[2] = ambientcolor[2] * distintensity;
2636 if (r_refdef.fogenabled)
2639 f = RSurf_FogVertex(vertex3f);
2640 VectorScale(color4f, f, color4f);
2644 VectorClear(color4f);
2650 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.array_passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
2652 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2653 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2655 color4f[0] = ambientcolor[0] * distintensity;
2656 color4f[1] = ambientcolor[1] * distintensity;
2657 color4f[2] = ambientcolor[2] * distintensity;
2658 if (r_refdef.fogenabled)
2661 f = RSurf_FogVertex(vertex3f);
2662 VectorScale(color4f, f, color4f);
2666 VectorClear(color4f);
2671 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2672 if (VectorLength2(diffusecolor) > 0)
2674 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)
2676 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2677 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2679 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2680 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2681 if ((dot = DotProduct(n, v)) < 0)
2683 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2684 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2685 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2686 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2690 color4f[0] = ambientcolor[0] * distintensity;
2691 color4f[1] = ambientcolor[1] * distintensity;
2692 color4f[2] = ambientcolor[2] * distintensity;
2694 if (r_refdef.fogenabled)
2697 f = RSurf_FogVertex(vertex3f);
2698 VectorScale(color4f, f, color4f);
2702 VectorClear(color4f);
2708 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.array_passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
2710 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2711 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2713 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2714 color4f[0] = ambientcolor[0] * distintensity;
2715 color4f[1] = ambientcolor[1] * distintensity;
2716 color4f[2] = ambientcolor[2] * distintensity;
2717 if (r_refdef.fogenabled)
2720 f = RSurf_FogVertex(vertex3f);
2721 VectorScale(color4f, f, color4f);
2725 VectorClear(color4f);
2735 static void R_Shadow_RenderLighting_VisibleLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
2737 // used to display how many times a surface is lit for level design purposes
2738 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
2739 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
2743 static void R_Shadow_RenderLighting_Light_GLSL(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale, float specularscale)
2745 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2746 R_SetupShader_Surface(lightcolor, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT, texturenumsurfaces, texturesurfacelist, NULL);
2747 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2748 GL_DepthFunc(GL_EQUAL);
2750 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2751 GL_DepthFunc(GL_LEQUAL);
2754 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
2761 int newnumtriangles;
2765 int maxtriangles = 4096;
2766 static int newelements[4096*3];
2767 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, diffusecolor2, ambientcolor2);
2768 for (renders = 0;renders < 4;renders++)
2773 newnumtriangles = 0;
2775 // due to low fillrate on the cards this vertex lighting path is
2776 // designed for, we manually cull all triangles that do not
2777 // contain a lit vertex
2778 // this builds batches of triangles from multiple surfaces and
2779 // renders them at once
2780 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
2782 if (VectorLength2(rsurface.array_passcolor4f + e[0] * 4) + VectorLength2(rsurface.array_passcolor4f + e[1] * 4) + VectorLength2(rsurface.array_passcolor4f + e[2] * 4) >= 0.01)
2784 if (newnumtriangles)
2786 newfirstvertex = min(newfirstvertex, e[0]);
2787 newlastvertex = max(newlastvertex, e[0]);
2791 newfirstvertex = e[0];
2792 newlastvertex = e[0];
2794 newfirstvertex = min(newfirstvertex, e[1]);
2795 newlastvertex = max(newlastvertex, e[1]);
2796 newfirstvertex = min(newfirstvertex, e[2]);
2797 newlastvertex = max(newlastvertex, e[2]);
2803 if (newnumtriangles >= maxtriangles)
2805 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
2806 newnumtriangles = 0;
2812 if (newnumtriangles >= 1)
2814 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
2817 // if we couldn't find any lit triangles, exit early
2820 // now reduce the intensity for the next overbright pass
2821 // we have to clamp to 0 here incase the drivers have improper
2822 // handling of negative colors
2823 // (some old drivers even have improper handling of >1 color)
2825 for (i = 0, c = rsurface.array_passcolor4f + 4 * firstvertex;i < numvertices;i++, c += 4)
2827 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
2829 c[0] = max(0, c[0] - 1);
2830 c[1] = max(0, c[1] - 1);
2831 c[2] = max(0, c[2] - 1);
2843 static void R_Shadow_RenderLighting_Light_Vertex(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale)
2845 // OpenGL 1.1 path (anything)
2846 float ambientcolorbase[3], diffusecolorbase[3];
2847 float ambientcolorpants[3], diffusecolorpants[3];
2848 float ambientcolorshirt[3], diffusecolorshirt[3];
2849 const float *surfacecolor = rsurface.texture->dlightcolor;
2850 const float *surfacepants = rsurface.colormap_pantscolor;
2851 const float *surfaceshirt = rsurface.colormap_shirtcolor;
2852 rtexture_t *basetexture = rsurface.texture->basetexture;
2853 rtexture_t *pantstexture = rsurface.texture->pantstexture;
2854 rtexture_t *shirttexture = rsurface.texture->shirttexture;
2855 qboolean dopants = pantstexture && VectorLength2(surfacepants) >= (1.0f / 1048576.0f);
2856 qboolean doshirt = shirttexture && VectorLength2(surfaceshirt) >= (1.0f / 1048576.0f);
2857 ambientscale *= 2 * r_refdef.view.colorscale;
2858 diffusescale *= 2 * r_refdef.view.colorscale;
2859 ambientcolorbase[0] = lightcolor[0] * ambientscale * surfacecolor[0];ambientcolorbase[1] = lightcolor[1] * ambientscale * surfacecolor[1];ambientcolorbase[2] = lightcolor[2] * ambientscale * surfacecolor[2];
2860 diffusecolorbase[0] = lightcolor[0] * diffusescale * surfacecolor[0];diffusecolorbase[1] = lightcolor[1] * diffusescale * surfacecolor[1];diffusecolorbase[2] = lightcolor[2] * diffusescale * surfacecolor[2];
2861 ambientcolorpants[0] = ambientcolorbase[0] * surfacepants[0];ambientcolorpants[1] = ambientcolorbase[1] * surfacepants[1];ambientcolorpants[2] = ambientcolorbase[2] * surfacepants[2];
2862 diffusecolorpants[0] = diffusecolorbase[0] * surfacepants[0];diffusecolorpants[1] = diffusecolorbase[1] * surfacepants[1];diffusecolorpants[2] = diffusecolorbase[2] * surfacepants[2];
2863 ambientcolorshirt[0] = ambientcolorbase[0] * surfaceshirt[0];ambientcolorshirt[1] = ambientcolorbase[1] * surfaceshirt[1];ambientcolorshirt[2] = ambientcolorbase[2] * surfaceshirt[2];
2864 diffusecolorshirt[0] = diffusecolorbase[0] * surfaceshirt[0];diffusecolorshirt[1] = diffusecolorbase[1] * surfaceshirt[1];diffusecolorshirt[2] = diffusecolorbase[2] * surfaceshirt[2];
2865 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | (diffusescale > 0 ? BATCHNEED_ARRAY_NORMAL : 0) | BATCHNEED_ARRAY_TEXCOORD, texturenumsurfaces, texturesurfacelist);
2866 R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
2867 R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.array_passcolor4f, 0, 0);
2868 R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
2869 R_Mesh_TexBind(0, basetexture);
2870 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
2871 R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
2872 switch(r_shadow_rendermode)
2874 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2875 R_Mesh_TexBind(1, r_shadow_attenuation3dtexture);
2876 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
2877 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
2878 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
2880 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2881 R_Mesh_TexBind(2, r_shadow_attenuation2dtexture);
2882 R_Mesh_TexMatrix(2, &rsurface.entitytoattenuationz);
2883 R_Mesh_TexCombine(2, GL_MODULATE, GL_MODULATE, 1, 1);
2884 R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
2886 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2887 R_Mesh_TexBind(1, r_shadow_attenuation2dtexture);
2888 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
2889 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
2890 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
2892 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2897 //R_Mesh_TexBind(0, basetexture);
2898 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorbase, ambientcolorbase);
2901 R_Mesh_TexBind(0, pantstexture);
2902 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorpants, ambientcolorpants);
2906 R_Mesh_TexBind(0, shirttexture);
2907 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorshirt, ambientcolorshirt);
2911 extern cvar_t gl_lightmaps;
2912 void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
2914 float ambientscale, diffusescale, specularscale;
2916 float lightcolor[3];
2917 VectorCopy(rsurface.rtlight->currentcolor, lightcolor);
2918 ambientscale = rsurface.rtlight->ambientscale;
2919 diffusescale = rsurface.rtlight->diffusescale;
2920 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
2921 if (!r_shadow_usenormalmap.integer)
2923 ambientscale += 1.0f * diffusescale;
2927 if ((ambientscale + diffusescale) * VectorLength2(lightcolor) + specularscale * VectorLength2(lightcolor) < (1.0f / 1048576.0f))
2929 negated = (lightcolor[0] + lightcolor[1] + lightcolor[2] < 0) && vid.support.ext_blend_subtract;
2932 VectorNegate(lightcolor, lightcolor);
2933 switch(vid.renderpath)
2935 case RENDERPATH_GL11:
2936 case RENDERPATH_GL13:
2937 case RENDERPATH_GL20:
2938 case RENDERPATH_CGGL:
2939 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
2941 case RENDERPATH_D3D9:
2943 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_SUBTRACT);
2946 case RENDERPATH_D3D10:
2947 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2949 case RENDERPATH_D3D11:
2950 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2954 RSurf_SetupDepthAndCulling();
2955 switch (r_shadow_rendermode)
2957 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2958 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2959 R_Shadow_RenderLighting_VisibleLighting(texturenumsurfaces, texturesurfacelist);
2961 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2962 R_Shadow_RenderLighting_Light_GLSL(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale, specularscale);
2964 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2965 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2966 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2967 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2968 R_Shadow_RenderLighting_Light_Vertex(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale);
2971 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2976 switch(vid.renderpath)
2978 case RENDERPATH_GL11:
2979 case RENDERPATH_GL13:
2980 case RENDERPATH_GL20:
2981 case RENDERPATH_CGGL:
2982 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
2984 case RENDERPATH_D3D9:
2986 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_ADD);
2989 case RENDERPATH_D3D10:
2990 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2992 case RENDERPATH_D3D11:
2993 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2999 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)
3001 matrix4x4_t tempmatrix = *matrix;
3002 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
3004 // if this light has been compiled before, free the associated data
3005 R_RTLight_Uncompile(rtlight);
3007 // clear it completely to avoid any lingering data
3008 memset(rtlight, 0, sizeof(*rtlight));
3010 // copy the properties
3011 rtlight->matrix_lighttoworld = tempmatrix;
3012 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
3013 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
3014 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
3015 VectorCopy(color, rtlight->color);
3016 rtlight->cubemapname[0] = 0;
3017 if (cubemapname && cubemapname[0])
3018 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
3019 rtlight->shadow = shadow;
3020 rtlight->corona = corona;
3021 rtlight->style = style;
3022 rtlight->isstatic = isstatic;
3023 rtlight->coronasizescale = coronasizescale;
3024 rtlight->ambientscale = ambientscale;
3025 rtlight->diffusescale = diffusescale;
3026 rtlight->specularscale = specularscale;
3027 rtlight->flags = flags;
3029 // compute derived data
3030 //rtlight->cullradius = rtlight->radius;
3031 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
3032 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3033 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3034 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3035 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3036 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3037 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3040 // compiles rtlight geometry
3041 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
3042 void R_RTLight_Compile(rtlight_t *rtlight)
3045 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
3046 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
3047 entity_render_t *ent = r_refdef.scene.worldentity;
3048 dp_model_t *model = r_refdef.scene.worldmodel;
3049 unsigned char *data;
3052 // compile the light
3053 rtlight->compiled = true;
3054 rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
3055 rtlight->static_numleafs = 0;
3056 rtlight->static_numleafpvsbytes = 0;
3057 rtlight->static_leaflist = NULL;
3058 rtlight->static_leafpvs = NULL;
3059 rtlight->static_numsurfaces = 0;
3060 rtlight->static_surfacelist = NULL;
3061 rtlight->static_shadowmap_receivers = 0x3F;
3062 rtlight->static_shadowmap_casters = 0x3F;
3063 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3064 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3065 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3066 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3067 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3068 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3070 if (model && model->GetLightInfo)
3072 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
3073 r_shadow_compilingrtlight = rtlight;
3074 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);
3075 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
3076 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
3077 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3078 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
3079 rtlight->static_numsurfaces = numsurfaces;
3080 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
3081 rtlight->static_numleafs = numleafs;
3082 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
3083 rtlight->static_numleafpvsbytes = numleafpvsbytes;
3084 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
3085 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
3086 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
3087 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
3088 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3089 if (rtlight->static_numsurfaces)
3090 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3091 if (rtlight->static_numleafs)
3092 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3093 if (rtlight->static_numleafpvsbytes)
3094 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3095 if (rtlight->static_numshadowtrispvsbytes)
3096 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3097 if (rtlight->static_numlighttrispvsbytes)
3098 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3099 switch (rtlight->shadowmode)
3101 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
3102 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
3103 case R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE:
3104 if (model->CompileShadowMap && rtlight->shadow)
3105 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3108 if (model->CompileShadowVolume && rtlight->shadow)
3109 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3112 // now we're done compiling the rtlight
3113 r_shadow_compilingrtlight = NULL;
3117 // use smallest available cullradius - box radius or light radius
3118 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3119 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3121 shadowzpasstris = 0;
3122 if (rtlight->static_meshchain_shadow_zpass)
3123 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
3124 shadowzpasstris += mesh->numtriangles;
3126 shadowzfailtris = 0;
3127 if (rtlight->static_meshchain_shadow_zfail)
3128 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
3129 shadowzfailtris += mesh->numtriangles;
3132 if (rtlight->static_numlighttrispvsbytes)
3133 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3134 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3138 if (rtlight->static_numlighttrispvsbytes)
3139 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3140 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3143 if (developer_extra.integer)
3144 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);
3147 void R_RTLight_Uncompile(rtlight_t *rtlight)
3149 if (rtlight->compiled)
3151 if (rtlight->static_meshchain_shadow_zpass)
3152 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
3153 rtlight->static_meshchain_shadow_zpass = NULL;
3154 if (rtlight->static_meshchain_shadow_zfail)
3155 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
3156 rtlight->static_meshchain_shadow_zfail = NULL;
3157 if (rtlight->static_meshchain_shadow_shadowmap)
3158 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
3159 rtlight->static_meshchain_shadow_shadowmap = NULL;
3160 // these allocations are grouped
3161 if (rtlight->static_surfacelist)
3162 Mem_Free(rtlight->static_surfacelist);
3163 rtlight->static_numleafs = 0;
3164 rtlight->static_numleafpvsbytes = 0;
3165 rtlight->static_leaflist = NULL;
3166 rtlight->static_leafpvs = NULL;
3167 rtlight->static_numsurfaces = 0;
3168 rtlight->static_surfacelist = NULL;
3169 rtlight->static_numshadowtrispvsbytes = 0;
3170 rtlight->static_shadowtrispvs = NULL;
3171 rtlight->static_numlighttrispvsbytes = 0;
3172 rtlight->static_lighttrispvs = NULL;
3173 rtlight->compiled = false;
3177 void R_Shadow_UncompileWorldLights(void)
3181 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3182 for (lightindex = 0;lightindex < range;lightindex++)
3184 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3187 R_RTLight_Uncompile(&light->rtlight);
3191 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3195 // reset the count of frustum planes
3196 // see rtlight->cached_frustumplanes definition for how much this array
3198 rtlight->cached_numfrustumplanes = 0;
3200 // haven't implemented a culling path for ortho rendering
3201 if (!r_refdef.view.useperspective)
3203 // check if the light is on screen and copy the 4 planes if it is
3204 for (i = 0;i < 4;i++)
3205 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3208 for (i = 0;i < 4;i++)
3209 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3214 // generate a deformed frustum that includes the light origin, this is
3215 // used to cull shadow casting surfaces that can not possibly cast a
3216 // shadow onto the visible light-receiving surfaces, which can be a
3219 // if the light origin is onscreen the result will be 4 planes exactly
3220 // if the light origin is offscreen on only one axis the result will
3221 // be exactly 5 planes (split-side case)
3222 // if the light origin is offscreen on two axes the result will be
3223 // exactly 4 planes (stretched corner case)
3224 for (i = 0;i < 4;i++)
3226 // quickly reject standard frustum planes that put the light
3227 // origin outside the frustum
3228 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3231 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3233 // if all the standard frustum planes were accepted, the light is onscreen
3234 // otherwise we need to generate some more planes below...
3235 if (rtlight->cached_numfrustumplanes < 4)
3237 // at least one of the stock frustum planes failed, so we need to
3238 // create one or two custom planes to enclose the light origin
3239 for (i = 0;i < 4;i++)
3241 // create a plane using the view origin and light origin, and a
3242 // single point from the frustum corner set
3243 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3244 VectorNormalize(plane.normal);
3245 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3246 // see if this plane is backwards and flip it if so
3247 for (j = 0;j < 4;j++)
3248 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3252 VectorNegate(plane.normal, plane.normal);
3254 // flipped plane, test again to see if it is now valid
3255 for (j = 0;j < 4;j++)
3256 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3258 // if the plane is still not valid, then it is dividing the
3259 // frustum and has to be rejected
3263 // we have created a valid plane, compute extra info
3264 PlaneClassify(&plane);
3266 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3268 // if we've found 5 frustum planes then we have constructed a
3269 // proper split-side case and do not need to keep searching for
3270 // planes to enclose the light origin
3271 if (rtlight->cached_numfrustumplanes == 5)
3279 for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
3281 plane = rtlight->cached_frustumplanes[i];
3282 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));
3287 // now add the light-space box planes if the light box is rotated, as any
3288 // caster outside the oriented light box is irrelevant (even if it passed
3289 // the worldspace light box, which is axial)
3290 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3292 for (i = 0;i < 6;i++)
3296 v[i >> 1] = (i & 1) ? -1 : 1;
3297 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3298 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3299 plane.dist = VectorNormalizeLength(plane.normal);
3300 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3301 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3307 // add the world-space reduced box planes
3308 for (i = 0;i < 6;i++)
3310 VectorClear(plane.normal);
3311 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3312 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
3313 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3322 // reduce all plane distances to tightly fit the rtlight cull box, which
3324 VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3325 VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3326 VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3327 VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3328 VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3329 VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3330 VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3331 VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3332 oldnum = rtlight->cached_numfrustumplanes;
3333 rtlight->cached_numfrustumplanes = 0;
3334 for (j = 0;j < oldnum;j++)
3336 // find the nearest point on the box to this plane
3337 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
3338 for (i = 1;i < 8;i++)
3340 dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
3341 if (bestdist > dist)
3344 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);
3345 // if the nearest point is near or behind the plane, we want this
3346 // plane, otherwise the plane is useless as it won't cull anything
3347 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
3349 PlaneClassify(&rtlight->cached_frustumplanes[j]);
3350 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
3357 void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
3361 RSurf_ActiveWorldEntity();
3363 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3366 GL_CullFace(GL_NONE);
3367 mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3368 for (;mesh;mesh = mesh->next)
3370 if (!mesh->sidetotals[r_shadow_shadowmapside])
3372 r_refdef.stats.lights_shadowtriangles += mesh->sidetotals[r_shadow_shadowmapside];
3373 R_Mesh_PrepareVertices_Position(mesh->numverts, mesh->vertexposition, mesh->vertexpositionbuffer);
3374 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);
3378 else if (r_refdef.scene.worldentity->model)
3379 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);
3381 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3384 void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3386 qboolean zpass = false;
3389 int surfacelistindex;
3390 msurface_t *surface;
3392 RSurf_ActiveWorldEntity();
3394 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3397 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
3399 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
3400 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
3402 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
3403 for (;mesh;mesh = mesh->next)
3405 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
3406 R_Mesh_PrepareVertices_Position(mesh->numverts, mesh->vertexposition, mesh->vertexpositionbuffer);
3407 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
3409 // increment stencil if frontface is infront of depthbuffer
3410 GL_CullFace(r_refdef.view.cullface_back);
3411 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
3412 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);
3413 // decrement stencil if backface is infront of depthbuffer
3414 GL_CullFace(r_refdef.view.cullface_front);
3415 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
3417 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
3419 // decrement stencil if backface is behind depthbuffer
3420 GL_CullFace(r_refdef.view.cullface_front);
3421 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
3422 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);
3423 // increment stencil if frontface is behind depthbuffer
3424 GL_CullFace(r_refdef.view.cullface_back);
3425 R_SetStencil(true, 255, GL_KEEP, GL_INCR, 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);
3431 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh)
3433 // use the shadow trispvs calculated earlier by GetLightInfo to cull world triangles on this dynamic light
3434 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
3435 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
3437 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
3438 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
3439 if (CHECKPVSBIT(trispvs, t))
3440 shadowmarklist[numshadowmark++] = t;
3442 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);
3444 else if (numsurfaces)
3445 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);
3447 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3450 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3452 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3453 vec_t relativeshadowradius;
3454 RSurf_ActiveModelEntity(ent, false, false, false);
3455 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3456 // we need to re-init the shader for each entity because the matrix changed
3457 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3458 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3459 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3460 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3461 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3462 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3463 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3464 switch (r_shadow_rendermode)
3466 case R_SHADOW_RENDERMODE_SHADOWMAP2D:
3467 case R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE:
3468 case R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE:
3469 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
3472 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3475 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3478 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3480 // set up properties for rendering light onto this entity
3481 RSurf_ActiveModelEntity(ent, true, true, false);
3482 GL_AlphaTest(false);
3483 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3484 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3485 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3486 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3489 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
3491 if (!r_refdef.scene.worldmodel->DrawLight)
3494 // set up properties for rendering light onto this entity
3495 RSurf_ActiveWorldEntity();
3496 GL_AlphaTest(false);
3497 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3498 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3499 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3500 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3502 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
3504 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3507 void R_Shadow_DrawEntityLight(entity_render_t *ent)
3509 dp_model_t *model = ent->model;
3510 if (!model->DrawLight)
3513 R_Shadow_SetupEntityLight(ent);
3515 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3517 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3520 void R_Shadow_PrepareLight(rtlight_t *rtlight)
3524 int numleafs, numsurfaces;
3525 int *leaflist, *surfacelist;
3526 unsigned char *leafpvs;
3527 unsigned char *shadowtrispvs;
3528 unsigned char *lighttrispvs;
3529 //unsigned char *surfacesides;
3530 int numlightentities;
3531 int numlightentities_noselfshadow;
3532 int numshadowentities;
3533 int numshadowentities_noselfshadow;
3534 static entity_render_t *lightentities[MAX_EDICTS];
3535 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3536 static entity_render_t *shadowentities[MAX_EDICTS];
3537 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3540 rtlight->draw = false;
3542 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3543 // skip lights that are basically invisible (color 0 0 0)
3544 nolight = VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f);
3546 // loading is done before visibility checks because loading should happen
3547 // all at once at the start of a level, not when it stalls gameplay.
3548 // (especially important to benchmarks)
3550 if (rtlight->isstatic && !nolight && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
3552 if (rtlight->compiled)
3553 R_RTLight_Uncompile(rtlight);
3554 R_RTLight_Compile(rtlight);
3558 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
3560 // look up the light style value at this time
3561 f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3562 VectorScale(rtlight->color, f, rtlight->currentcolor);
3564 if (rtlight->selected)
3566 f = 2 + sin(realtime * M_PI * 4.0);
3567 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3571 // if lightstyle is currently off, don't draw the light
3572 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3575 // skip processing on corona-only lights
3579 // if the light box is offscreen, skip it
3580 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3583 VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
3584 VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
3586 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3588 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3590 // compiled light, world available and can receive realtime lighting
3591 // retrieve leaf information
3592 numleafs = rtlight->static_numleafs;
3593 leaflist = rtlight->static_leaflist;
3594 leafpvs = rtlight->static_leafpvs;
3595 numsurfaces = rtlight->static_numsurfaces;
3596 surfacelist = rtlight->static_surfacelist;
3597 //surfacesides = NULL;
3598 shadowtrispvs = rtlight->static_shadowtrispvs;
3599 lighttrispvs = rtlight->static_lighttrispvs;
3601 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3603 // dynamic light, world available and can receive realtime lighting
3604 // calculate lit surfaces and leafs
3605 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);
3606 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3607 leaflist = r_shadow_buffer_leaflist;
3608 leafpvs = r_shadow_buffer_leafpvs;
3609 surfacelist = r_shadow_buffer_surfacelist;
3610 //surfacesides = r_shadow_buffer_surfacesides;
3611 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3612 lighttrispvs = r_shadow_buffer_lighttrispvs;
3613 // if the reduced leaf bounds are offscreen, skip it
3614 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3625 //surfacesides = NULL;
3626 shadowtrispvs = NULL;
3627 lighttrispvs = NULL;
3629 // check if light is illuminating any visible leafs
3632 for (i = 0;i < numleafs;i++)
3633 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3639 // make a list of lit entities and shadow casting entities
3640 numlightentities = 0;
3641 numlightentities_noselfshadow = 0;
3642 numshadowentities = 0;
3643 numshadowentities_noselfshadow = 0;
3645 // add dynamic entities that are lit by the light
3646 for (i = 0;i < r_refdef.scene.numentities;i++)
3649 entity_render_t *ent = r_refdef.scene.entities[i];
3651 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3653 // skip the object entirely if it is not within the valid
3654 // shadow-casting region (which includes the lit region)
3655 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
3657 if (!(model = ent->model))
3659 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
3661 // this entity wants to receive light, is visible, and is
3662 // inside the light box
3663 // TODO: check if the surfaces in the model can receive light
3664 // so now check if it's in a leaf seen by the light
3665 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))
3667 if (ent->flags & RENDER_NOSELFSHADOW)
3668 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
3670 lightentities[numlightentities++] = ent;
3671 // since it is lit, it probably also casts a shadow...
3672 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3673 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3674 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3676 // note: exterior models without the RENDER_NOSELFSHADOW
3677 // flag still create a RENDER_NOSELFSHADOW shadow but
3678 // are lit normally, this means that they are
3679 // self-shadowing but do not shadow other
3680 // RENDER_NOSELFSHADOW entities such as the gun
3681 // (very weird, but keeps the player shadow off the gun)
3682 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3683 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3685 shadowentities[numshadowentities++] = ent;
3688 else if (ent->flags & RENDER_SHADOW)
3690 // this entity is not receiving light, but may still need to
3692 // TODO: check if the surfaces in the model can cast shadow
3693 // now check if it is in a leaf seen by the light
3694 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))
3696 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3697 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3698 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3700 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3701 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3703 shadowentities[numshadowentities++] = ent;
3708 // return if there's nothing at all to light
3709 if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
3712 // count this light in the r_speeds
3713 r_refdef.stats.lights++;
3715 // flag it as worth drawing later
3716 rtlight->draw = true;
3718 // cache all the animated entities that cast a shadow but are not visible
3719 for (i = 0;i < numshadowentities;i++)
3720 if (!shadowentities[i]->animcache_vertex3f)
3721 R_AnimCache_GetEntity(shadowentities[i], false, false);
3722 for (i = 0;i < numshadowentities_noselfshadow;i++)
3723 if (!shadowentities_noselfshadow[i]->animcache_vertex3f)
3724 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
3726 // allocate some temporary memory for rendering this light later in the frame
3727 // reusable buffers need to be copied, static data can be used as-is
3728 rtlight->cached_numlightentities = numlightentities;
3729 rtlight->cached_numlightentities_noselfshadow = numlightentities_noselfshadow;
3730 rtlight->cached_numshadowentities = numshadowentities;
3731 rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
3732 rtlight->cached_numsurfaces = numsurfaces;
3733 rtlight->cached_lightentities = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
3734 rtlight->cached_lightentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
3735 rtlight->cached_shadowentities = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
3736 rtlight->cached_shadowentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
3737 if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
3739 int numshadowtrispvsbytes = (((r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles) + 7) >> 3);
3740 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
3741 rtlight->cached_shadowtrispvs = (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
3742 rtlight->cached_lighttrispvs = (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
3743 rtlight->cached_surfacelist = (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
3747 // compiled light data
3748 rtlight->cached_shadowtrispvs = shadowtrispvs;
3749 rtlight->cached_lighttrispvs = lighttrispvs;
3750 rtlight->cached_surfacelist = surfacelist;
3754 void R_Shadow_DrawLight(rtlight_t *rtlight)
3758 unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
3759 int numlightentities;
3760 int numlightentities_noselfshadow;
3761 int numshadowentities;
3762 int numshadowentities_noselfshadow;
3763 entity_render_t **lightentities;
3764 entity_render_t **lightentities_noselfshadow;
3765 entity_render_t **shadowentities;
3766 entity_render_t **shadowentities_noselfshadow;
3768 static unsigned char entitysides[MAX_EDICTS];
3769 static unsigned char entitysides_noselfshadow[MAX_EDICTS];
3770 vec3_t nearestpoint;
3772 qboolean castshadows;
3775 // check if we cached this light this frame (meaning it is worth drawing)
3779 // if R_FrameData_Store ran out of space we skip anything dependent on it
3780 if (r_framedata_failed)
3783 numlightentities = rtlight->cached_numlightentities;
3784 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
3785 numshadowentities = rtlight->cached_numshadowentities;
3786 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
3787 numsurfaces = rtlight->cached_numsurfaces;
3788 lightentities = rtlight->cached_lightentities;
3789 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
3790 shadowentities = rtlight->cached_shadowentities;
3791 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
3792 shadowtrispvs = rtlight->cached_shadowtrispvs;
3793 lighttrispvs = rtlight->cached_lighttrispvs;
3794 surfacelist = rtlight->cached_surfacelist;
3796 // set up a scissor rectangle for this light
3797 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3800 // don't let sound skip if going slow
3801 if (r_refdef.scene.extraupdate)
3804 // make this the active rtlight for rendering purposes
3805 R_Shadow_RenderMode_ActiveLight(rtlight);
3807 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
3809 // optionally draw visible shape of the shadow volumes
3810 // for performance analysis by level designers
3811 R_Shadow_RenderMode_VisibleShadowVolumes();
3813 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
3814 for (i = 0;i < numshadowentities;i++)
3815 R_Shadow_DrawEntityShadow(shadowentities[i]);
3816 for (i = 0;i < numshadowentities_noselfshadow;i++)
3817 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3818 R_Shadow_RenderMode_VisibleLighting(false, false);
3821 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
3823 // optionally draw the illuminated areas
3824 // for performance analysis by level designers
3825 R_Shadow_RenderMode_VisibleLighting(false, false);
3827 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3828 for (i = 0;i < numlightentities;i++)
3829 R_Shadow_DrawEntityLight(lightentities[i]);
3830 for (i = 0;i < numlightentities_noselfshadow;i++)
3831 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3834 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
3836 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
3837 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
3838 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
3839 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
3841 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance/rtlight->radius));
3842 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
3843 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
3845 if (castshadows && (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE))
3851 int receivermask = 0;
3852 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
3853 Matrix4x4_Abs(&radiustolight);
3855 r_shadow_shadowmaplod = 0;
3856 for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
3857 if ((r_shadow_shadowmapmaxsize >> i) > lodlinear)
3858 r_shadow_shadowmaplod = i;
3860 if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
3861 size = max(1, r_shadow_shadowmapmaxsize >> r_shadow_shadowmaplod);
3863 size = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
3865 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
3867 surfacesides = NULL;
3870 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3872 castermask = rtlight->static_shadowmap_casters;
3873 receivermask = rtlight->static_shadowmap_receivers;
3877 surfacesides = r_shadow_buffer_surfacesides;
3878 for(i = 0;i < numsurfaces;i++)
3880 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
3881 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3882 castermask |= surfacesides[i];
3883 receivermask |= surfacesides[i];
3887 if (receivermask < 0x3F)
3889 for (i = 0;i < numlightentities;i++)
3890 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3891 if (receivermask < 0x3F)
3892 for(i = 0; i < numlightentities_noselfshadow;i++)
3893 receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3896 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
3900 for (i = 0;i < numshadowentities;i++)
3901 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3902 for (i = 0;i < numshadowentities_noselfshadow;i++)
3903 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3906 //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
3908 // render shadow casters into 6 sided depth texture
3909 for (side = 0;side < 6;side++) if (receivermask & (1 << side))
3911 R_Shadow_RenderMode_ShadowMap(side, receivermask, size);
3912 if (! (castermask & (1 << side))) continue;
3914 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
3915 for (i = 0;i < numshadowentities;i++) if (entitysides[i] & (1 << side))
3916 R_Shadow_DrawEntityShadow(shadowentities[i]);
3919 if (numlightentities_noselfshadow)
3921 // render lighting using the depth texture as shadowmap
3922 // draw lighting in the unmasked areas
3923 R_Shadow_RenderMode_Lighting(false, false, true);
3924 for (i = 0;i < numlightentities_noselfshadow;i++)
3925 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3928 // render shadow casters into 6 sided depth texture
3929 if (numshadowentities_noselfshadow)
3931 for (side = 0;side < 6;side++) if ((receivermask & castermask) & (1 << side))
3933 R_Shadow_RenderMode_ShadowMap(side, 0, size);
3934 for (i = 0;i < numshadowentities_noselfshadow;i++) if (entitysides_noselfshadow[i] & (1 << side))
3935 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3939 // render lighting using the depth texture as shadowmap
3940 // draw lighting in the unmasked areas
3941 R_Shadow_RenderMode_Lighting(false, false, true);
3942 // draw lighting in the unmasked areas
3944 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3945 for (i = 0;i < numlightentities;i++)
3946 R_Shadow_DrawEntityLight(lightentities[i]);
3948 else if (castshadows && vid.stencil)
3950 // draw stencil shadow volumes to mask off pixels that are in shadow
3951 // so that they won't receive lighting
3952 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
3953 R_Shadow_ClearStencil();
3956 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
3957 for (i = 0;i < numshadowentities;i++)
3958 R_Shadow_DrawEntityShadow(shadowentities[i]);
3960 // draw lighting in the unmasked areas
3961 R_Shadow_RenderMode_Lighting(true, false, false);
3962 for (i = 0;i < numlightentities_noselfshadow;i++)
3963 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3965 for (i = 0;i < numshadowentities_noselfshadow;i++)
3966 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3968 // draw lighting in the unmasked areas
3969 R_Shadow_RenderMode_Lighting(true, false, false);
3971 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3972 for (i = 0;i < numlightentities;i++)
3973 R_Shadow_DrawEntityLight(lightentities[i]);
3977 // draw lighting in the unmasked areas
3978 R_Shadow_RenderMode_Lighting(false, false, false);
3980 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3981 for (i = 0;i < numlightentities;i++)
3982 R_Shadow_DrawEntityLight(lightentities[i]);
3983 for (i = 0;i < numlightentities_noselfshadow;i++)
3984 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3987 if (r_shadow_usingdeferredprepass)
3989 // when rendering deferred lighting, we simply rasterize the box
3990 if (castshadows && (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE))
3991 R_Shadow_RenderMode_DrawDeferredLight(false, true);
3992 else if (castshadows && vid.stencil)
3993 R_Shadow_RenderMode_DrawDeferredLight(true, false);
3995 R_Shadow_RenderMode_DrawDeferredLight(false, false);
3999 static void R_Shadow_FreeDeferred(void)
4001 R_Mesh_DestroyFramebufferObject(r_shadow_prepassgeometryfbo);
4002 r_shadow_prepassgeometryfbo = 0;
4004 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingfbo);
4005 r_shadow_prepasslightingfbo = 0;
4007 if (r_shadow_prepassgeometrydepthtexture)
4008 R_FreeTexture(r_shadow_prepassgeometrydepthtexture);
4009 r_shadow_prepassgeometrydepthtexture = NULL;
4011 if (r_shadow_prepassgeometrynormalmaptexture)
4012 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
4013 r_shadow_prepassgeometrynormalmaptexture = NULL;
4015 if (r_shadow_prepasslightingdiffusetexture)
4016 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
4017 r_shadow_prepasslightingdiffusetexture = NULL;
4019 if (r_shadow_prepasslightingspeculartexture)
4020 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
4021 r_shadow_prepasslightingspeculartexture = NULL;
4024 void R_Shadow_DrawPrepass(void)
4032 entity_render_t *ent;
4033 float clearcolor[4];
4035 GL_AlphaTest(false);
4036 R_Mesh_ResetTextureState();
4038 GL_ColorMask(1,1,1,1);
4039 GL_BlendFunc(GL_ONE, GL_ZERO);
4042 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4043 Vector4Set(clearcolor, 0.5f,0.5f,0.5f,1.0f);
4044 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, clearcolor, 1.0f, 0);
4045 if (r_timereport_active)
4046 R_TimeReport("prepasscleargeom");
4048 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
4049 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
4050 if (r_timereport_active)
4051 R_TimeReport("prepassworld");
4053 for (i = 0;i < r_refdef.scene.numentities;i++)
4055 if (!r_refdef.viewcache.entityvisible[i])
4057 ent = r_refdef.scene.entities[i];
4058 if (ent->model && ent->model->DrawPrepass != NULL)
4059 ent->model->DrawPrepass(ent);
4062 if (r_timereport_active)
4063 R_TimeReport("prepassmodels");
4065 GL_DepthMask(false);
4066 GL_ColorMask(1,1,1,1);
4069 R_Mesh_SetRenderTargets(r_shadow_prepasslightingfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4070 Vector4Set(clearcolor, 0, 0, 0, 0);
4071 GL_Clear(GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
4072 if (r_timereport_active)
4073 R_TimeReport("prepassclearlit");
4075 R_Shadow_RenderMode_Begin();
4077 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4078 if (r_shadow_debuglight.integer >= 0)
4080 lightindex = r_shadow_debuglight.integer;
4081 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4082 if (light && (light->flags & flag))
4083 R_Shadow_DrawLight(&light->rtlight);
4087 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4088 for (lightindex = 0;lightindex < range;lightindex++)
4090 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4091 if (light && (light->flags & flag))
4092 R_Shadow_DrawLight(&light->rtlight);
4095 if (r_refdef.scene.rtdlight)
4096 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4097 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4099 R_Mesh_ResetRenderTargets();
4101 R_Shadow_RenderMode_End();
4103 if (r_timereport_active)
4104 R_TimeReport("prepasslights");
4107 void R_Shadow_DrawLightSprites(void);
4108 void R_Shadow_PrepareLights(void)
4118 if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4) ||
4119 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
4120 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0) ||
4121 r_shadow_shadowmaptexturetype != r_shadow_shadowmapping_texturetype.integer ||
4122 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
4123 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
4124 r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
4125 R_Shadow_FreeShadowMaps();
4127 r_shadow_usingshadowmaportho = false;
4129 switch (vid.renderpath)
4131 case RENDERPATH_GL20:
4132 case RENDERPATH_CGGL:
4133 case RENDERPATH_D3D9:
4134 case RENDERPATH_D3D10:
4135 case RENDERPATH_D3D11:
4136 if (!r_shadow_deferred.integer || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_STENCIL || !vid.support.ext_framebuffer_object || vid.maxdrawbuffers < 2)
4138 r_shadow_usingdeferredprepass = false;
4139 if (r_shadow_prepass_width)
4140 R_Shadow_FreeDeferred();
4141 r_shadow_prepass_width = r_shadow_prepass_height = 0;
4145 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
4147 R_Shadow_FreeDeferred();
4149 r_shadow_usingdeferredprepass = true;
4150 r_shadow_prepass_width = vid.width;
4151 r_shadow_prepass_height = vid.height;
4152 r_shadow_prepassgeometrydepthtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "prepassgeometrydepthmap", vid.width, vid.height, 24, false);
4153 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);
4154 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);
4155 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);
4157 // set up the geometry pass fbo (depth + normalmap)
4158 r_shadow_prepassgeometryfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4159 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4160 // render depth into one texture and normalmap into the other
4161 if (qglDrawBuffersARB)
4163 qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);CHECKGLERROR
4164 qglReadBuffer(GL_NONE);CHECKGLERROR
4165 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4166 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4168 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4169 Cvar_SetValueQuick(&r_shadow_deferred, 0);
4170 r_shadow_usingdeferredprepass = false;
4174 // set up the lighting pass fbo (diffuse + specular)
4175 r_shadow_prepasslightingfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4176 R_Mesh_SetRenderTargets(r_shadow_prepasslightingfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4177 // render diffuse into one texture and specular into another,
4178 // with depth and normalmap bound as textures,
4179 // with depth bound as attachment as well
4180 if (qglDrawBuffersARB)
4182 qglDrawBuffersARB(2, r_shadow_prepasslightingdrawbuffers);CHECKGLERROR
4183 qglReadBuffer(GL_NONE);CHECKGLERROR
4184 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4185 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4187 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4188 Cvar_SetValueQuick(&r_shadow_deferred, 0);
4189 r_shadow_usingdeferredprepass = false;
4194 case RENDERPATH_GL13:
4195 case RENDERPATH_GL11:
4196 r_shadow_usingdeferredprepass = false;
4200 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);
4202 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4203 if (r_shadow_debuglight.integer >= 0)
4205 lightindex = r_shadow_debuglight.integer;
4206 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4207 if (light && (light->flags & flag))
4208 R_Shadow_PrepareLight(&light->rtlight);
4212 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4213 for (lightindex = 0;lightindex < range;lightindex++)
4215 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4216 if (light && (light->flags & flag))
4217 R_Shadow_PrepareLight(&light->rtlight);
4220 if (r_refdef.scene.rtdlight)
4222 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4223 R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
4225 else if(gl_flashblend.integer)
4227 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4229 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
4230 f = (rtlight->style >= 0 ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4231 VectorScale(rtlight->color, f, rtlight->currentcolor);
4235 if (r_editlights.integer)
4236 R_Shadow_DrawLightSprites();
4239 void R_Shadow_DrawLights(void)
4247 R_Shadow_RenderMode_Begin();
4249 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4250 if (r_shadow_debuglight.integer >= 0)
4252 lightindex = r_shadow_debuglight.integer;
4253 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4254 if (light && (light->flags & flag))
4255 R_Shadow_DrawLight(&light->rtlight);
4259 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4260 for (lightindex = 0;lightindex < range;lightindex++)
4262 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4263 if (light && (light->flags & flag))
4264 R_Shadow_DrawLight(&light->rtlight);
4267 if (r_refdef.scene.rtdlight)
4268 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4269 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4271 R_Shadow_RenderMode_End();
4274 extern const float r_screenvertex3f[12];
4275 extern void R_SetupView(qboolean allowwaterclippingplane);
4276 extern void R_ResetViewRendering3D(void);
4277 extern void R_ResetViewRendering2D(void);
4278 extern cvar_t r_shadows;
4279 extern cvar_t r_shadows_darken;
4280 extern cvar_t r_shadows_drawafterrtlighting;
4281 extern cvar_t r_shadows_castfrombmodels;
4282 extern cvar_t r_shadows_throwdistance;
4283 extern cvar_t r_shadows_throwdirection;
4284 extern cvar_t r_shadows_focus;
4285 extern cvar_t r_shadows_shadowmapscale;
4287 void R_Shadow_PrepareModelShadows(void)
4290 float scale, size, radius, dot1, dot2;
4291 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
4292 entity_render_t *ent;
4294 if (!r_refdef.scene.numentities)
4297 switch (r_shadow_shadowmode)
4299 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4300 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
4301 if (r_shadows.integer >= 2)
4304 case R_SHADOW_SHADOWMODE_STENCIL:
4305 for (i = 0;i < r_refdef.scene.numentities;i++)
4307 ent = r_refdef.scene.entities[i];
4308 if (!ent->animcache_vertex3f && ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4309 R_AnimCache_GetEntity(ent, false, false);
4316 size = 2*r_shadow_shadowmapmaxsize;
4317 scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
4318 radius = 0.5f * size / scale;
4320 Math_atov(r_shadows_throwdirection.string, shadowdir);
4321 VectorNormalize(shadowdir);
4322 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4323 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4324 if (fabs(dot1) <= fabs(dot2))
4325 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4327 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4328 VectorNormalize(shadowforward);
4329 CrossProduct(shadowdir, shadowforward, shadowright);
4330 Math_atov(r_shadows_focus.string, shadowfocus);
4331 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4332 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4333 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4334 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4335 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4337 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4339 shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4340 shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4341 shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4342 shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4343 shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4344 shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4346 for (i = 0;i < r_refdef.scene.numentities;i++)
4348 ent = r_refdef.scene.entities[i];
4349 if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
4351 // cast shadows from anything of the map (submodels are optional)
4352 if (!ent->animcache_vertex3f && ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4353 R_AnimCache_GetEntity(ent, false, false);
4357 void R_DrawModelShadowMaps(void)
4360 float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
4361 entity_render_t *ent;
4362 vec3_t relativelightorigin;
4363 vec3_t relativelightdirection, relativeforward, relativeright;
4364 vec3_t relativeshadowmins, relativeshadowmaxs;
4365 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
4367 matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
4368 r_viewport_t viewport;
4370 float clearcolor[4];
4372 if (!r_refdef.scene.numentities)
4375 switch (r_shadow_shadowmode)
4377 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4378 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
4384 R_ResetViewRendering3D();
4385 R_Shadow_RenderMode_Begin();
4386 R_Shadow_RenderMode_ActiveLight(NULL);
4388 switch (r_shadow_shadowmode)
4390 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4391 if (!r_shadow_shadowmap2dtexture)
4392 R_Shadow_MakeShadowMap(0, r_shadow_shadowmapmaxsize);
4393 fbo = r_shadow_fbo2d;
4394 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
4395 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
4396 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
4398 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
4399 if (!r_shadow_shadowmaprectangletexture)
4400 R_Shadow_MakeShadowMap(0, r_shadow_shadowmapmaxsize);
4401 fbo = r_shadow_fborectangle;
4402 r_shadow_shadowmap_texturescale[0] = 1.0f;
4403 r_shadow_shadowmap_texturescale[1] = 1.0f;
4404 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE;
4410 size = 2*r_shadow_shadowmapmaxsize;
4411 scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
4412 radius = 0.5f / scale;
4413 nearclip = -r_shadows_throwdistance.value;
4414 farclip = r_shadows_throwdistance.value;
4415 bias = r_shadow_shadowmapping_bias.value * r_shadow_shadowmapping_nearclip.value / (2 * r_shadows_throwdistance.value) * (1024.0f / size);
4417 r_shadow_shadowmap_parameters[0] = size;
4418 r_shadow_shadowmap_parameters[1] = size;
4419 r_shadow_shadowmap_parameters[2] = 1.0;
4420 r_shadow_shadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
4422 Math_atov(r_shadows_throwdirection.string, shadowdir);
4423 VectorNormalize(shadowdir);
4424 Math_atov(r_shadows_focus.string, shadowfocus);
4425 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4426 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4427 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4428 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4429 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4430 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4431 if (fabs(dot1) <= fabs(dot2))
4432 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4434 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4435 VectorNormalize(shadowforward);
4436 VectorM(scale, shadowforward, &m[0]);
4437 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4439 m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
4440 CrossProduct(shadowdir, shadowforward, shadowright);
4441 VectorM(scale, shadowright, &m[4]);
4442 m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
4443 VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
4444 m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
4445 Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
4446 Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
4447 R_Viewport_InitOrtho(&viewport, &cameramatrix, 0, 0, size, size, 0, 0, 1, 1, 0, -1, NULL);
4449 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4452 R_Mesh_ResetRenderTargets();
4453 R_SetupShader_ShowDepth();
4455 R_Mesh_SetRenderTargets(fbo, r_shadow_shadowmap2dtexture, NULL, NULL, NULL, NULL);
4456 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);
4465 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4467 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4469 GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
4471 for (i = 0;i < r_refdef.scene.numentities;i++)
4473 ent = r_refdef.scene.entities[i];
4475 // cast shadows from anything of the map (submodels are optional)
4476 if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4478 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4479 Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
4480 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4481 Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
4482 Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
4483 relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4484 relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4485 relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4486 relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4487 relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4488 relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4489 RSurf_ActiveModelEntity(ent, false, false, false);
4490 ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
4491 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4495 R_Shadow_RenderMode_End();
4497 Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
4498 Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
4499 Matrix4x4_CreateScale3(&scalematrix, size, -size, 1);
4500 Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
4501 Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
4502 Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
4504 r_shadow_usingshadowmaportho = true;
4505 switch (r_shadow_shadowmode)
4507 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4508 r_shadow_usingshadowmap2d = true;
4510 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
4511 r_shadow_usingshadowmaprect = true;
4518 void R_DrawModelShadows(void)
4521 float relativethrowdistance;
4522 entity_render_t *ent;
4523 vec3_t relativelightorigin;
4524 vec3_t relativelightdirection;
4525 vec3_t relativeshadowmins, relativeshadowmaxs;
4526 vec3_t tmp, shadowdir;
4528 if (!r_refdef.scene.numentities || !vid.stencil || (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL && r_shadows.integer != 1))
4531 R_ResetViewRendering3D();
4532 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4533 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4534 R_Shadow_RenderMode_Begin();
4535 R_Shadow_RenderMode_ActiveLight(NULL);
4536 r_shadow_lightscissor[0] = r_refdef.view.x;
4537 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
4538 r_shadow_lightscissor[2] = r_refdef.view.width;
4539 r_shadow_lightscissor[3] = r_refdef.view.height;
4540 R_Shadow_RenderMode_StencilShadowVolumes(false);
4543 if (r_shadows.integer == 2)
4545 Math_atov(r_shadows_throwdirection.string, shadowdir);
4546 VectorNormalize(shadowdir);
4549 R_Shadow_ClearStencil();
4551 for (i = 0;i < r_refdef.scene.numentities;i++)
4553 ent = r_refdef.scene.entities[i];
4555 // cast shadows from anything of the map (submodels are optional)
4556 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4558 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4559 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
4560 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
4561 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
4562 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4565 if(ent->entitynumber != 0)
4567 if(ent->entitynumber >= MAX_EDICTS) // csqc entity
4569 // FIXME handle this
4570 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4574 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
4575 int entnum, entnum2, recursion;
4576 entnum = entnum2 = ent->entitynumber;
4577 for(recursion = 32; recursion > 0; --recursion)
4579 entnum2 = cl.entities[entnum].state_current.tagentity;
4580 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
4585 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
4587 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
4588 // transform into modelspace of OUR entity
4589 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
4590 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
4593 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4597 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4600 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
4601 RSurf_ActiveModelEntity(ent, false, false, false);
4602 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4603 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4607 // not really the right mode, but this will disable any silly stencil features
4608 R_Shadow_RenderMode_End();
4610 // set up ortho view for rendering this pass
4611 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4612 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4613 //GL_ScissorTest(true);
4614 //R_EntityMatrix(&identitymatrix);
4615 //R_Mesh_ResetTextureState();
4616 R_ResetViewRendering2D();
4618 // set up a darkening blend on shadowed areas
4619 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4620 //GL_DepthRange(0, 1);
4621 //GL_DepthTest(false);
4622 //GL_DepthMask(false);
4623 //GL_PolygonOffset(0, 0);CHECKGLERROR
4624 GL_Color(0, 0, 0, r_shadows_darken.value);
4625 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4626 //GL_DepthFunc(GL_ALWAYS);
4627 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_NOTEQUAL, 128, 255);
4629 // apply the blend to the shadowed areas
4630 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, NULL);
4631 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
4632 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4634 // restore the viewport
4635 R_SetViewport(&r_refdef.view.viewport);
4637 // restore other state to normal
4638 //R_Shadow_RenderMode_End();
4641 void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4644 vec3_t centerorigin;
4646 // if it's too close, skip it
4647 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
4649 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4652 if (usequery && r_numqueries + 2 <= r_maxqueries)
4654 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4655 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4656 // 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
4657 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4659 switch(vid.renderpath)
4661 case RENDERPATH_GL20:
4662 case RENDERPATH_GL13:
4663 case RENDERPATH_GL11:
4664 case RENDERPATH_CGGL:
4666 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use GL_DepthFunc instead
4667 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
4668 GL_DepthFunc(GL_ALWAYS);
4669 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4670 R_Mesh_PrepareVertices_Position_Arrays(4, vertex3f);
4671 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4672 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4673 GL_DepthFunc(GL_LEQUAL);
4674 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
4675 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4676 R_Mesh_PrepareVertices_Position_Arrays(4, vertex3f);
4677 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4678 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4681 case RENDERPATH_D3D9:
4682 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4684 case RENDERPATH_D3D10:
4685 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4687 case RENDERPATH_D3D11:
4688 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4692 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4695 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
4697 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4700 GLint allpixels = 0, visiblepixels = 0;
4701 // now we have to check the query result
4702 if (rtlight->corona_queryindex_visiblepixels)
4704 switch(vid.renderpath)
4706 case RENDERPATH_GL20:
4707 case RENDERPATH_GL13:
4708 case RENDERPATH_GL11:
4709 case RENDERPATH_CGGL:
4711 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
4712 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
4715 case RENDERPATH_D3D9:
4716 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4718 case RENDERPATH_D3D10:
4719 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4721 case RENDERPATH_D3D11:
4722 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4725 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
4726 if (visiblepixels < 1 || allpixels < 1)
4728 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
4729 cscale *= rtlight->corona_visibility;
4733 // FIXME: these traces should scan all render entities instead of cl.world
4734 if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
4737 VectorScale(rtlight->currentcolor, cscale, color);
4738 if (VectorLength(color) > (1.0f / 256.0f))
4741 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
4744 VectorNegate(color, color);
4745 switch(vid.renderpath)
4747 case RENDERPATH_GL11:
4748 case RENDERPATH_GL13:
4749 case RENDERPATH_GL20:
4750 case RENDERPATH_CGGL:
4751 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
4753 case RENDERPATH_D3D9:
4755 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_SUBTRACT);
4758 case RENDERPATH_D3D10:
4759 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4761 case RENDERPATH_D3D11:
4762 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4766 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4767 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);
4768 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4771 switch(vid.renderpath)
4773 case RENDERPATH_GL11:
4774 case RENDERPATH_GL13:
4775 case RENDERPATH_GL20:
4776 case RENDERPATH_CGGL:
4777 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
4779 case RENDERPATH_D3D9:
4781 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_ADD);
4784 case RENDERPATH_D3D10:
4785 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4787 case RENDERPATH_D3D11:
4788 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4795 void R_Shadow_DrawCoronas(void)
4798 qboolean usequery = false;
4803 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4805 if (r_waterstate.renderingscene)
4807 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4808 R_EntityMatrix(&identitymatrix);
4810 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4812 // check occlusion of coronas
4813 // use GL_ARB_occlusion_query if available
4814 // otherwise use raytraces
4816 switch (vid.renderpath)
4818 case RENDERPATH_GL11:
4819 case RENDERPATH_GL13:
4820 case RENDERPATH_GL20:
4821 case RENDERPATH_CGGL:
4822 usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
4825 GL_ColorMask(0,0,0,0);
4826 if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
4827 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
4830 r_maxqueries = (range + r_refdef.scene.numlights) * 4;
4831 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
4833 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
4836 RSurf_ActiveWorldEntity();
4837 GL_BlendFunc(GL_ONE, GL_ZERO);
4838 GL_CullFace(GL_NONE);
4839 GL_DepthMask(false);
4840 GL_DepthRange(0, 1);
4841 GL_PolygonOffset(0, 0);
4843 R_Mesh_ResetTextureState();
4844 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
4847 case RENDERPATH_D3D9:
4849 //Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4851 case RENDERPATH_D3D10:
4852 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4854 case RENDERPATH_D3D11:
4855 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4858 for (lightindex = 0;lightindex < range;lightindex++)
4860 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4863 rtlight = &light->rtlight;
4864 rtlight->corona_visibility = 0;
4865 rtlight->corona_queryindex_visiblepixels = 0;
4866 rtlight->corona_queryindex_allpixels = 0;
4867 if (!(rtlight->flags & flag))
4869 if (rtlight->corona <= 0)
4871 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4873 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4875 for (i = 0;i < r_refdef.scene.numlights;i++)
4877 rtlight = r_refdef.scene.lights[i];
4878 rtlight->corona_visibility = 0;
4879 rtlight->corona_queryindex_visiblepixels = 0;
4880 rtlight->corona_queryindex_allpixels = 0;
4881 if (!(rtlight->flags & flag))
4883 if (rtlight->corona <= 0)
4885 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4888 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4890 // now draw the coronas using the query data for intensity info
4891 for (lightindex = 0;lightindex < range;lightindex++)
4893 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4896 rtlight = &light->rtlight;
4897 if (rtlight->corona_visibility <= 0)
4899 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4901 for (i = 0;i < r_refdef.scene.numlights;i++)
4903 rtlight = r_refdef.scene.lights[i];
4904 if (rtlight->corona_visibility <= 0)
4906 if (gl_flashblend.integer)
4907 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4909 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4915 dlight_t *R_Shadow_NewWorldLight(void)
4917 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4920 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)
4923 // validate parameters
4924 if (style < 0 || style >= MAX_LIGHTSTYLES)
4926 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
4932 // copy to light properties
4933 VectorCopy(origin, light->origin);
4934 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4935 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4936 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4938 light->color[0] = max(color[0], 0);
4939 light->color[1] = max(color[1], 0);
4940 light->color[2] = max(color[2], 0);
4942 light->color[0] = color[0];
4943 light->color[1] = color[1];
4944 light->color[2] = color[2];
4945 light->radius = max(radius, 0);
4946 light->style = style;
4947 light->shadow = shadowenable;
4948 light->corona = corona;
4949 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4950 light->coronasizescale = coronasizescale;
4951 light->ambientscale = ambientscale;
4952 light->diffusescale = diffusescale;
4953 light->specularscale = specularscale;
4954 light->flags = flags;
4956 // update renderable light data
4957 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4958 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);
4961 void R_Shadow_FreeWorldLight(dlight_t *light)
4963 if (r_shadow_selectedlight == light)
4964 r_shadow_selectedlight = NULL;
4965 R_RTLight_Uncompile(&light->rtlight);
4966 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4969 void R_Shadow_ClearWorldLights(void)
4973 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4974 for (lightindex = 0;lightindex < range;lightindex++)
4976 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4978 R_Shadow_FreeWorldLight(light);
4980 r_shadow_selectedlight = NULL;
4983 void R_Shadow_SelectLight(dlight_t *light)
4985 if (r_shadow_selectedlight)
4986 r_shadow_selectedlight->selected = false;
4987 r_shadow_selectedlight = light;
4988 if (r_shadow_selectedlight)
4989 r_shadow_selectedlight->selected = true;
4992 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4994 // this is never batched (there can be only one)
4996 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
4997 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4998 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5001 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
5006 skinframe_t *skinframe;
5009 // this is never batched (due to the ent parameter changing every time)
5010 // so numsurfaces == 1 and surfacelist[0] == lightnumber
5011 const dlight_t *light = (dlight_t *)ent;
5014 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
5017 VectorScale(light->color, intensity, spritecolor);
5018 if (VectorLength(spritecolor) < 0.1732f)
5019 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
5020 if (VectorLength(spritecolor) > 1.0f)
5021 VectorNormalize(spritecolor);
5023 // draw light sprite
5024 if (light->cubemapname[0] && !light->shadow)
5025 skinframe = r_editlights_sprcubemapnoshadowlight;
5026 else if (light->cubemapname[0])
5027 skinframe = r_editlights_sprcubemaplight;
5028 else if (!light->shadow)
5029 skinframe = r_editlights_sprnoshadowlight;
5031 skinframe = r_editlights_sprlight;
5033 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);
5034 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5036 // draw selection sprite if light is selected
5037 if (light->selected)
5039 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
5040 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
5041 // VorteX todo: add normalmode/realtime mode light overlay sprites?
5045 void R_Shadow_DrawLightSprites(void)
5049 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5050 for (lightindex = 0;lightindex < range;lightindex++)
5052 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5054 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
5056 if (!r_editlights_lockcursor)
5057 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
5060 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
5065 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
5066 if (lightindex >= range)
5068 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5071 rtlight = &light->rtlight;
5072 //if (!(rtlight->flags & flag))
5074 VectorCopy(rtlight->shadoworigin, origin);
5075 *radius = rtlight->radius;
5076 VectorCopy(rtlight->color, color);
5080 void R_Shadow_SelectLightInView(void)
5082 float bestrating, rating, temp[3];
5086 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5090 if (r_editlights_lockcursor)
5092 for (lightindex = 0;lightindex < range;lightindex++)
5094 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5097 VectorSubtract(light->origin, r_refdef.view.origin, temp);
5098 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
5101 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
5102 if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1.0f)
5104 bestrating = rating;
5109 R_Shadow_SelectLight(best);
5112 void R_Shadow_LoadWorldLights(void)
5114 int n, a, style, shadow, flags;
5115 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
5116 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
5117 if (cl.worldmodel == NULL)
5119 Con_Print("No map loaded.\n");
5122 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
5123 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5133 for (;COM_Parse(t, true) && strcmp(
5134 if (COM_Parse(t, true))
5136 if (com_token[0] == '!')
5139 origin[0] = atof(com_token+1);
5142 origin[0] = atof(com_token);
5147 while (*s && *s != '\n' && *s != '\r')
5153 // check for modifier flags
5160 #if _MSC_VER >= 1400
5161 #define sscanf sscanf_s
5163 cubemapname[sizeof(cubemapname)-1] = 0;
5164 #if MAX_QPATH != 128
5165 #error update this code if MAX_QPATH changes
5167 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
5168 #if _MSC_VER >= 1400
5169 , sizeof(cubemapname)
5171 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
5174 flags = LIGHTFLAG_REALTIMEMODE;
5182 coronasizescale = 0.25f;
5184 VectorClear(angles);
5187 if (a < 9 || !strcmp(cubemapname, "\"\""))
5189 // remove quotes on cubemapname
5190 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
5193 namelen = strlen(cubemapname) - 2;
5194 memmove(cubemapname, cubemapname + 1, namelen);
5195 cubemapname[namelen] = '\0';
5199 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);
5202 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5210 Con_Printf("invalid rtlights file \"%s\"\n", name);
5211 Mem_Free(lightsstring);
5215 void R_Shadow_SaveWorldLights(void)
5219 size_t bufchars, bufmaxchars;
5221 char name[MAX_QPATH];
5222 char line[MAX_INPUTLINE];
5223 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
5224 // I hate lines which are 3 times my screen size :( --blub
5227 if (cl.worldmodel == NULL)
5229 Con_Print("No map loaded.\n");
5232 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
5233 bufchars = bufmaxchars = 0;
5235 for (lightindex = 0;lightindex < range;lightindex++)
5237 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5240 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
5241 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);
5242 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
5243 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]);
5245 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);
5246 if (bufchars + strlen(line) > bufmaxchars)
5248 bufmaxchars = bufchars + strlen(line) + 2048;
5250 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
5254 memcpy(buf, oldbuf, bufchars);
5260 memcpy(buf + bufchars, line, strlen(line));
5261 bufchars += strlen(line);
5265 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
5270 void R_Shadow_LoadLightsFile(void)
5273 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
5274 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
5275 if (cl.worldmodel == NULL)
5277 Con_Print("No map loaded.\n");
5280 dpsnprintf(name, sizeof(name), "%s.lights", cl.worldnamenoextension);
5281 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5289 while (*s && *s != '\n' && *s != '\r')
5295 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);
5299 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);
5302 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
5303 radius = bound(15, radius, 4096);
5304 VectorScale(color, (2.0f / (8388608.0f)), color);
5305 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5313 Con_Printf("invalid lights file \"%s\"\n", name);
5314 Mem_Free(lightsstring);
5318 // tyrlite/hmap2 light types in the delay field
5319 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
5321 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
5333 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
5334 char key[256], value[MAX_INPUTLINE];
5336 if (cl.worldmodel == NULL)
5338 Con_Print("No map loaded.\n");
5341 // try to load a .ent file first
5342 dpsnprintf(key, sizeof(key), "%s.ent", cl.worldnamenoextension);
5343 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
5344 // and if that is not found, fall back to the bsp file entity string
5346 data = cl.worldmodel->brush.entities;
5349 for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
5351 type = LIGHTTYPE_MINUSX;
5352 origin[0] = origin[1] = origin[2] = 0;
5353 originhack[0] = originhack[1] = originhack[2] = 0;
5354 angles[0] = angles[1] = angles[2] = 0;
5355 color[0] = color[1] = color[2] = 1;
5356 light[0] = light[1] = light[2] = 1;light[3] = 300;
5357 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
5367 if (!COM_ParseToken_Simple(&data, false, false))
5369 if (com_token[0] == '}')
5370 break; // end of entity
5371 if (com_token[0] == '_')
5372 strlcpy(key, com_token + 1, sizeof(key));
5374 strlcpy(key, com_token, sizeof(key));
5375 while (key[strlen(key)-1] == ' ') // remove trailing spaces
5376 key[strlen(key)-1] = 0;
5377 if (!COM_ParseToken_Simple(&data, false, false))
5379 strlcpy(value, com_token, sizeof(value));
5381 // now that we have the key pair worked out...
5382 if (!strcmp("light", key))
5384 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5388 light[0] = vec[0] * (1.0f / 256.0f);
5389 light[1] = vec[0] * (1.0f / 256.0f);
5390 light[2] = vec[0] * (1.0f / 256.0f);
5396 light[0] = vec[0] * (1.0f / 255.0f);
5397 light[1] = vec[1] * (1.0f / 255.0f);
5398 light[2] = vec[2] * (1.0f / 255.0f);
5402 else if (!strcmp("delay", key))
5404 else if (!strcmp("origin", key))
5405 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5406 else if (!strcmp("angle", key))
5407 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5408 else if (!strcmp("angles", key))
5409 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5410 else if (!strcmp("color", key))
5411 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5412 else if (!strcmp("wait", key))
5413 fadescale = atof(value);
5414 else if (!strcmp("classname", key))
5416 if (!strncmp(value, "light", 5))
5419 if (!strcmp(value, "light_fluoro"))
5424 overridecolor[0] = 1;
5425 overridecolor[1] = 1;
5426 overridecolor[2] = 1;
5428 if (!strcmp(value, "light_fluorospark"))
5433 overridecolor[0] = 1;
5434 overridecolor[1] = 1;
5435 overridecolor[2] = 1;
5437 if (!strcmp(value, "light_globe"))
5442 overridecolor[0] = 1;
5443 overridecolor[1] = 0.8;
5444 overridecolor[2] = 0.4;
5446 if (!strcmp(value, "light_flame_large_yellow"))
5451 overridecolor[0] = 1;
5452 overridecolor[1] = 0.5;
5453 overridecolor[2] = 0.1;
5455 if (!strcmp(value, "light_flame_small_yellow"))
5460 overridecolor[0] = 1;
5461 overridecolor[1] = 0.5;
5462 overridecolor[2] = 0.1;
5464 if (!strcmp(value, "light_torch_small_white"))
5469 overridecolor[0] = 1;
5470 overridecolor[1] = 0.5;
5471 overridecolor[2] = 0.1;
5473 if (!strcmp(value, "light_torch_small_walltorch"))
5478 overridecolor[0] = 1;
5479 overridecolor[1] = 0.5;
5480 overridecolor[2] = 0.1;
5484 else if (!strcmp("style", key))
5485 style = atoi(value);
5486 else if (!strcmp("skin", key))
5487 skin = (int)atof(value);
5488 else if (!strcmp("pflags", key))
5489 pflags = (int)atof(value);
5490 //else if (!strcmp("effects", key))
5491 // effects = (int)atof(value);
5492 else if (cl.worldmodel->type == mod_brushq3)
5494 if (!strcmp("scale", key))
5495 lightscale = atof(value);
5496 if (!strcmp("fade", key))
5497 fadescale = atof(value);
5502 if (lightscale <= 0)
5506 if (color[0] == color[1] && color[0] == color[2])
5508 color[0] *= overridecolor[0];
5509 color[1] *= overridecolor[1];
5510 color[2] *= overridecolor[2];
5512 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5513 color[0] = color[0] * light[0];
5514 color[1] = color[1] * light[1];
5515 color[2] = color[2] * light[2];
5518 case LIGHTTYPE_MINUSX:
5520 case LIGHTTYPE_RECIPX:
5522 VectorScale(color, (1.0f / 16.0f), color);
5524 case LIGHTTYPE_RECIPXX:
5526 VectorScale(color, (1.0f / 16.0f), color);
5529 case LIGHTTYPE_NONE:
5533 case LIGHTTYPE_MINUSXX:
5536 VectorAdd(origin, originhack, origin);
5538 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);
5541 Mem_Free(entfiledata);
5545 void R_Shadow_SetCursorLocationForView(void)
5548 vec3_t dest, endpos;
5550 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5551 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
5552 if (trace.fraction < 1)
5554 dist = trace.fraction * r_editlights_cursordistance.value;
5555 push = r_editlights_cursorpushback.value;
5559 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5560 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5564 VectorClear( endpos );
5566 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5567 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5568 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5571 void R_Shadow_UpdateWorldLightSelection(void)
5573 if (r_editlights.integer)
5575 R_Shadow_SetCursorLocationForView();
5576 R_Shadow_SelectLightInView();
5579 R_Shadow_SelectLight(NULL);
5582 void R_Shadow_EditLights_Clear_f(void)
5584 R_Shadow_ClearWorldLights();
5587 void R_Shadow_EditLights_Reload_f(void)
5591 strlcpy(r_shadow_mapname, cl.worldname, sizeof(r_shadow_mapname));
5592 R_Shadow_ClearWorldLights();
5593 R_Shadow_LoadWorldLights();
5594 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5596 R_Shadow_LoadLightsFile();
5597 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5598 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5602 void R_Shadow_EditLights_Save_f(void)
5606 R_Shadow_SaveWorldLights();
5609 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
5611 R_Shadow_ClearWorldLights();
5612 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5615 void R_Shadow_EditLights_ImportLightsFile_f(void)
5617 R_Shadow_ClearWorldLights();
5618 R_Shadow_LoadLightsFile();
5621 void R_Shadow_EditLights_Spawn_f(void)
5624 if (!r_editlights.integer)
5626 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5629 if (Cmd_Argc() != 1)
5631 Con_Print("r_editlights_spawn does not take parameters\n");
5634 color[0] = color[1] = color[2] = 1;
5635 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5638 void R_Shadow_EditLights_Edit_f(void)
5640 vec3_t origin, angles, color;
5641 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5642 int style, shadows, flags, normalmode, realtimemode;
5643 char cubemapname[MAX_INPUTLINE];
5644 if (!r_editlights.integer)
5646 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5649 if (!r_shadow_selectedlight)
5651 Con_Print("No selected light.\n");
5654 VectorCopy(r_shadow_selectedlight->origin, origin);
5655 VectorCopy(r_shadow_selectedlight->angles, angles);
5656 VectorCopy(r_shadow_selectedlight->color, color);
5657 radius = r_shadow_selectedlight->radius;
5658 style = r_shadow_selectedlight->style;
5659 if (r_shadow_selectedlight->cubemapname)
5660 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5663 shadows = r_shadow_selectedlight->shadow;
5664 corona = r_shadow_selectedlight->corona;
5665 coronasizescale = r_shadow_selectedlight->coronasizescale;
5666 ambientscale = r_shadow_selectedlight->ambientscale;
5667 diffusescale = r_shadow_selectedlight->diffusescale;
5668 specularscale = r_shadow_selectedlight->specularscale;
5669 flags = r_shadow_selectedlight->flags;
5670 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5671 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5672 if (!strcmp(Cmd_Argv(1), "origin"))
5674 if (Cmd_Argc() != 5)
5676 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5679 origin[0] = atof(Cmd_Argv(2));
5680 origin[1] = atof(Cmd_Argv(3));
5681 origin[2] = atof(Cmd_Argv(4));
5683 else if (!strcmp(Cmd_Argv(1), "originx"))
5685 if (Cmd_Argc() != 3)
5687 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5690 origin[0] = atof(Cmd_Argv(2));
5692 else if (!strcmp(Cmd_Argv(1), "originy"))
5694 if (Cmd_Argc() != 3)
5696 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5699 origin[1] = atof(Cmd_Argv(2));
5701 else if (!strcmp(Cmd_Argv(1), "originz"))
5703 if (Cmd_Argc() != 3)
5705 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5708 origin[2] = atof(Cmd_Argv(2));
5710 else if (!strcmp(Cmd_Argv(1), "move"))
5712 if (Cmd_Argc() != 5)
5714 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5717 origin[0] += atof(Cmd_Argv(2));
5718 origin[1] += atof(Cmd_Argv(3));
5719 origin[2] += atof(Cmd_Argv(4));
5721 else if (!strcmp(Cmd_Argv(1), "movex"))
5723 if (Cmd_Argc() != 3)
5725 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5728 origin[0] += atof(Cmd_Argv(2));
5730 else if (!strcmp(Cmd_Argv(1), "movey"))
5732 if (Cmd_Argc() != 3)
5734 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5737 origin[1] += atof(Cmd_Argv(2));
5739 else if (!strcmp(Cmd_Argv(1), "movez"))
5741 if (Cmd_Argc() != 3)
5743 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5746 origin[2] += atof(Cmd_Argv(2));
5748 else if (!strcmp(Cmd_Argv(1), "angles"))
5750 if (Cmd_Argc() != 5)
5752 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5755 angles[0] = atof(Cmd_Argv(2));
5756 angles[1] = atof(Cmd_Argv(3));
5757 angles[2] = atof(Cmd_Argv(4));
5759 else if (!strcmp(Cmd_Argv(1), "anglesx"))
5761 if (Cmd_Argc() != 3)
5763 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5766 angles[0] = atof(Cmd_Argv(2));
5768 else if (!strcmp(Cmd_Argv(1), "anglesy"))
5770 if (Cmd_Argc() != 3)
5772 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5775 angles[1] = atof(Cmd_Argv(2));
5777 else if (!strcmp(Cmd_Argv(1), "anglesz"))
5779 if (Cmd_Argc() != 3)
5781 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5784 angles[2] = atof(Cmd_Argv(2));
5786 else if (!strcmp(Cmd_Argv(1), "color"))
5788 if (Cmd_Argc() != 5)
5790 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
5793 color[0] = atof(Cmd_Argv(2));
5794 color[1] = atof(Cmd_Argv(3));
5795 color[2] = atof(Cmd_Argv(4));
5797 else if (!strcmp(Cmd_Argv(1), "radius"))
5799 if (Cmd_Argc() != 3)
5801 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5804 radius = atof(Cmd_Argv(2));
5806 else if (!strcmp(Cmd_Argv(1), "colorscale"))
5808 if (Cmd_Argc() == 3)
5810 double scale = atof(Cmd_Argv(2));
5817 if (Cmd_Argc() != 5)
5819 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
5822 color[0] *= atof(Cmd_Argv(2));
5823 color[1] *= atof(Cmd_Argv(3));
5824 color[2] *= atof(Cmd_Argv(4));
5827 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
5829 if (Cmd_Argc() != 3)
5831 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5834 radius *= atof(Cmd_Argv(2));
5836 else if (!strcmp(Cmd_Argv(1), "style"))
5838 if (Cmd_Argc() != 3)
5840 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5843 style = atoi(Cmd_Argv(2));
5845 else if (!strcmp(Cmd_Argv(1), "cubemap"))
5849 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5852 if (Cmd_Argc() == 3)
5853 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
5857 else if (!strcmp(Cmd_Argv(1), "shadows"))
5859 if (Cmd_Argc() != 3)
5861 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5864 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5866 else if (!strcmp(Cmd_Argv(1), "corona"))
5868 if (Cmd_Argc() != 3)
5870 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5873 corona = atof(Cmd_Argv(2));
5875 else if (!strcmp(Cmd_Argv(1), "coronasize"))
5877 if (Cmd_Argc() != 3)
5879 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5882 coronasizescale = atof(Cmd_Argv(2));
5884 else if (!strcmp(Cmd_Argv(1), "ambient"))
5886 if (Cmd_Argc() != 3)
5888 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5891 ambientscale = atof(Cmd_Argv(2));
5893 else if (!strcmp(Cmd_Argv(1), "diffuse"))
5895 if (Cmd_Argc() != 3)
5897 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5900 diffusescale = atof(Cmd_Argv(2));
5902 else if (!strcmp(Cmd_Argv(1), "specular"))
5904 if (Cmd_Argc() != 3)
5906 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5909 specularscale = atof(Cmd_Argv(2));
5911 else if (!strcmp(Cmd_Argv(1), "normalmode"))
5913 if (Cmd_Argc() != 3)
5915 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5918 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5920 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
5922 if (Cmd_Argc() != 3)
5924 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5927 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5931 Con_Print("usage: r_editlights_edit [property] [value]\n");
5932 Con_Print("Selected light's properties:\n");
5933 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5934 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5935 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5936 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
5937 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
5938 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
5939 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5940 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
5941 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
5942 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
5943 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
5944 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
5945 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5946 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5949 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5950 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5953 void R_Shadow_EditLights_EditAll_f(void)
5956 dlight_t *light, *oldselected;
5959 if (!r_editlights.integer)
5961 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5965 oldselected = r_shadow_selectedlight;
5966 // EditLights doesn't seem to have a "remove" command or something so:
5967 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5968 for (lightindex = 0;lightindex < range;lightindex++)
5970 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5973 R_Shadow_SelectLight(light);
5974 R_Shadow_EditLights_Edit_f();
5976 // return to old selected (to not mess editing once selection is locked)
5977 R_Shadow_SelectLight(oldselected);
5980 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
5982 int lightnumber, lightcount;
5983 size_t lightindex, range;
5987 if (!r_editlights.integer)
5989 x = vid_conwidth.value - 240;
5991 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
5994 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5995 for (lightindex = 0;lightindex < range;lightindex++)
5997 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
6000 if (light == r_shadow_selectedlight)
6001 lightnumber = lightindex;
6004 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;
6005 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;
6007 if (r_shadow_selectedlight == NULL)
6009 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;
6010 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;
6011 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;
6012 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;
6013 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;
6014 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;
6015 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;
6016 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;
6017 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;
6018 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;
6019 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;
6020 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;
6021 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;
6022 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;
6023 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;
6026 void R_Shadow_EditLights_ToggleShadow_f(void)
6028 if (!r_editlights.integer)
6030 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6033 if (!r_shadow_selectedlight)
6035 Con_Print("No selected light.\n");
6038 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);
6041 void R_Shadow_EditLights_ToggleCorona_f(void)
6043 if (!r_editlights.integer)
6045 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
6048 if (!r_shadow_selectedlight)
6050 Con_Print("No selected light.\n");
6053 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);
6056 void R_Shadow_EditLights_Remove_f(void)
6058 if (!r_editlights.integer)
6060 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
6063 if (!r_shadow_selectedlight)
6065 Con_Print("No selected light.\n");
6068 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
6069 r_shadow_selectedlight = NULL;
6072 void R_Shadow_EditLights_Help_f(void)
6075 "Documentation on r_editlights system:\n"
6077 "r_editlights : enable/disable editing mode\n"
6078 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
6079 "r_editlights_cursorpushback : push back cursor this far from surface\n"
6080 "r_editlights_cursorpushoff : push cursor off surface this far\n"
6081 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
6082 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
6084 "r_editlights_help : this help\n"
6085 "r_editlights_clear : remove all lights\n"
6086 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
6087 "r_editlights_lock : lock selection to current light, if already locked - unlock\n"
6088 "r_editlights_save : save to .rtlights file\n"
6089 "r_editlights_spawn : create a light with default settings\n"
6090 "r_editlights_edit command : edit selected light - more documentation below\n"
6091 "r_editlights_remove : remove selected light\n"
6092 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
6093 "r_editlights_importlightentitiesfrommap : reload light entities\n"
6094 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
6096 "origin x y z : set light location\n"
6097 "originx x: set x component of light location\n"
6098 "originy y: set y component of light location\n"
6099 "originz z: set z component of light location\n"
6100 "move x y z : adjust light location\n"
6101 "movex x: adjust x component of light location\n"
6102 "movey y: adjust y component of light location\n"
6103 "movez z: adjust z component of light location\n"
6104 "angles x y z : set light angles\n"
6105 "anglesx x: set x component of light angles\n"
6106 "anglesy y: set y component of light angles\n"
6107 "anglesz z: set z component of light angles\n"
6108 "color r g b : set color of light (can be brighter than 1 1 1)\n"
6109 "radius radius : set radius (size) of light\n"
6110 "colorscale grey : multiply color of light (1 does nothing)\n"
6111 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
6112 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
6113 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
6114 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
6115 "cubemap basename : set filter cubemap of light (not yet supported)\n"
6116 "shadows 1/0 : turn on/off shadows\n"
6117 "corona n : set corona intensity\n"
6118 "coronasize n : set corona size (0-1)\n"
6119 "ambient n : set ambient intensity (0-1)\n"
6120 "diffuse n : set diffuse intensity (0-1)\n"
6121 "specular n : set specular intensity (0-1)\n"
6122 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
6123 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
6124 "<nothing> : print light properties to console\n"
6128 void R_Shadow_EditLights_CopyInfo_f(void)
6130 if (!r_editlights.integer)
6132 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
6135 if (!r_shadow_selectedlight)
6137 Con_Print("No selected light.\n");
6140 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
6141 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
6142 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
6143 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
6144 if (r_shadow_selectedlight->cubemapname)
6145 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
6147 r_shadow_bufferlight.cubemapname[0] = 0;
6148 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
6149 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
6150 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
6151 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
6152 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
6153 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
6154 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
6157 void R_Shadow_EditLights_PasteInfo_f(void)
6159 if (!r_editlights.integer)
6161 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
6164 if (!r_shadow_selectedlight)
6166 Con_Print("No selected light.\n");
6169 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);
6172 void R_Shadow_EditLights_Lock_f(void)
6174 if (!r_editlights.integer)
6176 Con_Print("Cannot lock on light when not in editing mode. Set r_editlights to 1.\n");
6179 if (r_editlights_lockcursor)
6181 r_editlights_lockcursor = false;
6184 if (!r_shadow_selectedlight)
6186 Con_Print("No selected light to lock on.\n");
6189 r_editlights_lockcursor = true;
6192 void R_Shadow_EditLights_Init(void)
6194 Cvar_RegisterVariable(&r_editlights);
6195 Cvar_RegisterVariable(&r_editlights_cursordistance);
6196 Cvar_RegisterVariable(&r_editlights_cursorpushback);
6197 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
6198 Cvar_RegisterVariable(&r_editlights_cursorgrid);
6199 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
6200 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
6201 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
6202 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)");
6203 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
6204 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
6205 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
6206 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)");
6207 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
6208 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
6209 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
6210 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
6211 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
6212 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
6213 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)");
6214 Cmd_AddCommand("r_editlights_lock", R_Shadow_EditLights_Lock_f, "lock selection to current light, if already locked - unlock");
6220 =============================================================================
6224 =============================================================================
6227 void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, int dynamic)
6229 VectorClear(diffusecolor);
6230 VectorClear(diffusenormal);
6232 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
6234 ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_refdef.scene.ambient;
6235 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
6238 VectorSet(ambientcolor, 1, 1, 1);
6245 for (i = 0;i < r_refdef.scene.numlights;i++)
6247 light = r_refdef.scene.lights[i];
6248 Matrix4x4_Transform(&light->matrix_worldtolight, p, v);
6249 f = 1 - VectorLength2(v);
6250 if (f > 0 && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
6251 VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);