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"
142 #include "dpsoftrast.h"
146 extern LPDIRECT3DDEVICE9 vid_d3d9dev;
149 extern void R_Shadow_EditLights_Init(void);
151 typedef enum r_shadow_rendermode_e
153 R_SHADOW_RENDERMODE_NONE,
154 R_SHADOW_RENDERMODE_ZPASS_STENCIL,
155 R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL,
156 R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE,
157 R_SHADOW_RENDERMODE_ZFAIL_STENCIL,
158 R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL,
159 R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE,
160 R_SHADOW_RENDERMODE_LIGHT_VERTEX,
161 R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN,
162 R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN,
163 R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN,
164 R_SHADOW_RENDERMODE_LIGHT_GLSL,
165 R_SHADOW_RENDERMODE_VISIBLEVOLUMES,
166 R_SHADOW_RENDERMODE_VISIBLELIGHTING,
167 R_SHADOW_RENDERMODE_SHADOWMAP2D
169 r_shadow_rendermode_t;
171 typedef enum r_shadow_shadowmode_e
173 R_SHADOW_SHADOWMODE_STENCIL,
174 R_SHADOW_SHADOWMODE_SHADOWMAP2D
176 r_shadow_shadowmode_t;
178 r_shadow_rendermode_t r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
179 r_shadow_rendermode_t r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_NONE;
180 r_shadow_rendermode_t r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_NONE;
181 r_shadow_rendermode_t r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_NONE;
182 qboolean r_shadow_usingshadowmap2d;
183 qboolean r_shadow_usingshadowmaportho;
184 int r_shadow_shadowmapside;
185 float r_shadow_shadowmap_texturescale[2];
186 float r_shadow_shadowmap_parameters[4];
188 int r_shadow_drawbuffer;
189 int r_shadow_readbuffer;
191 int r_shadow_cullface_front, r_shadow_cullface_back;
192 GLuint r_shadow_fbo2d;
193 r_shadow_shadowmode_t r_shadow_shadowmode;
194 int r_shadow_shadowmapfilterquality;
195 int r_shadow_shadowmapdepthbits;
196 int r_shadow_shadowmapmaxsize;
197 qboolean r_shadow_shadowmapvsdct;
198 qboolean r_shadow_shadowmapsampler;
199 int r_shadow_shadowmappcf;
200 int r_shadow_shadowmapborder;
201 matrix4x4_t r_shadow_shadowmapmatrix;
202 int r_shadow_lightscissor[4];
203 qboolean r_shadow_usingdeferredprepass;
205 int maxshadowtriangles;
208 int maxshadowvertices;
209 float *shadowvertex3f;
219 unsigned char *shadowsides;
220 int *shadowsideslist;
227 int r_shadow_buffer_numleafpvsbytes;
228 unsigned char *r_shadow_buffer_visitingleafpvs;
229 unsigned char *r_shadow_buffer_leafpvs;
230 int *r_shadow_buffer_leaflist;
232 int r_shadow_buffer_numsurfacepvsbytes;
233 unsigned char *r_shadow_buffer_surfacepvs;
234 int *r_shadow_buffer_surfacelist;
235 unsigned char *r_shadow_buffer_surfacesides;
237 int r_shadow_buffer_numshadowtrispvsbytes;
238 unsigned char *r_shadow_buffer_shadowtrispvs;
239 int r_shadow_buffer_numlighttrispvsbytes;
240 unsigned char *r_shadow_buffer_lighttrispvs;
242 rtexturepool_t *r_shadow_texturepool;
243 rtexture_t *r_shadow_attenuationgradienttexture;
244 rtexture_t *r_shadow_attenuation2dtexture;
245 rtexture_t *r_shadow_attenuation3dtexture;
246 skinframe_t *r_shadow_lightcorona;
247 rtexture_t *r_shadow_shadowmap2dtexture;
248 rtexture_t *r_shadow_shadowmap2dcolortexture;
249 rtexture_t *r_shadow_shadowmapvsdcttexture;
250 int r_shadow_shadowmapsize; // changes for each light based on distance
251 int r_shadow_shadowmaplod; // changes for each light based on distance
253 GLuint r_shadow_prepassgeometryfbo;
254 GLuint r_shadow_prepasslightingfbo;
255 int r_shadow_prepass_width;
256 int r_shadow_prepass_height;
257 rtexture_t *r_shadow_prepassgeometrydepthtexture;
258 rtexture_t *r_shadow_prepassgeometrydepthcolortexture;
259 rtexture_t *r_shadow_prepassgeometrynormalmaptexture;
260 rtexture_t *r_shadow_prepasslightingdiffusetexture;
261 rtexture_t *r_shadow_prepasslightingspeculartexture;
263 // lights are reloaded when this changes
264 char r_shadow_mapname[MAX_QPATH];
266 // used only for light filters (cubemaps)
267 rtexturepool_t *r_shadow_filters_texturepool;
269 static const GLenum r_shadow_prepasslightingdrawbuffers[2] = {GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT};
271 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"};
272 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"};
273 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
274 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"};
275 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)"};
276 //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"};
277 cvar_t r_shadow_usebihculling = {0, "r_shadow_usebihculling", "1", "use BIH (Bounding Interval Hierarchy) for culling lit surfaces instead of BSP (Binary Space Partitioning)"};
278 cvar_t r_shadow_usenormalmap = {CVAR_SAVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"};
279 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)"};
280 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"};
281 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
282 cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
283 cvar_t r_shadow_gloss2exponent = {0, "r_shadow_gloss2exponent", "32", "same as r_shadow_glossexponent but for forced gloss (gloss 2) surfaces"};
284 cvar_t r_shadow_glossexact = {0, "r_shadow_glossexact", "0", "use exact reflection math for gloss (slightly slower, but should look a tad better)"};
285 cvar_t r_shadow_lightattenuationdividebias = {0, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"};
286 cvar_t r_shadow_lightattenuationlinearscale = {0, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"};
287 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
288 cvar_t r_shadow_lightradiusscale = {0, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
289 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "0", "how far to cast shadows"};
290 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)"};
291 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
292 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
293 cvar_t r_shadow_realtime_dlight_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
294 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
295 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)"};
296 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"};
297 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
298 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
299 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"};
300 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)"};
301 cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "1", "enables portal-based culling optimization during compilation (overrides compilesvbsp)"};
302 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)"};
303 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"};
304 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)"};
305 cvar_t r_shadow_shadowmapping_depthbits = {CVAR_SAVE, "r_shadow_shadowmapping_depthbits", "24", "requested minimum shadowmap texture depth bits"};
306 cvar_t r_shadow_shadowmapping_vsdct = {CVAR_SAVE, "r_shadow_shadowmapping_vsdct", "1", "enables use of virtual shadow depth cube texture"};
307 cvar_t r_shadow_shadowmapping_minsize = {CVAR_SAVE, "r_shadow_shadowmapping_minsize", "32", "shadowmap size limit"};
308 cvar_t r_shadow_shadowmapping_maxsize = {CVAR_SAVE, "r_shadow_shadowmapping_maxsize", "512", "shadowmap size limit"};
309 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"};
310 //cvar_t r_shadow_shadowmapping_lod_bias = {CVAR_SAVE, "r_shadow_shadowmapping_lod_bias", "16", "shadowmap size bias"};
311 //cvar_t r_shadow_shadowmapping_lod_scale = {CVAR_SAVE, "r_shadow_shadowmapping_lod_scale", "128", "shadowmap size scaling parameter"};
312 cvar_t r_shadow_shadowmapping_bordersize = {CVAR_SAVE, "r_shadow_shadowmapping_bordersize", "4", "shadowmap size bias for filtering"};
313 cvar_t r_shadow_shadowmapping_nearclip = {CVAR_SAVE, "r_shadow_shadowmapping_nearclip", "1", "shadowmap nearclip in world units"};
314 cvar_t r_shadow_shadowmapping_bias = {CVAR_SAVE, "r_shadow_shadowmapping_bias", "0.03", "shadowmap bias parameter (this is multiplied by nearclip * 1024 / lodsize)"};
315 cvar_t r_shadow_shadowmapping_polygonfactor = {CVAR_SAVE, "r_shadow_shadowmapping_polygonfactor", "2", "slope-dependent shadowmapping bias"};
316 cvar_t r_shadow_shadowmapping_polygonoffset = {CVAR_SAVE, "r_shadow_shadowmapping_polygonoffset", "0", "constant shadowmapping bias"};
317 cvar_t r_shadow_sortsurfaces = {0, "r_shadow_sortsurfaces", "1", "improve performance by sorting illuminated surfaces by texture"};
318 cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
319 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)"};
320 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)"};
321 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "1", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
322 cvar_t r_coronas_occlusionsizescale = {CVAR_SAVE, "r_coronas_occlusionsizescale", "0.1", "size of light source for corona occlusion checksum the proportion of hidden pixels controls corona intensity"};
323 cvar_t r_coronas_occlusionquery = {CVAR_SAVE, "r_coronas_occlusionquery", "1", "use GL_ARB_occlusion_query extension if supported (fades coronas according to visibility)"};
324 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
325 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
326 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
327 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
328 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
329 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
330 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
331 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
332 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
334 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
335 #define ATTENTABLESIZE 256
336 // 1D gradient, 2D circle and 3D sphere attenuation textures
337 #define ATTEN1DSIZE 32
338 #define ATTEN2DSIZE 64
339 #define ATTEN3DSIZE 32
341 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
342 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
343 static float r_shadow_attentable[ATTENTABLESIZE+1];
345 rtlight_t *r_shadow_compilingrtlight;
346 static memexpandablearray_t r_shadow_worldlightsarray;
347 dlight_t *r_shadow_selectedlight;
348 dlight_t r_shadow_bufferlight;
349 vec3_t r_editlights_cursorlocation;
350 qboolean r_editlights_lockcursor;
352 extern int con_vislines;
354 void R_Shadow_UncompileWorldLights(void);
355 void R_Shadow_ClearWorldLights(void);
356 void R_Shadow_SaveWorldLights(void);
357 void R_Shadow_LoadWorldLights(void);
358 void R_Shadow_LoadLightsFile(void);
359 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
360 void R_Shadow_EditLights_Reload_f(void);
361 void R_Shadow_ValidateCvars(void);
362 static void R_Shadow_MakeTextures(void);
364 #define EDLIGHTSPRSIZE 8
365 skinframe_t *r_editlights_sprcursor;
366 skinframe_t *r_editlights_sprlight;
367 skinframe_t *r_editlights_sprnoshadowlight;
368 skinframe_t *r_editlights_sprcubemaplight;
369 skinframe_t *r_editlights_sprcubemapnoshadowlight;
370 skinframe_t *r_editlights_sprselection;
372 void R_Shadow_SetShadowMode(void)
374 r_shadow_shadowmapmaxsize = bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4);
375 r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20;
376 r_shadow_shadowmapfilterquality = r_shadow_shadowmapping_filterquality.integer;
377 r_shadow_shadowmapdepthbits = r_shadow_shadowmapping_depthbits.integer;
378 r_shadow_shadowmapborder = bound(0, r_shadow_shadowmapping_bordersize.integer, 16);
379 r_shadow_shadowmaplod = -1;
380 r_shadow_shadowmapsize = 0;
381 r_shadow_shadowmapsampler = false;
382 r_shadow_shadowmappcf = 0;
383 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
384 if ((r_shadow_shadowmapping.integer || r_shadow_deferred.integer) && vid.support.ext_framebuffer_object)
386 switch(vid.renderpath)
388 case RENDERPATH_GL20:
389 if(r_shadow_shadowmapfilterquality < 0)
391 if(vid.support.amd_texture_texture4 || vid.support.arb_texture_gather)
392 r_shadow_shadowmappcf = 1;
393 else if(strstr(gl_vendor, "NVIDIA") || strstr(gl_renderer, "Radeon HD"))
395 r_shadow_shadowmapsampler = vid.support.arb_shadow;
396 r_shadow_shadowmappcf = 1;
398 else if(strstr(gl_vendor, "ATI"))
399 r_shadow_shadowmappcf = 1;
401 r_shadow_shadowmapsampler = vid.support.arb_shadow;
405 switch (r_shadow_shadowmapfilterquality)
408 r_shadow_shadowmapsampler = vid.support.arb_shadow;
411 r_shadow_shadowmapsampler = vid.support.arb_shadow;
412 r_shadow_shadowmappcf = 1;
415 r_shadow_shadowmappcf = 1;
418 r_shadow_shadowmappcf = 2;
422 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
423 // Cg has very little choice in depth texture sampling
425 r_shadow_shadowmapsampler = false;
427 case RENDERPATH_CGGL:
428 case RENDERPATH_D3D9:
429 case RENDERPATH_D3D10:
430 case RENDERPATH_D3D11:
431 case RENDERPATH_SOFT:
432 r_shadow_shadowmapsampler = false;
433 r_shadow_shadowmappcf = 1;
434 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
436 case RENDERPATH_GL13:
438 case RENDERPATH_GL11:
440 case RENDERPATH_GLES2:
446 qboolean R_Shadow_ShadowMappingEnabled(void)
448 switch (r_shadow_shadowmode)
450 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
457 void R_Shadow_FreeShadowMaps(void)
459 R_Shadow_SetShadowMode();
461 R_Mesh_DestroyFramebufferObject(r_shadow_fbo2d);
465 if (r_shadow_shadowmap2dtexture)
466 R_FreeTexture(r_shadow_shadowmap2dtexture);
467 r_shadow_shadowmap2dtexture = NULL;
469 if (r_shadow_shadowmap2dcolortexture)
470 R_FreeTexture(r_shadow_shadowmap2dcolortexture);
471 r_shadow_shadowmap2dcolortexture = NULL;
473 if (r_shadow_shadowmapvsdcttexture)
474 R_FreeTexture(r_shadow_shadowmapvsdcttexture);
475 r_shadow_shadowmapvsdcttexture = NULL;
478 void r_shadow_start(void)
480 // allocate vertex processing arrays
481 r_shadow_attenuationgradienttexture = NULL;
482 r_shadow_attenuation2dtexture = NULL;
483 r_shadow_attenuation3dtexture = NULL;
484 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
485 r_shadow_shadowmap2dtexture = NULL;
486 r_shadow_shadowmap2dcolortexture = NULL;
487 r_shadow_shadowmapvsdcttexture = NULL;
488 r_shadow_shadowmapmaxsize = 0;
489 r_shadow_shadowmapsize = 0;
490 r_shadow_shadowmaplod = 0;
491 r_shadow_shadowmapfilterquality = -1;
492 r_shadow_shadowmapdepthbits = 0;
493 r_shadow_shadowmapvsdct = false;
494 r_shadow_shadowmapsampler = false;
495 r_shadow_shadowmappcf = 0;
498 R_Shadow_FreeShadowMaps();
500 r_shadow_texturepool = NULL;
501 r_shadow_filters_texturepool = NULL;
502 R_Shadow_ValidateCvars();
503 R_Shadow_MakeTextures();
504 maxshadowtriangles = 0;
505 shadowelements = NULL;
506 maxshadowvertices = 0;
507 shadowvertex3f = NULL;
515 shadowmarklist = NULL;
520 shadowsideslist = NULL;
521 r_shadow_buffer_numleafpvsbytes = 0;
522 r_shadow_buffer_visitingleafpvs = NULL;
523 r_shadow_buffer_leafpvs = NULL;
524 r_shadow_buffer_leaflist = NULL;
525 r_shadow_buffer_numsurfacepvsbytes = 0;
526 r_shadow_buffer_surfacepvs = NULL;
527 r_shadow_buffer_surfacelist = NULL;
528 r_shadow_buffer_surfacesides = NULL;
529 r_shadow_buffer_numshadowtrispvsbytes = 0;
530 r_shadow_buffer_shadowtrispvs = NULL;
531 r_shadow_buffer_numlighttrispvsbytes = 0;
532 r_shadow_buffer_lighttrispvs = NULL;
534 r_shadow_usingdeferredprepass = false;
535 r_shadow_prepass_width = r_shadow_prepass_height = 0;
538 static void R_Shadow_FreeDeferred(void);
539 void r_shadow_shutdown(void)
542 R_Shadow_UncompileWorldLights();
544 R_Shadow_FreeShadowMaps();
546 r_shadow_usingdeferredprepass = false;
547 if (r_shadow_prepass_width)
548 R_Shadow_FreeDeferred();
549 r_shadow_prepass_width = r_shadow_prepass_height = 0;
552 r_shadow_attenuationgradienttexture = NULL;
553 r_shadow_attenuation2dtexture = NULL;
554 r_shadow_attenuation3dtexture = NULL;
555 R_FreeTexturePool(&r_shadow_texturepool);
556 R_FreeTexturePool(&r_shadow_filters_texturepool);
557 maxshadowtriangles = 0;
559 Mem_Free(shadowelements);
560 shadowelements = NULL;
562 Mem_Free(shadowvertex3f);
563 shadowvertex3f = NULL;
566 Mem_Free(vertexupdate);
569 Mem_Free(vertexremap);
575 Mem_Free(shadowmark);
578 Mem_Free(shadowmarklist);
579 shadowmarklist = NULL;
584 Mem_Free(shadowsides);
587 Mem_Free(shadowsideslist);
588 shadowsideslist = NULL;
589 r_shadow_buffer_numleafpvsbytes = 0;
590 if (r_shadow_buffer_visitingleafpvs)
591 Mem_Free(r_shadow_buffer_visitingleafpvs);
592 r_shadow_buffer_visitingleafpvs = NULL;
593 if (r_shadow_buffer_leafpvs)
594 Mem_Free(r_shadow_buffer_leafpvs);
595 r_shadow_buffer_leafpvs = NULL;
596 if (r_shadow_buffer_leaflist)
597 Mem_Free(r_shadow_buffer_leaflist);
598 r_shadow_buffer_leaflist = NULL;
599 r_shadow_buffer_numsurfacepvsbytes = 0;
600 if (r_shadow_buffer_surfacepvs)
601 Mem_Free(r_shadow_buffer_surfacepvs);
602 r_shadow_buffer_surfacepvs = NULL;
603 if (r_shadow_buffer_surfacelist)
604 Mem_Free(r_shadow_buffer_surfacelist);
605 r_shadow_buffer_surfacelist = NULL;
606 if (r_shadow_buffer_surfacesides)
607 Mem_Free(r_shadow_buffer_surfacesides);
608 r_shadow_buffer_surfacesides = NULL;
609 r_shadow_buffer_numshadowtrispvsbytes = 0;
610 if (r_shadow_buffer_shadowtrispvs)
611 Mem_Free(r_shadow_buffer_shadowtrispvs);
612 r_shadow_buffer_numlighttrispvsbytes = 0;
613 if (r_shadow_buffer_lighttrispvs)
614 Mem_Free(r_shadow_buffer_lighttrispvs);
617 void r_shadow_newmap(void)
619 if (r_shadow_lightcorona) R_SkinFrame_MarkUsed(r_shadow_lightcorona);
620 if (r_editlights_sprcursor) R_SkinFrame_MarkUsed(r_editlights_sprcursor);
621 if (r_editlights_sprlight) R_SkinFrame_MarkUsed(r_editlights_sprlight);
622 if (r_editlights_sprnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprnoshadowlight);
623 if (r_editlights_sprcubemaplight) R_SkinFrame_MarkUsed(r_editlights_sprcubemaplight);
624 if (r_editlights_sprcubemapnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprcubemapnoshadowlight);
625 if (r_editlights_sprselection) R_SkinFrame_MarkUsed(r_editlights_sprselection);
626 if (strncmp(cl.worldname, r_shadow_mapname, sizeof(r_shadow_mapname)))
627 R_Shadow_EditLights_Reload_f();
630 void R_Shadow_Init(void)
632 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
633 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
634 Cvar_RegisterVariable(&r_shadow_usebihculling);
635 Cvar_RegisterVariable(&r_shadow_usenormalmap);
636 Cvar_RegisterVariable(&r_shadow_debuglight);
637 Cvar_RegisterVariable(&r_shadow_deferred);
638 Cvar_RegisterVariable(&r_shadow_deferred_8bitrange);
639 // Cvar_RegisterVariable(&r_shadow_deferred_fp);
640 Cvar_RegisterVariable(&r_shadow_gloss);
641 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
642 Cvar_RegisterVariable(&r_shadow_glossintensity);
643 Cvar_RegisterVariable(&r_shadow_glossexponent);
644 Cvar_RegisterVariable(&r_shadow_gloss2exponent);
645 Cvar_RegisterVariable(&r_shadow_glossexact);
646 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
647 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
648 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
649 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
650 Cvar_RegisterVariable(&r_shadow_projectdistance);
651 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
652 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
653 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
654 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
655 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
656 Cvar_RegisterVariable(&r_shadow_realtime_world);
657 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
658 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
659 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
660 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
661 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
662 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
663 Cvar_RegisterVariable(&r_shadow_scissor);
664 Cvar_RegisterVariable(&r_shadow_shadowmapping);
665 Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
666 Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
667 Cvar_RegisterVariable(&r_shadow_shadowmapping_depthbits);
668 Cvar_RegisterVariable(&r_shadow_shadowmapping_precision);
669 Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
670 Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
671 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
672 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
673 Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
674 Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
675 Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
676 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonfactor);
677 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonoffset);
678 Cvar_RegisterVariable(&r_shadow_sortsurfaces);
679 Cvar_RegisterVariable(&r_shadow_polygonfactor);
680 Cvar_RegisterVariable(&r_shadow_polygonoffset);
681 Cvar_RegisterVariable(&r_shadow_texture3d);
682 Cvar_RegisterVariable(&r_coronas);
683 Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
684 Cvar_RegisterVariable(&r_coronas_occlusionquery);
685 Cvar_RegisterVariable(&gl_flashblend);
686 Cvar_RegisterVariable(&gl_ext_separatestencil);
687 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
688 if (gamemode == GAME_TENEBRAE)
690 Cvar_SetValue("r_shadow_gloss", 2);
691 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
693 R_Shadow_EditLights_Init();
694 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
695 maxshadowtriangles = 0;
696 shadowelements = NULL;
697 maxshadowvertices = 0;
698 shadowvertex3f = NULL;
706 shadowmarklist = NULL;
711 shadowsideslist = NULL;
712 r_shadow_buffer_numleafpvsbytes = 0;
713 r_shadow_buffer_visitingleafpvs = NULL;
714 r_shadow_buffer_leafpvs = NULL;
715 r_shadow_buffer_leaflist = NULL;
716 r_shadow_buffer_numsurfacepvsbytes = 0;
717 r_shadow_buffer_surfacepvs = NULL;
718 r_shadow_buffer_surfacelist = NULL;
719 r_shadow_buffer_surfacesides = NULL;
720 r_shadow_buffer_shadowtrispvs = NULL;
721 r_shadow_buffer_lighttrispvs = NULL;
722 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap, NULL, NULL);
725 matrix4x4_t matrix_attenuationxyz =
728 {0.5, 0.0, 0.0, 0.5},
729 {0.0, 0.5, 0.0, 0.5},
730 {0.0, 0.0, 0.5, 0.5},
735 matrix4x4_t matrix_attenuationz =
738 {0.0, 0.0, 0.5, 0.5},
739 {0.0, 0.0, 0.0, 0.5},
740 {0.0, 0.0, 0.0, 0.5},
745 void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles, int vertscale, int triscale)
747 numvertices = ((numvertices + 255) & ~255) * vertscale;
748 numtriangles = ((numtriangles + 255) & ~255) * triscale;
749 // make sure shadowelements is big enough for this volume
750 if (maxshadowtriangles < numtriangles)
752 maxshadowtriangles = numtriangles;
754 Mem_Free(shadowelements);
755 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[3]));
757 // make sure shadowvertex3f is big enough for this volume
758 if (maxshadowvertices < numvertices)
760 maxshadowvertices = numvertices;
762 Mem_Free(shadowvertex3f);
763 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[3]));
767 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
769 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
770 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
771 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
772 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
773 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
775 if (r_shadow_buffer_visitingleafpvs)
776 Mem_Free(r_shadow_buffer_visitingleafpvs);
777 if (r_shadow_buffer_leafpvs)
778 Mem_Free(r_shadow_buffer_leafpvs);
779 if (r_shadow_buffer_leaflist)
780 Mem_Free(r_shadow_buffer_leaflist);
781 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
782 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
783 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
784 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
786 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
788 if (r_shadow_buffer_surfacepvs)
789 Mem_Free(r_shadow_buffer_surfacepvs);
790 if (r_shadow_buffer_surfacelist)
791 Mem_Free(r_shadow_buffer_surfacelist);
792 if (r_shadow_buffer_surfacesides)
793 Mem_Free(r_shadow_buffer_surfacesides);
794 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
795 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
796 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
797 r_shadow_buffer_surfacesides = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
799 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
801 if (r_shadow_buffer_shadowtrispvs)
802 Mem_Free(r_shadow_buffer_shadowtrispvs);
803 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
804 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
806 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
808 if (r_shadow_buffer_lighttrispvs)
809 Mem_Free(r_shadow_buffer_lighttrispvs);
810 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
811 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
815 void R_Shadow_PrepareShadowMark(int numtris)
817 // make sure shadowmark is big enough for this volume
818 if (maxshadowmark < numtris)
820 maxshadowmark = numtris;
822 Mem_Free(shadowmark);
824 Mem_Free(shadowmarklist);
825 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
826 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
830 // if shadowmarkcount wrapped we clear the array and adjust accordingly
831 if (shadowmarkcount == 0)
834 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
839 void R_Shadow_PrepareShadowSides(int numtris)
841 if (maxshadowsides < numtris)
843 maxshadowsides = numtris;
845 Mem_Free(shadowsides);
847 Mem_Free(shadowsideslist);
848 shadowsides = (unsigned char *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsides));
849 shadowsideslist = (int *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsideslist));
854 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)
857 int outtriangles = 0, outvertices = 0;
860 float ratio, direction[3], projectvector[3];
862 if (projectdirection)
863 VectorScale(projectdirection, projectdistance, projectvector);
865 VectorClear(projectvector);
867 // create the vertices
868 if (projectdirection)
870 for (i = 0;i < numshadowmarktris;i++)
872 element = inelement3i + shadowmarktris[i] * 3;
873 for (j = 0;j < 3;j++)
875 if (vertexupdate[element[j]] != vertexupdatenum)
877 vertexupdate[element[j]] = vertexupdatenum;
878 vertexremap[element[j]] = outvertices;
879 vertex = invertex3f + element[j] * 3;
880 // project one copy of the vertex according to projectvector
881 VectorCopy(vertex, outvertex3f);
882 VectorAdd(vertex, projectvector, (outvertex3f + 3));
891 for (i = 0;i < numshadowmarktris;i++)
893 element = inelement3i + shadowmarktris[i] * 3;
894 for (j = 0;j < 3;j++)
896 if (vertexupdate[element[j]] != vertexupdatenum)
898 vertexupdate[element[j]] = vertexupdatenum;
899 vertexremap[element[j]] = outvertices;
900 vertex = invertex3f + element[j] * 3;
901 // project one copy of the vertex to the sphere radius of the light
902 // (FIXME: would projecting it to the light box be better?)
903 VectorSubtract(vertex, projectorigin, direction);
904 ratio = projectdistance / VectorLength(direction);
905 VectorCopy(vertex, outvertex3f);
906 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
914 if (r_shadow_frontsidecasting.integer)
916 for (i = 0;i < numshadowmarktris;i++)
918 int remappedelement[3];
920 const int *neighbortriangle;
922 markindex = shadowmarktris[i] * 3;
923 element = inelement3i + markindex;
924 neighbortriangle = inneighbor3i + markindex;
925 // output the front and back triangles
926 outelement3i[0] = vertexremap[element[0]];
927 outelement3i[1] = vertexremap[element[1]];
928 outelement3i[2] = vertexremap[element[2]];
929 outelement3i[3] = vertexremap[element[2]] + 1;
930 outelement3i[4] = vertexremap[element[1]] + 1;
931 outelement3i[5] = vertexremap[element[0]] + 1;
935 // output the sides (facing outward from this triangle)
936 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
938 remappedelement[0] = vertexremap[element[0]];
939 remappedelement[1] = vertexremap[element[1]];
940 outelement3i[0] = remappedelement[1];
941 outelement3i[1] = remappedelement[0];
942 outelement3i[2] = remappedelement[0] + 1;
943 outelement3i[3] = remappedelement[1];
944 outelement3i[4] = remappedelement[0] + 1;
945 outelement3i[5] = remappedelement[1] + 1;
950 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
952 remappedelement[1] = vertexremap[element[1]];
953 remappedelement[2] = vertexremap[element[2]];
954 outelement3i[0] = remappedelement[2];
955 outelement3i[1] = remappedelement[1];
956 outelement3i[2] = remappedelement[1] + 1;
957 outelement3i[3] = remappedelement[2];
958 outelement3i[4] = remappedelement[1] + 1;
959 outelement3i[5] = remappedelement[2] + 1;
964 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
966 remappedelement[0] = vertexremap[element[0]];
967 remappedelement[2] = vertexremap[element[2]];
968 outelement3i[0] = remappedelement[0];
969 outelement3i[1] = remappedelement[2];
970 outelement3i[2] = remappedelement[2] + 1;
971 outelement3i[3] = remappedelement[0];
972 outelement3i[4] = remappedelement[2] + 1;
973 outelement3i[5] = remappedelement[0] + 1;
982 for (i = 0;i < numshadowmarktris;i++)
984 int remappedelement[3];
986 const int *neighbortriangle;
988 markindex = shadowmarktris[i] * 3;
989 element = inelement3i + markindex;
990 neighbortriangle = inneighbor3i + markindex;
991 // output the front and back triangles
992 outelement3i[0] = vertexremap[element[2]];
993 outelement3i[1] = vertexremap[element[1]];
994 outelement3i[2] = vertexremap[element[0]];
995 outelement3i[3] = vertexremap[element[0]] + 1;
996 outelement3i[4] = vertexremap[element[1]] + 1;
997 outelement3i[5] = vertexremap[element[2]] + 1;
1001 // output the sides (facing outward from this triangle)
1002 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
1004 remappedelement[0] = vertexremap[element[0]];
1005 remappedelement[1] = vertexremap[element[1]];
1006 outelement3i[0] = remappedelement[0];
1007 outelement3i[1] = remappedelement[1];
1008 outelement3i[2] = remappedelement[1] + 1;
1009 outelement3i[3] = remappedelement[0];
1010 outelement3i[4] = remappedelement[1] + 1;
1011 outelement3i[5] = remappedelement[0] + 1;
1016 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1018 remappedelement[1] = vertexremap[element[1]];
1019 remappedelement[2] = vertexremap[element[2]];
1020 outelement3i[0] = remappedelement[1];
1021 outelement3i[1] = remappedelement[2];
1022 outelement3i[2] = remappedelement[2] + 1;
1023 outelement3i[3] = remappedelement[1];
1024 outelement3i[4] = remappedelement[2] + 1;
1025 outelement3i[5] = remappedelement[1] + 1;
1030 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1032 remappedelement[0] = vertexremap[element[0]];
1033 remappedelement[2] = vertexremap[element[2]];
1034 outelement3i[0] = remappedelement[2];
1035 outelement3i[1] = remappedelement[0];
1036 outelement3i[2] = remappedelement[0] + 1;
1037 outelement3i[3] = remappedelement[2];
1038 outelement3i[4] = remappedelement[0] + 1;
1039 outelement3i[5] = remappedelement[2] + 1;
1047 *outnumvertices = outvertices;
1048 return outtriangles;
1051 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)
1054 int outtriangles = 0, outvertices = 0;
1056 const float *vertex;
1057 float ratio, direction[3], projectvector[3];
1060 if (projectdirection)
1061 VectorScale(projectdirection, projectdistance, projectvector);
1063 VectorClear(projectvector);
1065 for (i = 0;i < numshadowmarktris;i++)
1067 int remappedelement[3];
1069 const int *neighbortriangle;
1071 markindex = shadowmarktris[i] * 3;
1072 neighbortriangle = inneighbor3i + markindex;
1073 side[0] = shadowmark[neighbortriangle[0]] == shadowmarkcount;
1074 side[1] = shadowmark[neighbortriangle[1]] == shadowmarkcount;
1075 side[2] = shadowmark[neighbortriangle[2]] == shadowmarkcount;
1076 if (side[0] + side[1] + side[2] == 0)
1080 element = inelement3i + markindex;
1082 // create the vertices
1083 for (j = 0;j < 3;j++)
1085 if (side[j] + side[j+1] == 0)
1088 if (vertexupdate[k] != vertexupdatenum)
1090 vertexupdate[k] = vertexupdatenum;
1091 vertexremap[k] = outvertices;
1092 vertex = invertex3f + k * 3;
1093 VectorCopy(vertex, outvertex3f);
1094 if (projectdirection)
1096 // project one copy of the vertex according to projectvector
1097 VectorAdd(vertex, projectvector, (outvertex3f + 3));
1101 // project one copy of the vertex to the sphere radius of the light
1102 // (FIXME: would projecting it to the light box be better?)
1103 VectorSubtract(vertex, projectorigin, direction);
1104 ratio = projectdistance / VectorLength(direction);
1105 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1112 // output the sides (facing outward from this triangle)
1115 remappedelement[0] = vertexremap[element[0]];
1116 remappedelement[1] = vertexremap[element[1]];
1117 outelement3i[0] = remappedelement[1];
1118 outelement3i[1] = remappedelement[0];
1119 outelement3i[2] = remappedelement[0] + 1;
1120 outelement3i[3] = remappedelement[1];
1121 outelement3i[4] = remappedelement[0] + 1;
1122 outelement3i[5] = remappedelement[1] + 1;
1129 remappedelement[1] = vertexremap[element[1]];
1130 remappedelement[2] = vertexremap[element[2]];
1131 outelement3i[0] = remappedelement[2];
1132 outelement3i[1] = remappedelement[1];
1133 outelement3i[2] = remappedelement[1] + 1;
1134 outelement3i[3] = remappedelement[2];
1135 outelement3i[4] = remappedelement[1] + 1;
1136 outelement3i[5] = remappedelement[2] + 1;
1143 remappedelement[0] = vertexremap[element[0]];
1144 remappedelement[2] = vertexremap[element[2]];
1145 outelement3i[0] = remappedelement[0];
1146 outelement3i[1] = remappedelement[2];
1147 outelement3i[2] = remappedelement[2] + 1;
1148 outelement3i[3] = remappedelement[0];
1149 outelement3i[4] = remappedelement[2] + 1;
1150 outelement3i[5] = remappedelement[0] + 1;
1157 *outnumvertices = outvertices;
1158 return outtriangles;
1161 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)
1167 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1169 tend = firsttriangle + numtris;
1170 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1172 // surface box entirely inside light box, no box cull
1173 if (projectdirection)
1175 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1177 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
1178 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1179 shadowmarklist[numshadowmark++] = t;
1184 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1185 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
1186 shadowmarklist[numshadowmark++] = t;
1191 // surface box not entirely inside light box, cull each triangle
1192 if (projectdirection)
1194 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1196 v[0] = invertex3f + e[0] * 3;
1197 v[1] = invertex3f + e[1] * 3;
1198 v[2] = invertex3f + e[2] * 3;
1199 TriangleNormal(v[0], v[1], v[2], normal);
1200 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1201 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1202 shadowmarklist[numshadowmark++] = t;
1207 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1209 v[0] = invertex3f + e[0] * 3;
1210 v[1] = invertex3f + e[1] * 3;
1211 v[2] = invertex3f + e[2] * 3;
1212 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1213 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1214 shadowmarklist[numshadowmark++] = t;
1220 qboolean R_Shadow_UseZPass(vec3_t mins, vec3_t maxs)
1225 if (r_shadow_compilingrtlight || !r_shadow_frontsidecasting.integer || !r_shadow_usezpassifpossible.integer)
1227 // check if the shadow volume intersects the near plane
1229 // a ray between the eye and light origin may intersect the caster,
1230 // indicating that the shadow may touch the eye location, however we must
1231 // test the near plane (a polygon), not merely the eye location, so it is
1232 // easiest to enlarge the caster bounding shape slightly for this.
1238 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)
1240 int i, tris, outverts;
1241 if (projectdistance < 0.1)
1243 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
1246 if (!numverts || !nummarktris)
1248 // make sure shadowelements is big enough for this volume
1249 if (maxshadowtriangles < nummarktris*8 || maxshadowvertices < numverts*2)
1250 R_Shadow_ResizeShadowArrays(numverts, nummarktris, 2, 8);
1252 if (maxvertexupdate < numverts)
1254 maxvertexupdate = numverts;
1256 Mem_Free(vertexupdate);
1258 Mem_Free(vertexremap);
1259 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1260 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1261 vertexupdatenum = 0;
1264 if (vertexupdatenum == 0)
1266 vertexupdatenum = 1;
1267 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
1268 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
1271 for (i = 0;i < nummarktris;i++)
1272 shadowmark[marktris[i]] = shadowmarkcount;
1274 if (r_shadow_compilingrtlight)
1276 // if we're compiling an rtlight, capture the mesh
1277 //tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1278 //Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zpass, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1279 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1280 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zfail, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1282 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
1284 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1285 R_Mesh_PrepareVertices_Vertex3f(outverts, shadowvertex3f, NULL);
1286 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1290 // decide which type of shadow to generate and set stencil mode
1291 R_Shadow_RenderMode_StencilShadowVolumes(R_Shadow_UseZPass(trismins, trismaxs));
1292 // generate the sides or a solid volume, depending on type
1293 if (r_shadow_rendermode >= R_SHADOW_RENDERMODE_ZPASS_STENCIL && r_shadow_rendermode <= R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE)
1294 tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1296 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1297 r_refdef.stats.lights_dynamicshadowtriangles += tris;
1298 r_refdef.stats.lights_shadowtriangles += tris;
1299 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
1301 // increment stencil if frontface is infront of depthbuffer
1302 GL_CullFace(r_refdef.view.cullface_front);
1303 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
1304 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1305 // decrement stencil if backface is infront of depthbuffer
1306 GL_CullFace(r_refdef.view.cullface_back);
1307 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
1309 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
1311 // decrement stencil if backface is behind depthbuffer
1312 GL_CullFace(r_refdef.view.cullface_front);
1313 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
1314 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1315 // increment stencil if frontface is behind depthbuffer
1316 GL_CullFace(r_refdef.view.cullface_back);
1317 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
1319 R_Mesh_PrepareVertices_Vertex3f(outverts, shadowvertex3f, NULL);
1320 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1324 int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias)
1326 // p1, p2, p3 are in the cubemap's local coordinate system
1327 // bias = border/(size - border)
1330 float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1331 dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2),
1332 dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3);
1333 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1335 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1336 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1337 | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1338 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1340 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1341 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1342 | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1344 dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1345 dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2),
1346 dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3);
1347 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1349 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1350 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1351 | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1352 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1354 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1355 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1356 | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1358 dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1359 dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2),
1360 dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3);
1361 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1363 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1364 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1365 | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1366 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1368 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1369 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1370 | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1375 int R_Shadow_CalcBBoxSideMask(const vec3_t mins, const vec3_t maxs, const matrix4x4_t *worldtolight, const matrix4x4_t *radiustolight, float bias)
1377 vec3_t center, radius, lightcenter, lightradius, pmin, pmax;
1378 float dp1, dn1, ap1, an1, dp2, dn2, ap2, an2;
1381 VectorSubtract(maxs, mins, radius);
1382 VectorScale(radius, 0.5f, radius);
1383 VectorAdd(mins, radius, center);
1384 Matrix4x4_Transform(worldtolight, center, lightcenter);
1385 Matrix4x4_Transform3x3(radiustolight, radius, lightradius);
1386 VectorSubtract(lightcenter, lightradius, pmin);
1387 VectorAdd(lightcenter, lightradius, pmax);
1389 dp1 = pmax[0] + pmax[1], dn1 = pmax[0] - pmin[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1390 dp2 = pmin[0] + pmin[1], dn2 = pmin[0] - pmax[1], ap2 = fabs(dp2), an2 = fabs(dn2);
1391 if(ap1 > bias*an1 && ap2 > bias*an2)
1393 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1394 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1395 if(an1 > bias*ap1 && an2 > bias*ap2)
1397 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1398 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1400 dp1 = pmax[1] + pmax[2], dn1 = pmax[1] - pmin[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1401 dp2 = pmin[1] + pmin[2], dn2 = pmin[1] - pmax[2], ap2 = fabs(dp2), an2 = fabs(dn2);
1402 if(ap1 > bias*an1 && ap2 > bias*an2)
1404 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1405 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1406 if(an1 > bias*ap1 && an2 > bias*ap2)
1408 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1409 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1411 dp1 = pmax[2] + pmax[0], dn1 = pmax[2] - pmin[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1412 dp2 = pmin[2] + pmin[0], dn2 = pmin[2] - pmax[0], ap2 = fabs(dp2), an2 = fabs(dn2);
1413 if(ap1 > bias*an1 && ap2 > bias*an2)
1415 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1416 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1417 if(an1 > bias*ap1 && an2 > bias*ap2)
1419 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1420 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1425 #define R_Shadow_CalcEntitySideMask(ent, worldtolight, radiustolight, bias) R_Shadow_CalcBBoxSideMask((ent)->mins, (ent)->maxs, worldtolight, radiustolight, bias)
1427 int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
1429 // p is in the cubemap's local coordinate system
1430 // bias = border/(size - border)
1431 float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn);
1432 float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn);
1433 float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn);
1435 if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
1436 if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
1437 if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
1438 if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
1439 if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
1440 if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
1444 int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
1448 int sides = 0x3F, masks[6] = { 3<<4, 3<<4, 3<<0, 3<<0, 3<<2, 3<<2 };
1449 float scale = (size - 2*border)/size, len;
1450 float bias = border / (float)(size - border), dp, dn, ap, an;
1451 // check if cone enclosing side would cross frustum plane
1452 scale = 2 / (scale*scale + 2);
1453 for (i = 0;i < 5;i++)
1455 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) > -0.03125)
1457 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[i].normal, n);
1458 len = scale*VectorLength2(n);
1459 if(n[0]*n[0] > len) sides &= n[0] < 0 ? ~(1<<0) : ~(2 << 0);
1460 if(n[1]*n[1] > len) sides &= n[1] < 0 ? ~(1<<2) : ~(2 << 2);
1461 if(n[2]*n[2] > len) sides &= n[2] < 0 ? ~(1<<4) : ~(2 << 4);
1463 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[4]) >= r_refdef.farclip - r_refdef.nearclip + 0.03125)
1465 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[4].normal, n);
1466 len = scale*VectorLength(n);
1467 if(n[0]*n[0] > len) sides &= n[0] >= 0 ? ~(1<<0) : ~(2 << 0);
1468 if(n[1]*n[1] > len) sides &= n[1] >= 0 ? ~(1<<2) : ~(2 << 2);
1469 if(n[2]*n[2] > len) sides &= n[2] >= 0 ? ~(1<<4) : ~(2 << 4);
1471 // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results
1472 // check if frustum corners/origin cross plane sides
1474 // infinite version, assumes frustum corners merely give direction and extend to infinite distance
1475 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.origin, p);
1476 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1477 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1478 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1479 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1480 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1481 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1482 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1483 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1484 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1485 for (i = 0;i < 4;i++)
1487 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.frustumcorner[i], n);
1488 VectorSubtract(n, p, n);
1489 dp = n[0] + n[1], dn = n[0] - n[1], ap = fabs(dp), an = fabs(dn);
1490 if(ap > 0) masks[0] |= dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2);
1491 if(an > 0) masks[1] |= dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2);
1492 dp = n[1] + n[2], dn = n[1] - n[2], ap = fabs(dp), an = fabs(dn);
1493 if(ap > 0) masks[2] |= dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4);
1494 if(an > 0) masks[3] |= dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4);
1495 dp = n[2] + n[0], dn = n[2] - n[0], ap = fabs(dp), an = fabs(dn);
1496 if(ap > 0) masks[4] |= dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0);
1497 if(an > 0) masks[5] |= dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0);
1500 // finite version, assumes corners are a finite distance from origin dependent on far plane
1501 for (i = 0;i < 5;i++)
1503 Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p);
1504 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1505 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1506 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1507 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1508 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1509 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1510 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1511 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1512 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1515 return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5];
1518 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)
1526 int mask, surfacemask = 0;
1527 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1529 bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
1530 tend = firsttriangle + numtris;
1531 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1533 // surface box entirely inside light box, no box cull
1534 if (projectdirection)
1536 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1538 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1539 TriangleNormal(v[0], v[1], v[2], normal);
1540 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1542 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1543 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1544 surfacemask |= mask;
1547 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;
1548 shadowsides[numshadowsides] = mask;
1549 shadowsideslist[numshadowsides++] = t;
1556 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1558 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1559 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]))
1561 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1562 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1563 surfacemask |= mask;
1566 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;
1567 shadowsides[numshadowsides] = mask;
1568 shadowsideslist[numshadowsides++] = t;
1576 // surface box not entirely inside light box, cull each triangle
1577 if (projectdirection)
1579 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1581 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1582 TriangleNormal(v[0], v[1], v[2], normal);
1583 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1584 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1586 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1587 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1588 surfacemask |= mask;
1591 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;
1592 shadowsides[numshadowsides] = mask;
1593 shadowsideslist[numshadowsides++] = t;
1600 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1602 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1603 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1604 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1606 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1607 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1608 surfacemask |= mask;
1611 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;
1612 shadowsides[numshadowsides] = mask;
1613 shadowsideslist[numshadowsides++] = t;
1622 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)
1624 int i, j, outtriangles = 0;
1625 int *outelement3i[6];
1626 if (!numverts || !numsidetris || !r_shadow_compilingrtlight)
1628 outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5];
1629 // make sure shadowelements is big enough for this mesh
1630 if (maxshadowtriangles < outtriangles)
1631 R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1);
1633 // compute the offset and size of the separate index lists for each cubemap side
1635 for (i = 0;i < 6;i++)
1637 outelement3i[i] = shadowelements + outtriangles * 3;
1638 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles;
1639 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i];
1640 outtriangles += sidetotals[i];
1643 // gather up the (sparse) triangles into separate index lists for each cubemap side
1644 for (i = 0;i < numsidetris;i++)
1646 const int *element = elements + sidetris[i] * 3;
1647 for (j = 0;j < 6;j++)
1649 if (sides[i] & (1 << j))
1651 outelement3i[j][0] = element[0];
1652 outelement3i[j][1] = element[1];
1653 outelement3i[j][2] = element[2];
1654 outelement3i[j] += 3;
1659 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, outtriangles, shadowelements);
1662 static void R_Shadow_MakeTextures_MakeCorona(void)
1666 unsigned char pixels[32][32][4];
1667 for (y = 0;y < 32;y++)
1669 dy = (y - 15.5f) * (1.0f / 16.0f);
1670 for (x = 0;x < 32;x++)
1672 dx = (x - 15.5f) * (1.0f / 16.0f);
1673 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1674 a = bound(0, a, 255);
1675 pixels[y][x][0] = a;
1676 pixels[y][x][1] = a;
1677 pixels[y][x][2] = a;
1678 pixels[y][x][3] = 255;
1681 r_shadow_lightcorona = R_SkinFrame_LoadInternalBGRA("lightcorona", TEXF_FORCELINEAR, &pixels[0][0][0], 32, 32);
1684 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1686 float dist = sqrt(x*x+y*y+z*z);
1687 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1688 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1689 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1692 static void R_Shadow_MakeTextures(void)
1695 float intensity, dist;
1697 R_Shadow_FreeShadowMaps();
1698 R_FreeTexturePool(&r_shadow_texturepool);
1699 r_shadow_texturepool = R_AllocTexturePool();
1700 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1701 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1702 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1703 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1704 for (x = 0;x <= ATTENTABLESIZE;x++)
1706 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1707 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1708 r_shadow_attentable[x] = bound(0, intensity, 1);
1710 // 1D gradient texture
1711 for (x = 0;x < ATTEN1DSIZE;x++)
1712 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1713 r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1714 // 2D circle texture
1715 for (y = 0;y < ATTEN2DSIZE;y++)
1716 for (x = 0;x < ATTEN2DSIZE;x++)
1717 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);
1718 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1719 // 3D sphere texture
1720 if (r_shadow_texture3d.integer && vid.support.ext_texture_3d)
1722 for (z = 0;z < ATTEN3DSIZE;z++)
1723 for (y = 0;y < ATTEN3DSIZE;y++)
1724 for (x = 0;x < ATTEN3DSIZE;x++)
1725 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));
1726 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);
1729 r_shadow_attenuation3dtexture = NULL;
1732 R_Shadow_MakeTextures_MakeCorona();
1734 // Editor light sprites
1735 r_editlights_sprcursor = R_SkinFrame_LoadInternal8bit("gfx/editlights/cursor", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1752 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1753 r_editlights_sprlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/light", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1770 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1771 r_editlights_sprnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/noshadow", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1788 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1789 r_editlights_sprcubemaplight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemaplight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1806 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1807 r_editlights_sprcubemapnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemapnoshadowlight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1824 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1825 r_editlights_sprselection = R_SkinFrame_LoadInternal8bit("gfx/editlights/selection", TEXF_ALPHA | TEXF_CLAMP, (unsigned char *)
1842 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1845 void R_Shadow_ValidateCvars(void)
1847 if (r_shadow_texture3d.integer && !vid.support.ext_texture_3d)
1848 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1849 if (gl_ext_separatestencil.integer && !vid.support.ati_separate_stencil)
1850 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
1851 if (gl_ext_stenciltwoside.integer && !vid.support.ext_stencil_two_side)
1852 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1855 void R_Shadow_RenderMode_Begin(void)
1861 R_Shadow_ValidateCvars();
1863 if (!r_shadow_attenuation2dtexture
1864 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1865 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1866 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1867 R_Shadow_MakeTextures();
1870 R_Mesh_ResetTextureState();
1871 GL_BlendFunc(GL_ONE, GL_ZERO);
1872 GL_DepthRange(0, 1);
1873 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1875 GL_DepthMask(false);
1876 GL_Color(0, 0, 0, 1);
1877 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1879 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1881 if (gl_ext_separatestencil.integer && vid.support.ati_separate_stencil)
1883 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
1884 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
1886 else if (gl_ext_stenciltwoside.integer && vid.support.ext_stencil_two_side)
1888 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
1889 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
1893 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
1894 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
1897 switch(vid.renderpath)
1899 case RENDERPATH_GL20:
1900 case RENDERPATH_CGGL:
1901 case RENDERPATH_D3D9:
1902 case RENDERPATH_D3D10:
1903 case RENDERPATH_D3D11:
1904 case RENDERPATH_SOFT:
1905 case RENDERPATH_GLES2:
1906 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1908 case RENDERPATH_GL13:
1909 case RENDERPATH_GL11:
1910 if (r_textureunits.integer >= 2 && vid.texunits >= 2 && r_shadow_texture3d.integer && r_shadow_attenuation3dtexture)
1911 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN;
1912 else if (r_textureunits.integer >= 3 && vid.texunits >= 3)
1913 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN;
1914 else if (r_textureunits.integer >= 2 && vid.texunits >= 2)
1915 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN;
1917 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1923 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
1924 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
1925 r_shadow_drawbuffer = drawbuffer;
1926 r_shadow_readbuffer = readbuffer;
1928 r_shadow_cullface_front = r_refdef.view.cullface_front;
1929 r_shadow_cullface_back = r_refdef.view.cullface_back;
1932 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
1934 rsurface.rtlight = rtlight;
1937 void R_Shadow_RenderMode_Reset(void)
1939 R_Mesh_ResetRenderTargets();
1940 R_SetViewport(&r_refdef.view.viewport);
1941 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
1942 R_Mesh_ResetTextureState();
1943 GL_DepthRange(0, 1);
1945 GL_DepthMask(false);
1946 GL_DepthFunc(GL_LEQUAL);
1947 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1948 r_refdef.view.cullface_front = r_shadow_cullface_front;
1949 r_refdef.view.cullface_back = r_shadow_cullface_back;
1950 GL_CullFace(r_refdef.view.cullface_back);
1951 GL_Color(1, 1, 1, 1);
1952 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
1953 GL_BlendFunc(GL_ONE, GL_ZERO);
1954 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
1955 r_shadow_usingshadowmap2d = false;
1956 r_shadow_usingshadowmaportho = false;
1957 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
1960 void R_Shadow_ClearStencil(void)
1962 GL_Clear(GL_STENCIL_BUFFER_BIT, NULL, 1.0f, 128);
1963 r_refdef.stats.lights_clears++;
1966 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
1968 r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
1969 if (r_shadow_rendermode == mode)
1971 R_Shadow_RenderMode_Reset();
1972 GL_DepthFunc(GL_LESS);
1973 GL_ColorMask(0, 0, 0, 0);
1974 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1975 GL_CullFace(GL_NONE);
1976 R_SetupShader_DepthOrShadow();
1977 r_shadow_rendermode = mode;
1982 case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
1983 case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
1984 R_SetStencilSeparate(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, GL_ALWAYS, 128, 255);
1986 case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
1987 case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
1988 R_SetStencilSeparate(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, GL_ALWAYS, 128, 255);
1993 static void R_Shadow_MakeVSDCT(void)
1995 // maps to a 2x3 texture rectangle with normalized coordinates
2000 // stores abs(dir.xy), offset.xy/2.5
2001 unsigned char data[4*6] =
2003 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
2004 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
2005 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
2006 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
2007 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
2008 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
2010 r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
2013 static void R_Shadow_MakeShadowMap(int side, int size)
2015 switch (r_shadow_shadowmode)
2017 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2018 if (r_shadow_shadowmap2dtexture) return;
2019 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);
2020 r_shadow_shadowmap2dcolortexture = NULL;
2021 switch(vid.renderpath)
2024 case RENDERPATH_D3D9:
2025 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);
2026 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
2030 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2dtexture, NULL, NULL, NULL, NULL);
2038 // render depth into the fbo, do not render color at all
2039 // validate the fbo now
2043 qglDrawBuffer(GL_NONE);CHECKGLERROR
2044 qglReadBuffer(GL_NONE);CHECKGLERROR
2045 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2046 if (status != GL_FRAMEBUFFER_COMPLETE_EXT && (r_shadow_shadowmapping.integer || r_shadow_deferred.integer))
2048 Con_Printf("R_Shadow_MakeShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2049 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2050 Cvar_SetValueQuick(&r_shadow_deferred, 0);
2055 void R_Shadow_RenderMode_ShadowMap(int side, int clear, int size)
2057 float nearclip, farclip, bias;
2058 r_viewport_t viewport;
2061 float clearcolor[4];
2062 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
2064 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
2065 r_shadow_shadowmap_parameters[1] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
2066 r_shadow_shadowmap_parameters[3] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
2067 r_shadow_shadowmapside = side;
2068 r_shadow_shadowmapsize = size;
2070 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2071 r_shadow_shadowmap_parameters[2] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2072 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
2073 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D) goto init_done;
2075 // complex unrolled cube approach (more flexible)
2076 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2077 R_Shadow_MakeVSDCT();
2078 if (!r_shadow_shadowmap2dtexture)
2079 R_Shadow_MakeShadowMap(side, r_shadow_shadowmapmaxsize);
2080 if (r_shadow_shadowmap2dtexture) fbo = r_shadow_fbo2d;
2081 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
2082 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
2083 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
2085 R_Mesh_ResetTextureState();
2086 R_Mesh_ResetRenderTargets();
2087 R_Shadow_RenderMode_Reset();
2090 R_Mesh_SetRenderTargets(fbo, r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
2091 R_SetupShader_DepthOrShadow();
2094 R_SetupShader_ShowDepth();
2095 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
2100 R_SetViewport(&viewport);
2101 flipped = (side & 1) ^ (side >> 2);
2102 r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
2103 r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
2104 switch(vid.renderpath)
2106 case RENDERPATH_GL11:
2107 case RENDERPATH_GL13:
2108 case RENDERPATH_GL20:
2109 case RENDERPATH_CGGL:
2110 case RENDERPATH_SOFT:
2111 case RENDERPATH_GLES2:
2112 GL_CullFace(r_refdef.view.cullface_back);
2113 // OpenGL lets us scissor larger than the viewport, so go ahead and clear all views at once
2114 if ((clear & ((2 << side) - 1)) == (1 << side)) // only clear if the side is the first in the mask
2116 // get tightest scissor rectangle that encloses all viewports in the clear mask
2117 int x1 = clear & 0x15 ? 0 : size;
2118 int x2 = clear & 0x2A ? 2 * size : size;
2119 int y1 = clear & 0x03 ? 0 : (clear & 0xC ? size : 2 * size);
2120 int y2 = clear & 0x30 ? 3 * size : (clear & 0xC ? 2 * size : size);
2121 GL_Scissor(x1, y1, x2 - x1, y2 - y1);
2122 GL_Clear(GL_DEPTH_BUFFER_BIT, NULL, 1.0f, 0);
2124 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2126 case RENDERPATH_D3D9:
2127 case RENDERPATH_D3D10:
2128 case RENDERPATH_D3D11:
2129 Vector4Set(clearcolor, 1,1,1,1);
2130 // completely different meaning than in OpenGL path
2131 r_shadow_shadowmap_parameters[1] = 0;
2132 r_shadow_shadowmap_parameters[3] = -bias;
2133 // we invert the cull mode because we flip the projection matrix
2134 // NOTE: this actually does nothing because the DrawShadowMap code sets it to doublesided...
2135 GL_CullFace(r_refdef.view.cullface_front);
2136 // D3D considers it an error to use a scissor larger than the viewport... clear just this view
2137 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2138 if (r_shadow_shadowmapsampler)
2140 GL_ColorMask(0,0,0,0);
2142 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
2146 GL_ColorMask(1,1,1,1);
2148 GL_Clear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
2154 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
2156 R_Mesh_ResetTextureState();
2157 R_Mesh_ResetRenderTargets();
2160 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2161 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2162 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2163 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2165 R_Shadow_RenderMode_Reset();
2166 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2168 GL_DepthFunc(GL_EQUAL);
2169 // do global setup needed for the chosen lighting mode
2170 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2171 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2172 r_shadow_usingshadowmap2d = shadowmapping;
2173 r_shadow_rendermode = r_shadow_lightingrendermode;
2174 // only draw light where this geometry was already rendered AND the
2175 // stencil is 128 (values other than this mean shadow)
2177 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2179 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
2182 static const unsigned short bboxelements[36] =
2192 static const float bboxpoints[8][3] =
2204 void R_Shadow_RenderMode_DrawDeferredLight(qboolean stenciltest, qboolean shadowmapping)
2207 float vertex3f[8*3];
2208 const matrix4x4_t *matrix = &rsurface.rtlight->matrix_lighttoworld;
2209 // do global setup needed for the chosen lighting mode
2210 R_Shadow_RenderMode_Reset();
2211 r_shadow_rendermode = r_shadow_lightingrendermode;
2212 R_EntityMatrix(&identitymatrix);
2213 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2214 // only draw light where this geometry was already rendered AND the
2215 // stencil is 128 (values other than this mean shadow)
2216 R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2217 R_Mesh_SetRenderTargets(r_shadow_prepasslightingfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
2219 r_shadow_usingshadowmap2d = shadowmapping;
2221 // render the lighting
2222 R_SetupShader_DeferredLight(rsurface.rtlight);
2223 for (i = 0;i < 8;i++)
2224 Matrix4x4_Transform(matrix, bboxpoints[i], vertex3f + i*3);
2225 GL_ColorMask(1,1,1,1);
2226 GL_DepthMask(false);
2227 GL_DepthRange(0, 1);
2228 GL_PolygonOffset(0, 0);
2230 GL_DepthFunc(GL_GREATER);
2231 GL_CullFace(r_refdef.view.cullface_back);
2232 R_Mesh_PrepareVertices_Vertex3f(8, vertex3f, NULL);
2233 R_Mesh_Draw(0, 8, 0, 12, NULL, NULL, 0, bboxelements, NULL, 0);
2236 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
2238 R_Shadow_RenderMode_Reset();
2239 GL_BlendFunc(GL_ONE, GL_ONE);
2240 GL_DepthRange(0, 1);
2241 GL_DepthTest(r_showshadowvolumes.integer < 2);
2242 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
2243 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2244 GL_CullFace(GL_NONE);
2245 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
2248 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
2250 R_Shadow_RenderMode_Reset();
2251 GL_BlendFunc(GL_ONE, GL_ONE);
2252 GL_DepthRange(0, 1);
2253 GL_DepthTest(r_showlighting.integer < 2);
2254 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2256 GL_DepthFunc(GL_EQUAL);
2257 R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2258 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2261 void R_Shadow_RenderMode_End(void)
2263 R_Shadow_RenderMode_Reset();
2264 R_Shadow_RenderMode_ActiveLight(NULL);
2266 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2267 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2270 int bboxedges[12][2] =
2289 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2291 if (!r_shadow_scissor.integer)
2293 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2294 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2295 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2296 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2299 if(R_ScissorForBBox(mins, maxs, r_shadow_lightscissor))
2300 return true; // invisible
2301 if(r_shadow_lightscissor[0] != r_refdef.view.viewport.x
2302 || r_shadow_lightscissor[1] != r_refdef.view.viewport.y
2303 || r_shadow_lightscissor[2] != r_refdef.view.viewport.width
2304 || r_shadow_lightscissor[3] != r_refdef.view.viewport.height)
2305 r_refdef.stats.lights_scissored++;
2309 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, const float *diffusecolor, const float *ambientcolor)
2312 const float *vertex3f;
2313 const float *normal3f;
2315 float dist, dot, distintensity, shadeintensity, v[3], n[3];
2316 switch (r_shadow_rendermode)
2318 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2319 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2320 if (VectorLength2(diffusecolor) > 0)
2322 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, normal3f = rsurface.batchnormal3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, normal3f += 3, color4f += 4)
2324 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2325 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2326 if ((dot = DotProduct(n, v)) < 0)
2328 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2329 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
2332 VectorCopy(ambientcolor, color4f);
2333 if (r_refdef.fogenabled)
2336 f = RSurf_FogVertex(vertex3f);
2337 VectorScale(color4f, f, color4f);
2344 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
2346 VectorCopy(ambientcolor, color4f);
2347 if (r_refdef.fogenabled)
2350 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2351 f = RSurf_FogVertex(vertex3f);
2352 VectorScale(color4f + 4*i, f, color4f);
2358 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2359 if (VectorLength2(diffusecolor) > 0)
2361 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, normal3f = rsurface.batchnormal3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, normal3f += 3, color4f += 4)
2363 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2364 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2366 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2367 if ((dot = DotProduct(n, v)) < 0)
2369 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2370 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2371 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2372 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2376 color4f[0] = ambientcolor[0] * distintensity;
2377 color4f[1] = ambientcolor[1] * distintensity;
2378 color4f[2] = ambientcolor[2] * distintensity;
2380 if (r_refdef.fogenabled)
2383 f = RSurf_FogVertex(vertex3f);
2384 VectorScale(color4f, f, color4f);
2388 VectorClear(color4f);
2394 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
2396 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2397 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2399 color4f[0] = ambientcolor[0] * distintensity;
2400 color4f[1] = ambientcolor[1] * distintensity;
2401 color4f[2] = ambientcolor[2] * distintensity;
2402 if (r_refdef.fogenabled)
2405 f = RSurf_FogVertex(vertex3f);
2406 VectorScale(color4f, f, color4f);
2410 VectorClear(color4f);
2415 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2416 if (VectorLength2(diffusecolor) > 0)
2418 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, normal3f = rsurface.batchnormal3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, normal3f += 3, color4f += 4)
2420 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2421 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2423 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2424 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2425 if ((dot = DotProduct(n, v)) < 0)
2427 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2428 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2429 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2430 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2434 color4f[0] = ambientcolor[0] * distintensity;
2435 color4f[1] = ambientcolor[1] * distintensity;
2436 color4f[2] = ambientcolor[2] * distintensity;
2438 if (r_refdef.fogenabled)
2441 f = RSurf_FogVertex(vertex3f);
2442 VectorScale(color4f, f, color4f);
2446 VectorClear(color4f);
2452 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
2454 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2455 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2457 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2458 color4f[0] = ambientcolor[0] * distintensity;
2459 color4f[1] = ambientcolor[1] * distintensity;
2460 color4f[2] = ambientcolor[2] * distintensity;
2461 if (r_refdef.fogenabled)
2464 f = RSurf_FogVertex(vertex3f);
2465 VectorScale(color4f, f, color4f);
2469 VectorClear(color4f);
2479 static void R_Shadow_RenderLighting_VisibleLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
2481 // used to display how many times a surface is lit for level design purposes
2482 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
2483 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
2487 static void R_Shadow_RenderLighting_Light_GLSL(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale, float specularscale)
2489 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2490 R_SetupShader_Surface(lightcolor, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT, texturenumsurfaces, texturesurfacelist, NULL);
2491 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2492 GL_DepthFunc(GL_EQUAL);
2494 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2495 GL_DepthFunc(GL_LEQUAL);
2498 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
2505 int newnumtriangles;
2509 int maxtriangles = 4096;
2510 static int newelements[4096*3];
2511 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, diffusecolor2, ambientcolor2);
2512 for (renders = 0;renders < 4;renders++)
2517 newnumtriangles = 0;
2519 // due to low fillrate on the cards this vertex lighting path is
2520 // designed for, we manually cull all triangles that do not
2521 // contain a lit vertex
2522 // this builds batches of triangles from multiple surfaces and
2523 // renders them at once
2524 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
2526 if (VectorLength2(rsurface.passcolor4f + e[0] * 4) + VectorLength2(rsurface.passcolor4f + e[1] * 4) + VectorLength2(rsurface.passcolor4f + e[2] * 4) >= 0.01)
2528 if (newnumtriangles)
2530 newfirstvertex = min(newfirstvertex, e[0]);
2531 newlastvertex = max(newlastvertex, e[0]);
2535 newfirstvertex = e[0];
2536 newlastvertex = e[0];
2538 newfirstvertex = min(newfirstvertex, e[1]);
2539 newlastvertex = max(newlastvertex, e[1]);
2540 newfirstvertex = min(newfirstvertex, e[2]);
2541 newlastvertex = max(newlastvertex, e[2]);
2547 if (newnumtriangles >= maxtriangles)
2549 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
2550 newnumtriangles = 0;
2556 if (newnumtriangles >= 1)
2558 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
2561 // if we couldn't find any lit triangles, exit early
2564 // now reduce the intensity for the next overbright pass
2565 // we have to clamp to 0 here incase the drivers have improper
2566 // handling of negative colors
2567 // (some old drivers even have improper handling of >1 color)
2569 for (i = 0, c = rsurface.passcolor4f + 4 * firstvertex;i < numvertices;i++, c += 4)
2571 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
2573 c[0] = max(0, c[0] - 1);
2574 c[1] = max(0, c[1] - 1);
2575 c[2] = max(0, c[2] - 1);
2587 static void R_Shadow_RenderLighting_Light_Vertex(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale)
2589 // OpenGL 1.1 path (anything)
2590 float ambientcolorbase[3], diffusecolorbase[3];
2591 float ambientcolorpants[3], diffusecolorpants[3];
2592 float ambientcolorshirt[3], diffusecolorshirt[3];
2593 const float *surfacecolor = rsurface.texture->dlightcolor;
2594 const float *surfacepants = rsurface.colormap_pantscolor;
2595 const float *surfaceshirt = rsurface.colormap_shirtcolor;
2596 rtexture_t *basetexture = rsurface.texture->basetexture;
2597 rtexture_t *pantstexture = rsurface.texture->pantstexture;
2598 rtexture_t *shirttexture = rsurface.texture->shirttexture;
2599 qboolean dopants = pantstexture && VectorLength2(surfacepants) >= (1.0f / 1048576.0f);
2600 qboolean doshirt = shirttexture && VectorLength2(surfaceshirt) >= (1.0f / 1048576.0f);
2601 ambientscale *= 2 * r_refdef.view.colorscale;
2602 diffusescale *= 2 * r_refdef.view.colorscale;
2603 ambientcolorbase[0] = lightcolor[0] * ambientscale * surfacecolor[0];ambientcolorbase[1] = lightcolor[1] * ambientscale * surfacecolor[1];ambientcolorbase[2] = lightcolor[2] * ambientscale * surfacecolor[2];
2604 diffusecolorbase[0] = lightcolor[0] * diffusescale * surfacecolor[0];diffusecolorbase[1] = lightcolor[1] * diffusescale * surfacecolor[1];diffusecolorbase[2] = lightcolor[2] * diffusescale * surfacecolor[2];
2605 ambientcolorpants[0] = ambientcolorbase[0] * surfacepants[0];ambientcolorpants[1] = ambientcolorbase[1] * surfacepants[1];ambientcolorpants[2] = ambientcolorbase[2] * surfacepants[2];
2606 diffusecolorpants[0] = diffusecolorbase[0] * surfacepants[0];diffusecolorpants[1] = diffusecolorbase[1] * surfacepants[1];diffusecolorpants[2] = diffusecolorbase[2] * surfacepants[2];
2607 ambientcolorshirt[0] = ambientcolorbase[0] * surfaceshirt[0];ambientcolorshirt[1] = ambientcolorbase[1] * surfaceshirt[1];ambientcolorshirt[2] = ambientcolorbase[2] * surfaceshirt[2];
2608 diffusecolorshirt[0] = diffusecolorbase[0] * surfaceshirt[0];diffusecolorshirt[1] = diffusecolorbase[1] * surfaceshirt[1];diffusecolorshirt[2] = diffusecolorbase[2] * surfaceshirt[2];
2609 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | (diffusescale > 0 ? BATCHNEED_ARRAY_NORMAL : 0) | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
2610 rsurface.passcolor4f = (float *)R_FrameData_Alloc((rsurface.batchfirstvertex + rsurface.batchnumvertices) * sizeof(float[4]));
2611 R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
2612 R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.passcolor4f, 0, 0);
2613 R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
2614 R_Mesh_TexBind(0, basetexture);
2615 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
2616 R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
2617 switch(r_shadow_rendermode)
2619 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2620 R_Mesh_TexBind(1, r_shadow_attenuation3dtexture);
2621 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
2622 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
2623 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
2625 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2626 R_Mesh_TexBind(2, r_shadow_attenuation2dtexture);
2627 R_Mesh_TexMatrix(2, &rsurface.entitytoattenuationz);
2628 R_Mesh_TexCombine(2, GL_MODULATE, GL_MODULATE, 1, 1);
2629 R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
2631 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2632 R_Mesh_TexBind(1, r_shadow_attenuation2dtexture);
2633 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
2634 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
2635 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
2637 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2642 //R_Mesh_TexBind(0, basetexture);
2643 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorbase, ambientcolorbase);
2646 R_Mesh_TexBind(0, pantstexture);
2647 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorpants, ambientcolorpants);
2651 R_Mesh_TexBind(0, shirttexture);
2652 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorshirt, ambientcolorshirt);
2656 extern cvar_t gl_lightmaps;
2657 void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
2659 float ambientscale, diffusescale, specularscale;
2661 float lightcolor[3];
2662 VectorCopy(rsurface.rtlight->currentcolor, lightcolor);
2663 ambientscale = rsurface.rtlight->ambientscale;
2664 diffusescale = rsurface.rtlight->diffusescale;
2665 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
2666 if (!r_shadow_usenormalmap.integer)
2668 ambientscale += 1.0f * diffusescale;
2672 if ((ambientscale + diffusescale) * VectorLength2(lightcolor) + specularscale * VectorLength2(lightcolor) < (1.0f / 1048576.0f))
2674 negated = (lightcolor[0] + lightcolor[1] + lightcolor[2] < 0) && vid.support.ext_blend_subtract;
2677 VectorNegate(lightcolor, lightcolor);
2678 switch(vid.renderpath)
2680 case RENDERPATH_GL11:
2681 case RENDERPATH_GL13:
2682 case RENDERPATH_GL20:
2683 case RENDERPATH_CGGL:
2684 case RENDERPATH_GLES2:
2685 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
2687 case RENDERPATH_D3D9:
2689 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_SUBTRACT);
2692 case RENDERPATH_D3D10:
2693 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2695 case RENDERPATH_D3D11:
2696 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2698 case RENDERPATH_SOFT:
2699 DPSOFTRAST_BlendSubtract(true);
2703 RSurf_SetupDepthAndCulling();
2704 switch (r_shadow_rendermode)
2706 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2707 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2708 R_Shadow_RenderLighting_VisibleLighting(texturenumsurfaces, texturesurfacelist);
2710 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2711 R_Shadow_RenderLighting_Light_GLSL(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale, specularscale);
2713 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2714 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2715 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2716 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2717 R_Shadow_RenderLighting_Light_Vertex(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale);
2720 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2725 switch(vid.renderpath)
2727 case RENDERPATH_GL11:
2728 case RENDERPATH_GL13:
2729 case RENDERPATH_GL20:
2730 case RENDERPATH_CGGL:
2731 case RENDERPATH_GLES2:
2732 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
2734 case RENDERPATH_D3D9:
2736 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_ADD);
2739 case RENDERPATH_D3D10:
2740 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2742 case RENDERPATH_D3D11:
2743 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2745 case RENDERPATH_SOFT:
2746 DPSOFTRAST_BlendSubtract(false);
2752 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)
2754 matrix4x4_t tempmatrix = *matrix;
2755 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
2757 // if this light has been compiled before, free the associated data
2758 R_RTLight_Uncompile(rtlight);
2760 // clear it completely to avoid any lingering data
2761 memset(rtlight, 0, sizeof(*rtlight));
2763 // copy the properties
2764 rtlight->matrix_lighttoworld = tempmatrix;
2765 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
2766 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
2767 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
2768 VectorCopy(color, rtlight->color);
2769 rtlight->cubemapname[0] = 0;
2770 if (cubemapname && cubemapname[0])
2771 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
2772 rtlight->shadow = shadow;
2773 rtlight->corona = corona;
2774 rtlight->style = style;
2775 rtlight->isstatic = isstatic;
2776 rtlight->coronasizescale = coronasizescale;
2777 rtlight->ambientscale = ambientscale;
2778 rtlight->diffusescale = diffusescale;
2779 rtlight->specularscale = specularscale;
2780 rtlight->flags = flags;
2782 // compute derived data
2783 //rtlight->cullradius = rtlight->radius;
2784 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2785 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2786 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2787 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2788 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2789 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2790 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2793 // compiles rtlight geometry
2794 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2795 void R_RTLight_Compile(rtlight_t *rtlight)
2798 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
2799 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
2800 entity_render_t *ent = r_refdef.scene.worldentity;
2801 dp_model_t *model = r_refdef.scene.worldmodel;
2802 unsigned char *data;
2805 // compile the light
2806 rtlight->compiled = true;
2807 rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
2808 rtlight->static_numleafs = 0;
2809 rtlight->static_numleafpvsbytes = 0;
2810 rtlight->static_leaflist = NULL;
2811 rtlight->static_leafpvs = NULL;
2812 rtlight->static_numsurfaces = 0;
2813 rtlight->static_surfacelist = NULL;
2814 rtlight->static_shadowmap_receivers = 0x3F;
2815 rtlight->static_shadowmap_casters = 0x3F;
2816 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2817 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2818 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2819 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2820 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2821 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2823 if (model && model->GetLightInfo)
2825 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
2826 r_shadow_compilingrtlight = rtlight;
2827 R_FrameData_SetMark();
2828 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);
2829 R_FrameData_ReturnToMark();
2830 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2831 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
2832 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
2833 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
2834 rtlight->static_numsurfaces = numsurfaces;
2835 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
2836 rtlight->static_numleafs = numleafs;
2837 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
2838 rtlight->static_numleafpvsbytes = numleafpvsbytes;
2839 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
2840 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
2841 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
2842 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
2843 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
2844 if (rtlight->static_numsurfaces)
2845 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
2846 if (rtlight->static_numleafs)
2847 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
2848 if (rtlight->static_numleafpvsbytes)
2849 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
2850 if (rtlight->static_numshadowtrispvsbytes)
2851 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
2852 if (rtlight->static_numlighttrispvsbytes)
2853 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
2854 R_FrameData_SetMark();
2855 switch (rtlight->shadowmode)
2857 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2858 if (model->CompileShadowMap && rtlight->shadow)
2859 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2862 if (model->CompileShadowVolume && rtlight->shadow)
2863 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2866 R_FrameData_ReturnToMark();
2867 // now we're done compiling the rtlight
2868 r_shadow_compilingrtlight = NULL;
2872 // use smallest available cullradius - box radius or light radius
2873 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2874 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2876 shadowzpasstris = 0;
2877 if (rtlight->static_meshchain_shadow_zpass)
2878 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
2879 shadowzpasstris += mesh->numtriangles;
2881 shadowzfailtris = 0;
2882 if (rtlight->static_meshchain_shadow_zfail)
2883 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
2884 shadowzfailtris += mesh->numtriangles;
2887 if (rtlight->static_numlighttrispvsbytes)
2888 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
2889 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
2893 if (rtlight->static_numlighttrispvsbytes)
2894 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
2895 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
2898 if (developer_extra.integer)
2899 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);
2902 void R_RTLight_Uncompile(rtlight_t *rtlight)
2904 if (rtlight->compiled)
2906 if (rtlight->static_meshchain_shadow_zpass)
2907 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
2908 rtlight->static_meshchain_shadow_zpass = NULL;
2909 if (rtlight->static_meshchain_shadow_zfail)
2910 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
2911 rtlight->static_meshchain_shadow_zfail = NULL;
2912 if (rtlight->static_meshchain_shadow_shadowmap)
2913 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
2914 rtlight->static_meshchain_shadow_shadowmap = NULL;
2915 // these allocations are grouped
2916 if (rtlight->static_surfacelist)
2917 Mem_Free(rtlight->static_surfacelist);
2918 rtlight->static_numleafs = 0;
2919 rtlight->static_numleafpvsbytes = 0;
2920 rtlight->static_leaflist = NULL;
2921 rtlight->static_leafpvs = NULL;
2922 rtlight->static_numsurfaces = 0;
2923 rtlight->static_surfacelist = NULL;
2924 rtlight->static_numshadowtrispvsbytes = 0;
2925 rtlight->static_shadowtrispvs = NULL;
2926 rtlight->static_numlighttrispvsbytes = 0;
2927 rtlight->static_lighttrispvs = NULL;
2928 rtlight->compiled = false;
2932 void R_Shadow_UncompileWorldLights(void)
2936 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
2937 for (lightindex = 0;lightindex < range;lightindex++)
2939 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2942 R_RTLight_Uncompile(&light->rtlight);
2946 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
2950 // reset the count of frustum planes
2951 // see rtlight->cached_frustumplanes definition for how much this array
2953 rtlight->cached_numfrustumplanes = 0;
2955 // haven't implemented a culling path for ortho rendering
2956 if (!r_refdef.view.useperspective)
2958 // check if the light is on screen and copy the 4 planes if it is
2959 for (i = 0;i < 4;i++)
2960 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
2963 for (i = 0;i < 4;i++)
2964 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
2969 // generate a deformed frustum that includes the light origin, this is
2970 // used to cull shadow casting surfaces that can not possibly cast a
2971 // shadow onto the visible light-receiving surfaces, which can be a
2974 // if the light origin is onscreen the result will be 4 planes exactly
2975 // if the light origin is offscreen on only one axis the result will
2976 // be exactly 5 planes (split-side case)
2977 // if the light origin is offscreen on two axes the result will be
2978 // exactly 4 planes (stretched corner case)
2979 for (i = 0;i < 4;i++)
2981 // quickly reject standard frustum planes that put the light
2982 // origin outside the frustum
2983 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
2986 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
2988 // if all the standard frustum planes were accepted, the light is onscreen
2989 // otherwise we need to generate some more planes below...
2990 if (rtlight->cached_numfrustumplanes < 4)
2992 // at least one of the stock frustum planes failed, so we need to
2993 // create one or two custom planes to enclose the light origin
2994 for (i = 0;i < 4;i++)
2996 // create a plane using the view origin and light origin, and a
2997 // single point from the frustum corner set
2998 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
2999 VectorNormalize(plane.normal);
3000 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3001 // see if this plane is backwards and flip it if so
3002 for (j = 0;j < 4;j++)
3003 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3007 VectorNegate(plane.normal, plane.normal);
3009 // flipped plane, test again to see if it is now valid
3010 for (j = 0;j < 4;j++)
3011 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3013 // if the plane is still not valid, then it is dividing the
3014 // frustum and has to be rejected
3018 // we have created a valid plane, compute extra info
3019 PlaneClassify(&plane);
3021 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3023 // if we've found 5 frustum planes then we have constructed a
3024 // proper split-side case and do not need to keep searching for
3025 // planes to enclose the light origin
3026 if (rtlight->cached_numfrustumplanes == 5)
3034 for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
3036 plane = rtlight->cached_frustumplanes[i];
3037 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));
3042 // now add the light-space box planes if the light box is rotated, as any
3043 // caster outside the oriented light box is irrelevant (even if it passed
3044 // the worldspace light box, which is axial)
3045 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3047 for (i = 0;i < 6;i++)
3051 v[i >> 1] = (i & 1) ? -1 : 1;
3052 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3053 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3054 plane.dist = VectorNormalizeLength(plane.normal);
3055 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3056 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3062 // add the world-space reduced box planes
3063 for (i = 0;i < 6;i++)
3065 VectorClear(plane.normal);
3066 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3067 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
3068 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3077 // reduce all plane distances to tightly fit the rtlight cull box, which
3079 VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3080 VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3081 VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3082 VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3083 VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3084 VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3085 VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3086 VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3087 oldnum = rtlight->cached_numfrustumplanes;
3088 rtlight->cached_numfrustumplanes = 0;
3089 for (j = 0;j < oldnum;j++)
3091 // find the nearest point on the box to this plane
3092 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
3093 for (i = 1;i < 8;i++)
3095 dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
3096 if (bestdist > dist)
3099 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);
3100 // if the nearest point is near or behind the plane, we want this
3101 // plane, otherwise the plane is useless as it won't cull anything
3102 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
3104 PlaneClassify(&rtlight->cached_frustumplanes[j]);
3105 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
3112 void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
3116 RSurf_ActiveWorldEntity();
3118 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3121 GL_CullFace(GL_NONE);
3122 mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3123 for (;mesh;mesh = mesh->next)
3125 if (!mesh->sidetotals[r_shadow_shadowmapside])
3127 r_refdef.stats.lights_shadowtriangles += mesh->sidetotals[r_shadow_shadowmapside];
3128 if (mesh->vertex3fbuffer)
3129 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vertex3fbuffer);
3131 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer);
3132 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);
3136 else if (r_refdef.scene.worldentity->model)
3137 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);
3139 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3142 void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3144 qboolean zpass = false;
3147 int surfacelistindex;
3148 msurface_t *surface;
3150 // if triangle neighbors are disabled, shadowvolumes are disabled
3151 if (r_refdef.scene.worldmodel->brush.shadowmesh ? !r_refdef.scene.worldmodel->brush.shadowmesh->neighbor3i : !r_refdef.scene.worldmodel->surfmesh.data_neighbor3i)
3154 RSurf_ActiveWorldEntity();
3156 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3159 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
3161 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
3162 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
3164 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
3165 for (;mesh;mesh = mesh->next)
3167 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
3168 if (mesh->vertex3fbuffer)
3169 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vertex3fbuffer);
3171 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer);
3172 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
3174 // increment stencil if frontface is infront of depthbuffer
3175 GL_CullFace(r_refdef.view.cullface_back);
3176 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
3177 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);
3178 // decrement stencil if backface is infront of depthbuffer
3179 GL_CullFace(r_refdef.view.cullface_front);
3180 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
3182 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
3184 // decrement stencil if backface is behind depthbuffer
3185 GL_CullFace(r_refdef.view.cullface_front);
3186 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
3187 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);
3188 // increment stencil if frontface is behind depthbuffer
3189 GL_CullFace(r_refdef.view.cullface_back);
3190 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
3192 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);
3196 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh)
3198 // use the shadow trispvs calculated earlier by GetLightInfo to cull world triangles on this dynamic light
3199 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
3200 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
3202 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
3203 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
3204 if (CHECKPVSBIT(trispvs, t))
3205 shadowmarklist[numshadowmark++] = t;
3207 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);
3209 else if (numsurfaces)
3211 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);
3214 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3217 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3219 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3220 vec_t relativeshadowradius;
3221 RSurf_ActiveModelEntity(ent, false, false, false);
3222 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3223 // we need to re-init the shader for each entity because the matrix changed
3224 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3225 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3226 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3227 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3228 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3229 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3230 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3231 switch (r_shadow_rendermode)
3233 case R_SHADOW_RENDERMODE_SHADOWMAP2D:
3234 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
3237 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3240 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3243 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3245 // set up properties for rendering light onto this entity
3246 RSurf_ActiveModelEntity(ent, true, true, false);
3247 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3248 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3249 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3250 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3253 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
3255 if (!r_refdef.scene.worldmodel->DrawLight)
3258 // set up properties for rendering light onto this entity
3259 RSurf_ActiveWorldEntity();
3260 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3261 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3262 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3263 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3265 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
3267 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3270 void R_Shadow_DrawEntityLight(entity_render_t *ent)
3272 dp_model_t *model = ent->model;
3273 if (!model->DrawLight)
3276 R_Shadow_SetupEntityLight(ent);
3278 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3280 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3283 void R_Shadow_PrepareLight(rtlight_t *rtlight)
3287 int numleafs, numsurfaces;
3288 int *leaflist, *surfacelist;
3289 unsigned char *leafpvs;
3290 unsigned char *shadowtrispvs;
3291 unsigned char *lighttrispvs;
3292 //unsigned char *surfacesides;
3293 int numlightentities;
3294 int numlightentities_noselfshadow;
3295 int numshadowentities;
3296 int numshadowentities_noselfshadow;
3297 static entity_render_t *lightentities[MAX_EDICTS];
3298 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3299 static entity_render_t *shadowentities[MAX_EDICTS];
3300 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3303 rtlight->draw = false;
3305 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3306 // skip lights that are basically invisible (color 0 0 0)
3307 nolight = VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f);
3309 // loading is done before visibility checks because loading should happen
3310 // all at once at the start of a level, not when it stalls gameplay.
3311 // (especially important to benchmarks)
3313 if (rtlight->isstatic && !nolight && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
3315 if (rtlight->compiled)
3316 R_RTLight_Uncompile(rtlight);
3317 R_RTLight_Compile(rtlight);
3321 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
3323 // look up the light style value at this time
3324 f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3325 VectorScale(rtlight->color, f, rtlight->currentcolor);
3327 if (rtlight->selected)
3329 f = 2 + sin(realtime * M_PI * 4.0);
3330 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3334 // if lightstyle is currently off, don't draw the light
3335 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3338 // skip processing on corona-only lights
3342 // if the light box is offscreen, skip it
3343 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3346 VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
3347 VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
3349 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3351 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3353 // compiled light, world available and can receive realtime lighting
3354 // retrieve leaf information
3355 numleafs = rtlight->static_numleafs;
3356 leaflist = rtlight->static_leaflist;
3357 leafpvs = rtlight->static_leafpvs;
3358 numsurfaces = rtlight->static_numsurfaces;
3359 surfacelist = rtlight->static_surfacelist;
3360 //surfacesides = NULL;
3361 shadowtrispvs = rtlight->static_shadowtrispvs;
3362 lighttrispvs = rtlight->static_lighttrispvs;
3364 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3366 // dynamic light, world available and can receive realtime lighting
3367 // calculate lit surfaces and leafs
3368 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);
3369 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3370 leaflist = r_shadow_buffer_leaflist;
3371 leafpvs = r_shadow_buffer_leafpvs;
3372 surfacelist = r_shadow_buffer_surfacelist;
3373 //surfacesides = r_shadow_buffer_surfacesides;
3374 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3375 lighttrispvs = r_shadow_buffer_lighttrispvs;
3376 // if the reduced leaf bounds are offscreen, skip it
3377 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3388 //surfacesides = NULL;
3389 shadowtrispvs = NULL;
3390 lighttrispvs = NULL;
3392 // check if light is illuminating any visible leafs
3395 for (i = 0;i < numleafs;i++)
3396 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3402 // make a list of lit entities and shadow casting entities
3403 numlightentities = 0;
3404 numlightentities_noselfshadow = 0;
3405 numshadowentities = 0;
3406 numshadowentities_noselfshadow = 0;
3408 // add dynamic entities that are lit by the light
3409 for (i = 0;i < r_refdef.scene.numentities;i++)
3412 entity_render_t *ent = r_refdef.scene.entities[i];
3414 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3416 // skip the object entirely if it is not within the valid
3417 // shadow-casting region (which includes the lit region)
3418 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
3420 if (!(model = ent->model))
3422 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
3424 // this entity wants to receive light, is visible, and is
3425 // inside the light box
3426 // TODO: check if the surfaces in the model can receive light
3427 // so now check if it's in a leaf seen by the light
3428 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))
3430 if (ent->flags & RENDER_NOSELFSHADOW)
3431 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
3433 lightentities[numlightentities++] = ent;
3434 // since it is lit, it probably also casts a shadow...
3435 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3436 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3437 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3439 // note: exterior models without the RENDER_NOSELFSHADOW
3440 // flag still create a RENDER_NOSELFSHADOW shadow but
3441 // are lit normally, this means that they are
3442 // self-shadowing but do not shadow other
3443 // RENDER_NOSELFSHADOW entities such as the gun
3444 // (very weird, but keeps the player shadow off the gun)
3445 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3446 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3448 shadowentities[numshadowentities++] = ent;
3451 else if (ent->flags & RENDER_SHADOW)
3453 // this entity is not receiving light, but may still need to
3455 // TODO: check if the surfaces in the model can cast shadow
3456 // now check if it is in a leaf seen by the light
3457 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))
3459 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3460 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3461 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3463 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3464 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3466 shadowentities[numshadowentities++] = ent;
3471 // return if there's nothing at all to light
3472 if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
3475 // count this light in the r_speeds
3476 r_refdef.stats.lights++;
3478 // flag it as worth drawing later
3479 rtlight->draw = true;
3481 // cache all the animated entities that cast a shadow but are not visible
3482 for (i = 0;i < numshadowentities;i++)
3483 if (!shadowentities[i]->animcache_vertex3f)
3484 R_AnimCache_GetEntity(shadowentities[i], false, false);
3485 for (i = 0;i < numshadowentities_noselfshadow;i++)
3486 if (!shadowentities_noselfshadow[i]->animcache_vertex3f)
3487 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
3489 // allocate some temporary memory for rendering this light later in the frame
3490 // reusable buffers need to be copied, static data can be used as-is
3491 rtlight->cached_numlightentities = numlightentities;
3492 rtlight->cached_numlightentities_noselfshadow = numlightentities_noselfshadow;
3493 rtlight->cached_numshadowentities = numshadowentities;
3494 rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
3495 rtlight->cached_numsurfaces = numsurfaces;
3496 rtlight->cached_lightentities = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
3497 rtlight->cached_lightentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
3498 rtlight->cached_shadowentities = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
3499 rtlight->cached_shadowentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
3500 if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
3502 int numshadowtrispvsbytes = (((r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles) + 7) >> 3);
3503 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
3504 rtlight->cached_shadowtrispvs = (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
3505 rtlight->cached_lighttrispvs = (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
3506 rtlight->cached_surfacelist = (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
3510 // compiled light data
3511 rtlight->cached_shadowtrispvs = shadowtrispvs;
3512 rtlight->cached_lighttrispvs = lighttrispvs;
3513 rtlight->cached_surfacelist = surfacelist;
3517 void R_Shadow_DrawLight(rtlight_t *rtlight)
3521 unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
3522 int numlightentities;
3523 int numlightentities_noselfshadow;
3524 int numshadowentities;
3525 int numshadowentities_noselfshadow;
3526 entity_render_t **lightentities;
3527 entity_render_t **lightentities_noselfshadow;
3528 entity_render_t **shadowentities;
3529 entity_render_t **shadowentities_noselfshadow;
3531 static unsigned char entitysides[MAX_EDICTS];
3532 static unsigned char entitysides_noselfshadow[MAX_EDICTS];
3533 vec3_t nearestpoint;
3535 qboolean castshadows;
3538 // check if we cached this light this frame (meaning it is worth drawing)
3542 numlightentities = rtlight->cached_numlightentities;
3543 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
3544 numshadowentities = rtlight->cached_numshadowentities;
3545 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
3546 numsurfaces = rtlight->cached_numsurfaces;
3547 lightentities = rtlight->cached_lightentities;
3548 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
3549 shadowentities = rtlight->cached_shadowentities;
3550 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
3551 shadowtrispvs = rtlight->cached_shadowtrispvs;
3552 lighttrispvs = rtlight->cached_lighttrispvs;
3553 surfacelist = rtlight->cached_surfacelist;
3555 // set up a scissor rectangle for this light
3556 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3559 // don't let sound skip if going slow
3560 if (r_refdef.scene.extraupdate)
3563 // make this the active rtlight for rendering purposes
3564 R_Shadow_RenderMode_ActiveLight(rtlight);
3566 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
3568 // optionally draw visible shape of the shadow volumes
3569 // for performance analysis by level designers
3570 R_Shadow_RenderMode_VisibleShadowVolumes();
3572 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
3573 for (i = 0;i < numshadowentities;i++)
3574 R_Shadow_DrawEntityShadow(shadowentities[i]);
3575 for (i = 0;i < numshadowentities_noselfshadow;i++)
3576 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3577 R_Shadow_RenderMode_VisibleLighting(false, false);
3580 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
3582 // optionally draw the illuminated areas
3583 // for performance analysis by level designers
3584 R_Shadow_RenderMode_VisibleLighting(false, false);
3586 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3587 for (i = 0;i < numlightentities;i++)
3588 R_Shadow_DrawEntityLight(lightentities[i]);
3589 for (i = 0;i < numlightentities_noselfshadow;i++)
3590 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3593 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
3595 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
3596 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
3597 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
3598 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
3600 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance/rtlight->radius));
3601 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
3602 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
3604 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
3610 int receivermask = 0;
3611 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
3612 Matrix4x4_Abs(&radiustolight);
3614 r_shadow_shadowmaplod = 0;
3615 for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
3616 if ((r_shadow_shadowmapmaxsize >> i) > lodlinear)
3617 r_shadow_shadowmaplod = i;
3619 size = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
3621 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
3623 surfacesides = NULL;
3626 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3628 castermask = rtlight->static_shadowmap_casters;
3629 receivermask = rtlight->static_shadowmap_receivers;
3633 surfacesides = r_shadow_buffer_surfacesides;
3634 for(i = 0;i < numsurfaces;i++)
3636 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
3637 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3638 castermask |= surfacesides[i];
3639 receivermask |= surfacesides[i];
3643 if (receivermask < 0x3F)
3645 for (i = 0;i < numlightentities;i++)
3646 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3647 if (receivermask < 0x3F)
3648 for(i = 0; i < numlightentities_noselfshadow;i++)
3649 receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3652 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
3656 for (i = 0;i < numshadowentities;i++)
3657 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3658 for (i = 0;i < numshadowentities_noselfshadow;i++)
3659 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3662 //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
3664 // render shadow casters into 6 sided depth texture
3665 for (side = 0;side < 6;side++) if (receivermask & (1 << side))
3667 R_Shadow_RenderMode_ShadowMap(side, receivermask, size);
3668 if (! (castermask & (1 << side))) continue;
3670 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
3671 for (i = 0;i < numshadowentities;i++) if (entitysides[i] & (1 << side))
3672 R_Shadow_DrawEntityShadow(shadowentities[i]);
3675 if (numlightentities_noselfshadow)
3677 // render lighting using the depth texture as shadowmap
3678 // draw lighting in the unmasked areas
3679 R_Shadow_RenderMode_Lighting(false, false, true);
3680 for (i = 0;i < numlightentities_noselfshadow;i++)
3681 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3684 // render shadow casters into 6 sided depth texture
3685 if (numshadowentities_noselfshadow)
3687 for (side = 0;side < 6;side++) if ((receivermask & castermask) & (1 << side))
3689 R_Shadow_RenderMode_ShadowMap(side, 0, size);
3690 for (i = 0;i < numshadowentities_noselfshadow;i++) if (entitysides_noselfshadow[i] & (1 << side))
3691 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3695 // render lighting using the depth texture as shadowmap
3696 // draw lighting in the unmasked areas
3697 R_Shadow_RenderMode_Lighting(false, false, true);
3698 // draw lighting in the unmasked areas
3700 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3701 for (i = 0;i < numlightentities;i++)
3702 R_Shadow_DrawEntityLight(lightentities[i]);
3704 else if (castshadows && vid.stencil)
3706 // draw stencil shadow volumes to mask off pixels that are in shadow
3707 // so that they won't receive lighting
3708 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
3709 R_Shadow_ClearStencil();
3712 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
3713 for (i = 0;i < numshadowentities;i++)
3714 R_Shadow_DrawEntityShadow(shadowentities[i]);
3716 // draw lighting in the unmasked areas
3717 R_Shadow_RenderMode_Lighting(true, false, false);
3718 for (i = 0;i < numlightentities_noselfshadow;i++)
3719 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3721 for (i = 0;i < numshadowentities_noselfshadow;i++)
3722 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3724 // draw lighting in the unmasked areas
3725 R_Shadow_RenderMode_Lighting(true, false, false);
3727 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3728 for (i = 0;i < numlightentities;i++)
3729 R_Shadow_DrawEntityLight(lightentities[i]);
3733 // draw lighting in the unmasked areas
3734 R_Shadow_RenderMode_Lighting(false, false, false);
3736 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3737 for (i = 0;i < numlightentities;i++)
3738 R_Shadow_DrawEntityLight(lightentities[i]);
3739 for (i = 0;i < numlightentities_noselfshadow;i++)
3740 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3743 if (r_shadow_usingdeferredprepass)
3745 // when rendering deferred lighting, we simply rasterize the box
3746 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
3747 R_Shadow_RenderMode_DrawDeferredLight(false, true);
3748 else if (castshadows && vid.stencil)
3749 R_Shadow_RenderMode_DrawDeferredLight(true, false);
3751 R_Shadow_RenderMode_DrawDeferredLight(false, false);
3755 static void R_Shadow_FreeDeferred(void)
3757 R_Mesh_DestroyFramebufferObject(r_shadow_prepassgeometryfbo);
3758 r_shadow_prepassgeometryfbo = 0;
3760 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingfbo);
3761 r_shadow_prepasslightingfbo = 0;
3763 if (r_shadow_prepassgeometrydepthtexture)
3764 R_FreeTexture(r_shadow_prepassgeometrydepthtexture);
3765 r_shadow_prepassgeometrydepthtexture = NULL;
3767 if (r_shadow_prepassgeometrydepthcolortexture)
3768 R_FreeTexture(r_shadow_prepassgeometrydepthcolortexture);
3769 r_shadow_prepassgeometrydepthcolortexture = NULL;
3771 if (r_shadow_prepassgeometrynormalmaptexture)
3772 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
3773 r_shadow_prepassgeometrynormalmaptexture = NULL;
3775 if (r_shadow_prepasslightingdiffusetexture)
3776 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
3777 r_shadow_prepasslightingdiffusetexture = NULL;
3779 if (r_shadow_prepasslightingspeculartexture)
3780 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
3781 r_shadow_prepasslightingspeculartexture = NULL;
3784 void R_Shadow_DrawPrepass(void)
3792 entity_render_t *ent;
3793 float clearcolor[4];
3795 R_Mesh_ResetTextureState();
3797 GL_ColorMask(1,1,1,1);
3798 GL_BlendFunc(GL_ONE, GL_ZERO);
3801 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, r_shadow_prepassgeometrydepthcolortexture, NULL, NULL);
3802 Vector4Set(clearcolor, 0.5f,0.5f,0.5f,1.0f);
3803 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
3804 if (r_timereport_active)
3805 R_TimeReport("prepasscleargeom");
3807 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
3808 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
3809 if (r_timereport_active)
3810 R_TimeReport("prepassworld");
3812 for (i = 0;i < r_refdef.scene.numentities;i++)
3814 if (!r_refdef.viewcache.entityvisible[i])
3816 ent = r_refdef.scene.entities[i];
3817 if (ent->model && ent->model->DrawPrepass != NULL)
3818 ent->model->DrawPrepass(ent);
3821 if (r_timereport_active)
3822 R_TimeReport("prepassmodels");
3824 GL_DepthMask(false);
3825 GL_ColorMask(1,1,1,1);
3828 R_Mesh_SetRenderTargets(r_shadow_prepasslightingfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
3829 Vector4Set(clearcolor, 0, 0, 0, 0);
3830 GL_Clear(GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
3831 if (r_timereport_active)
3832 R_TimeReport("prepassclearlit");
3834 R_Shadow_RenderMode_Begin();
3836 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3837 if (r_shadow_debuglight.integer >= 0)
3839 lightindex = r_shadow_debuglight.integer;
3840 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3841 if (light && (light->flags & flag) && light->rtlight.draw)
3842 R_Shadow_DrawLight(&light->rtlight);
3846 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3847 for (lightindex = 0;lightindex < range;lightindex++)
3849 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3850 if (light && (light->flags & flag) && light->rtlight.draw)
3851 R_Shadow_DrawLight(&light->rtlight);
3854 if (r_refdef.scene.rtdlight)
3855 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
3856 if (r_refdef.scene.lights[lnum]->draw)
3857 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
3859 R_Mesh_ResetRenderTargets();
3861 R_Shadow_RenderMode_End();
3863 if (r_timereport_active)
3864 R_TimeReport("prepasslights");
3867 void R_Shadow_DrawLightSprites(void);
3868 void R_Shadow_PrepareLights(void)
3878 if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4) ||
3879 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
3880 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20) ||
3881 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
3882 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
3883 r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
3884 R_Shadow_FreeShadowMaps();
3886 r_shadow_usingshadowmaportho = false;
3888 switch (vid.renderpath)
3890 case RENDERPATH_GL20:
3891 case RENDERPATH_CGGL:
3892 case RENDERPATH_D3D9:
3893 case RENDERPATH_D3D10:
3894 case RENDERPATH_D3D11:
3895 case RENDERPATH_SOFT:
3896 case RENDERPATH_GLES2:
3897 if (!r_shadow_deferred.integer || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_STENCIL || !vid.support.ext_framebuffer_object || vid.maxdrawbuffers < 2)
3899 r_shadow_usingdeferredprepass = false;
3900 if (r_shadow_prepass_width)
3901 R_Shadow_FreeDeferred();
3902 r_shadow_prepass_width = r_shadow_prepass_height = 0;
3906 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
3908 R_Shadow_FreeDeferred();
3910 r_shadow_usingdeferredprepass = true;
3911 r_shadow_prepass_width = vid.width;
3912 r_shadow_prepass_height = vid.height;
3913 r_shadow_prepassgeometrydepthtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "prepassgeometrydepthmap", vid.width, vid.height, 24, false);
3914 switch (vid.renderpath)
3916 case RENDERPATH_D3D9:
3917 r_shadow_prepassgeometrydepthcolortexture = R_LoadTexture2D(r_shadow_texturepool, "prepassgeometrydepthcolormap", vid.width, vid.height, NULL, TEXTYPE_COLORBUFFER, TEXF_RENDERTARGET | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCENEAREST, -1, NULL);
3922 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);
3923 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);
3924 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);
3926 // set up the geometry pass fbo (depth + normalmap)
3927 r_shadow_prepassgeometryfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
3928 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, r_shadow_prepassgeometrydepthcolortexture, NULL, NULL);
3929 // render depth into one texture and normalmap into the other
3930 if (qglDrawBuffersARB)
3932 qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);CHECKGLERROR
3933 qglReadBuffer(GL_NONE);CHECKGLERROR
3934 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
3935 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
3937 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
3938 Cvar_SetValueQuick(&r_shadow_deferred, 0);
3939 r_shadow_usingdeferredprepass = false;
3943 // set up the lighting pass fbo (diffuse + specular)
3944 r_shadow_prepasslightingfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
3945 R_Mesh_SetRenderTargets(r_shadow_prepasslightingfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
3946 // render diffuse into one texture and specular into another,
3947 // with depth and normalmap bound as textures,
3948 // with depth bound as attachment as well
3949 if (qglDrawBuffersARB)
3951 qglDrawBuffersARB(2, r_shadow_prepasslightingdrawbuffers);CHECKGLERROR
3952 qglReadBuffer(GL_NONE);CHECKGLERROR
3953 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
3954 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
3956 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
3957 Cvar_SetValueQuick(&r_shadow_deferred, 0);
3958 r_shadow_usingdeferredprepass = false;
3963 case RENDERPATH_GL13:
3964 case RENDERPATH_GL11:
3965 r_shadow_usingdeferredprepass = false;
3969 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);
3971 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3972 if (r_shadow_debuglight.integer >= 0)
3974 lightindex = r_shadow_debuglight.integer;
3975 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3976 if (light && (light->flags & flag))
3977 R_Shadow_PrepareLight(&light->rtlight);
3981 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3982 for (lightindex = 0;lightindex < range;lightindex++)
3984 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3985 if (light && (light->flags & flag))
3986 R_Shadow_PrepareLight(&light->rtlight);
3989 if (r_refdef.scene.rtdlight)
3991 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
3992 R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
3994 else if(gl_flashblend.integer)
3996 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
3998 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
3999 f = (rtlight->style >= 0 ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4000 VectorScale(rtlight->color, f, rtlight->currentcolor);
4004 if (r_editlights.integer)
4005 R_Shadow_DrawLightSprites();
4008 void R_Shadow_DrawLights(void)
4016 R_Shadow_RenderMode_Begin();
4018 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4019 if (r_shadow_debuglight.integer >= 0)
4021 lightindex = r_shadow_debuglight.integer;
4022 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4023 if (light && (light->flags & flag))
4024 R_Shadow_DrawLight(&light->rtlight);
4028 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4029 for (lightindex = 0;lightindex < range;lightindex++)
4031 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4032 if (light && (light->flags & flag))
4033 R_Shadow_DrawLight(&light->rtlight);
4036 if (r_refdef.scene.rtdlight)
4037 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4038 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4040 R_Shadow_RenderMode_End();
4043 extern const float r_screenvertex3f[12];
4044 extern void R_SetupView(qboolean allowwaterclippingplane);
4045 extern void R_ResetViewRendering3D(void);
4046 extern void R_ResetViewRendering2D(void);
4047 extern cvar_t r_shadows;
4048 extern cvar_t r_shadows_darken;
4049 extern cvar_t r_shadows_drawafterrtlighting;
4050 extern cvar_t r_shadows_castfrombmodels;
4051 extern cvar_t r_shadows_throwdistance;
4052 extern cvar_t r_shadows_throwdirection;
4053 extern cvar_t r_shadows_focus;
4054 extern cvar_t r_shadows_shadowmapscale;
4056 void R_Shadow_PrepareModelShadows(void)
4059 float scale, size, radius, dot1, dot2;
4060 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
4061 entity_render_t *ent;
4063 if (!r_refdef.scene.numentities)
4066 switch (r_shadow_shadowmode)
4068 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4069 if (r_shadows.integer >= 2)
4072 case R_SHADOW_SHADOWMODE_STENCIL:
4073 for (i = 0;i < r_refdef.scene.numentities;i++)
4075 ent = r_refdef.scene.entities[i];
4076 if (!ent->animcache_vertex3f && ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4077 R_AnimCache_GetEntity(ent, false, false);
4084 size = 2*r_shadow_shadowmapmaxsize;
4085 scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
4086 radius = 0.5f * size / scale;
4088 Math_atov(r_shadows_throwdirection.string, shadowdir);
4089 VectorNormalize(shadowdir);
4090 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4091 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4092 if (fabs(dot1) <= fabs(dot2))
4093 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4095 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4096 VectorNormalize(shadowforward);
4097 CrossProduct(shadowdir, shadowforward, shadowright);
4098 Math_atov(r_shadows_focus.string, shadowfocus);
4099 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4100 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4101 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4102 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4103 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4105 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4107 shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4108 shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4109 shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4110 shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4111 shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4112 shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4114 for (i = 0;i < r_refdef.scene.numentities;i++)
4116 ent = r_refdef.scene.entities[i];
4117 if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
4119 // cast shadows from anything of the map (submodels are optional)
4120 if (!ent->animcache_vertex3f && ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4121 R_AnimCache_GetEntity(ent, false, false);
4125 void R_DrawModelShadowMaps(void)
4128 float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
4129 entity_render_t *ent;
4130 vec3_t relativelightorigin;
4131 vec3_t relativelightdirection, relativeforward, relativeright;
4132 vec3_t relativeshadowmins, relativeshadowmaxs;
4133 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
4135 matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
4136 r_viewport_t viewport;
4138 float clearcolor[4];
4140 if (!r_refdef.scene.numentities)
4143 switch (r_shadow_shadowmode)
4145 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4151 R_ResetViewRendering3D();
4152 R_Shadow_RenderMode_Begin();
4153 R_Shadow_RenderMode_ActiveLight(NULL);
4155 switch (r_shadow_shadowmode)
4157 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4158 if (!r_shadow_shadowmap2dtexture)
4159 R_Shadow_MakeShadowMap(0, r_shadow_shadowmapmaxsize);
4160 fbo = r_shadow_fbo2d;
4161 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
4162 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
4163 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
4169 size = 2*r_shadow_shadowmapmaxsize;
4170 scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
4171 radius = 0.5f / scale;
4172 nearclip = -r_shadows_throwdistance.value;
4173 farclip = r_shadows_throwdistance.value;
4174 bias = r_shadow_shadowmapping_bias.value * r_shadow_shadowmapping_nearclip.value / (2 * r_shadows_throwdistance.value) * (1024.0f / size);
4176 r_shadow_shadowmap_parameters[0] = size;
4177 r_shadow_shadowmap_parameters[1] = size;
4178 r_shadow_shadowmap_parameters[2] = 1.0;
4179 r_shadow_shadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
4181 Math_atov(r_shadows_throwdirection.string, shadowdir);
4182 VectorNormalize(shadowdir);
4183 Math_atov(r_shadows_focus.string, shadowfocus);
4184 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4185 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4186 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4187 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4188 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4189 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4190 if (fabs(dot1) <= fabs(dot2))
4191 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4193 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4194 VectorNormalize(shadowforward);
4195 VectorM(scale, shadowforward, &m[0]);
4196 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4198 m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
4199 CrossProduct(shadowdir, shadowforward, shadowright);
4200 VectorM(scale, shadowright, &m[4]);
4201 m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
4202 VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
4203 m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
4204 Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
4205 Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
4206 R_Viewport_InitOrtho(&viewport, &cameramatrix, 0, 0, size, size, 0, 0, 1, 1, 0, -1, NULL);
4208 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4210 R_Mesh_SetRenderTargets(fbo, r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
4211 R_SetupShader_DepthOrShadow();
4212 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
4215 R_SetViewport(&viewport);
4216 GL_Scissor(viewport.x, viewport.y, min(viewport.width + r_shadow_shadowmapborder, 2*r_shadow_shadowmapmaxsize), viewport.height + r_shadow_shadowmapborder);
4217 Vector4Set(clearcolor, 1,1,1,1);
4218 // in D3D9 we have to render to a color texture shadowmap
4219 // in GL we render directly to a depth texture only
4220 if (r_shadow_shadowmap2dtexture)
4221 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4223 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4224 // render into a slightly restricted region so that the borders of the
4225 // shadowmap area fade away, rather than streaking across everything
4226 // outside the usable area
4227 GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
4231 R_Mesh_ResetRenderTargets();
4232 R_SetupShader_ShowDepth();
4233 GL_ColorMask(1,1,1,1);
4234 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4237 for (i = 0;i < r_refdef.scene.numentities;i++)
4239 ent = r_refdef.scene.entities[i];
4241 // cast shadows from anything of the map (submodels are optional)
4242 if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4244 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4245 Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
4246 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4247 Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
4248 Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
4249 relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4250 relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4251 relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4252 relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4253 relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4254 relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4255 RSurf_ActiveModelEntity(ent, false, false, false);
4256 ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
4257 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4264 unsigned char *rawpixels = Z_Malloc(viewport.width*viewport.height*4);
4266 qglReadPixels(viewport.x, viewport.y, viewport.width, viewport.height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, rawpixels);
4268 Image_WriteTGABGRA("r_shadows_2.tga", viewport.width, viewport.height, rawpixels);
4269 Cvar_SetValueQuick(&r_test, 0);
4274 R_Shadow_RenderMode_End();
4276 Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
4277 Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
4278 Matrix4x4_CreateScale3(&scalematrix, size, -size, 1);
4279 Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
4280 Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
4281 Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
4283 switch (vid.renderpath)
4285 case RENDERPATH_GL11:
4286 case RENDERPATH_GL13:
4287 case RENDERPATH_GL20:
4288 case RENDERPATH_CGGL:
4289 case RENDERPATH_SOFT:
4290 case RENDERPATH_GLES2:
4292 case RENDERPATH_D3D9:
4293 case RENDERPATH_D3D10:
4294 case RENDERPATH_D3D11:
4295 #ifdef OPENGL_ORIENTATION
4296 r_shadow_shadowmapmatrix.m[0][0] *= -1.0f;
4297 r_shadow_shadowmapmatrix.m[0][1] *= -1.0f;
4298 r_shadow_shadowmapmatrix.m[0][2] *= -1.0f;
4299 r_shadow_shadowmapmatrix.m[0][3] *= -1.0f;
4301 r_shadow_shadowmapmatrix.m[0][0] *= -1.0f;
4302 r_shadow_shadowmapmatrix.m[1][0] *= -1.0f;
4303 r_shadow_shadowmapmatrix.m[2][0] *= -1.0f;
4304 r_shadow_shadowmapmatrix.m[3][0] *= -1.0f;
4309 r_shadow_usingshadowmaportho = true;
4310 switch (r_shadow_shadowmode)
4312 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4313 r_shadow_usingshadowmap2d = true;
4320 void R_DrawModelShadows(void)
4323 float relativethrowdistance;
4324 entity_render_t *ent;
4325 vec3_t relativelightorigin;
4326 vec3_t relativelightdirection;
4327 vec3_t relativeshadowmins, relativeshadowmaxs;
4328 vec3_t tmp, shadowdir;
4330 if (!r_refdef.scene.numentities || !vid.stencil || (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL && r_shadows.integer != 1))
4333 R_ResetViewRendering3D();
4334 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4335 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4336 R_Shadow_RenderMode_Begin();
4337 R_Shadow_RenderMode_ActiveLight(NULL);
4338 r_shadow_lightscissor[0] = r_refdef.view.x;
4339 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
4340 r_shadow_lightscissor[2] = r_refdef.view.width;
4341 r_shadow_lightscissor[3] = r_refdef.view.height;
4342 R_Shadow_RenderMode_StencilShadowVolumes(false);
4345 if (r_shadows.integer == 2)
4347 Math_atov(r_shadows_throwdirection.string, shadowdir);
4348 VectorNormalize(shadowdir);
4351 R_Shadow_ClearStencil();
4353 for (i = 0;i < r_refdef.scene.numentities;i++)
4355 ent = r_refdef.scene.entities[i];
4357 // cast shadows from anything of the map (submodels are optional)
4358 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4360 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4361 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
4362 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
4363 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
4364 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4367 if(ent->entitynumber != 0)
4369 if(ent->entitynumber >= MAX_EDICTS) // csqc entity
4371 // FIXME handle this
4372 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4376 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
4377 int entnum, entnum2, recursion;
4378 entnum = entnum2 = ent->entitynumber;
4379 for(recursion = 32; recursion > 0; --recursion)
4381 entnum2 = cl.entities[entnum].state_current.tagentity;
4382 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
4387 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
4389 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
4390 // transform into modelspace of OUR entity
4391 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
4392 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
4395 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4399 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4402 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
4403 RSurf_ActiveModelEntity(ent, false, false, false);
4404 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4405 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4409 // not really the right mode, but this will disable any silly stencil features
4410 R_Shadow_RenderMode_End();
4412 // set up ortho view for rendering this pass
4413 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4414 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4415 //GL_ScissorTest(true);
4416 //R_EntityMatrix(&identitymatrix);
4417 //R_Mesh_ResetTextureState();
4418 R_ResetViewRendering2D();
4420 // set up a darkening blend on shadowed areas
4421 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4422 //GL_DepthRange(0, 1);
4423 //GL_DepthTest(false);
4424 //GL_DepthMask(false);
4425 //GL_PolygonOffset(0, 0);CHECKGLERROR
4426 GL_Color(0, 0, 0, r_shadows_darken.value);
4427 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4428 //GL_DepthFunc(GL_ALWAYS);
4429 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_NOTEQUAL, 128, 255);
4431 // apply the blend to the shadowed areas
4432 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, NULL);
4433 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
4434 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4436 // restore the viewport
4437 R_SetViewport(&r_refdef.view.viewport);
4439 // restore other state to normal
4440 //R_Shadow_RenderMode_End();
4443 void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4446 vec3_t centerorigin;
4448 // if it's too close, skip it
4449 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
4451 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4454 if (usequery && r_numqueries + 2 <= r_maxqueries)
4456 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4457 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4458 // 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
4459 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4461 switch(vid.renderpath)
4463 case RENDERPATH_GL20:
4464 case RENDERPATH_GL13:
4465 case RENDERPATH_GL11:
4466 case RENDERPATH_CGGL:
4467 case RENDERPATH_GLES2:
4469 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use GL_DepthFunc instead
4470 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
4471 GL_DepthFunc(GL_ALWAYS);
4472 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4473 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL);
4474 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4475 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4476 GL_DepthFunc(GL_LEQUAL);
4477 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
4478 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4479 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL);
4480 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4481 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4484 case RENDERPATH_D3D9:
4485 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4487 case RENDERPATH_D3D10:
4488 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4490 case RENDERPATH_D3D11:
4491 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4493 case RENDERPATH_SOFT:
4494 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4498 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4501 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
4503 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4506 GLint allpixels = 0, visiblepixels = 0;
4507 // now we have to check the query result
4508 if (rtlight->corona_queryindex_visiblepixels)
4510 switch(vid.renderpath)
4512 case RENDERPATH_GL20:
4513 case RENDERPATH_GL13:
4514 case RENDERPATH_GL11:
4515 case RENDERPATH_CGGL:
4516 case RENDERPATH_GLES2:
4518 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
4519 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
4522 case RENDERPATH_D3D9:
4523 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4525 case RENDERPATH_D3D10:
4526 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4528 case RENDERPATH_D3D11:
4529 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4531 case RENDERPATH_SOFT:
4532 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4535 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
4536 if (visiblepixels < 1 || allpixels < 1)
4538 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
4539 cscale *= rtlight->corona_visibility;
4543 // FIXME: these traces should scan all render entities instead of cl.world
4544 if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
4547 VectorScale(rtlight->currentcolor, cscale, color);
4548 if (VectorLength(color) > (1.0f / 256.0f))
4551 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
4554 VectorNegate(color, color);
4555 switch(vid.renderpath)
4557 case RENDERPATH_GL11:
4558 case RENDERPATH_GL13:
4559 case RENDERPATH_GL20:
4560 case RENDERPATH_CGGL:
4561 case RENDERPATH_GLES2:
4562 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
4564 case RENDERPATH_D3D9:
4566 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_SUBTRACT);
4569 case RENDERPATH_D3D10:
4570 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4572 case RENDERPATH_D3D11:
4573 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4575 case RENDERPATH_SOFT:
4576 DPSOFTRAST_BlendSubtract(true);
4580 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4581 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);
4582 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4585 switch(vid.renderpath)
4587 case RENDERPATH_GL11:
4588 case RENDERPATH_GL13:
4589 case RENDERPATH_GL20:
4590 case RENDERPATH_CGGL:
4591 case RENDERPATH_GLES2:
4592 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
4594 case RENDERPATH_D3D9:
4596 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_ADD);
4599 case RENDERPATH_D3D10:
4600 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4602 case RENDERPATH_D3D11:
4603 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4605 case RENDERPATH_SOFT:
4606 DPSOFTRAST_BlendSubtract(false);
4613 void R_Shadow_DrawCoronas(void)
4616 qboolean usequery = false;
4621 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4623 if (r_waterstate.renderingscene)
4625 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4626 R_EntityMatrix(&identitymatrix);
4628 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4630 // check occlusion of coronas
4631 // use GL_ARB_occlusion_query if available
4632 // otherwise use raytraces
4634 switch (vid.renderpath)
4636 case RENDERPATH_GL11:
4637 case RENDERPATH_GL13:
4638 case RENDERPATH_GL20:
4639 case RENDERPATH_CGGL:
4640 case RENDERPATH_GLES2:
4641 usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
4644 GL_ColorMask(0,0,0,0);
4645 if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
4646 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
4649 r_maxqueries = (range + r_refdef.scene.numlights) * 4;
4650 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
4652 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
4655 RSurf_ActiveWorldEntity();
4656 GL_BlendFunc(GL_ONE, GL_ZERO);
4657 GL_CullFace(GL_NONE);
4658 GL_DepthMask(false);
4659 GL_DepthRange(0, 1);
4660 GL_PolygonOffset(0, 0);
4662 R_Mesh_ResetTextureState();
4663 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
4666 case RENDERPATH_D3D9:
4668 //Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4670 case RENDERPATH_D3D10:
4671 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4673 case RENDERPATH_D3D11:
4674 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4676 case RENDERPATH_SOFT:
4678 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4681 for (lightindex = 0;lightindex < range;lightindex++)
4683 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4686 rtlight = &light->rtlight;
4687 rtlight->corona_visibility = 0;
4688 rtlight->corona_queryindex_visiblepixels = 0;
4689 rtlight->corona_queryindex_allpixels = 0;
4690 if (!(rtlight->flags & flag))
4692 if (rtlight->corona <= 0)
4694 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4696 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4698 for (i = 0;i < r_refdef.scene.numlights;i++)
4700 rtlight = r_refdef.scene.lights[i];
4701 rtlight->corona_visibility = 0;
4702 rtlight->corona_queryindex_visiblepixels = 0;
4703 rtlight->corona_queryindex_allpixels = 0;
4704 if (!(rtlight->flags & flag))
4706 if (rtlight->corona <= 0)
4708 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4711 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4713 // now draw the coronas using the query data for intensity info
4714 for (lightindex = 0;lightindex < range;lightindex++)
4716 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4719 rtlight = &light->rtlight;
4720 if (rtlight->corona_visibility <= 0)
4722 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4724 for (i = 0;i < r_refdef.scene.numlights;i++)
4726 rtlight = r_refdef.scene.lights[i];
4727 if (rtlight->corona_visibility <= 0)
4729 if (gl_flashblend.integer)
4730 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4732 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4738 dlight_t *R_Shadow_NewWorldLight(void)
4740 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4743 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)
4746 // validate parameters
4747 if (style < 0 || style >= MAX_LIGHTSTYLES)
4749 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
4755 // copy to light properties
4756 VectorCopy(origin, light->origin);
4757 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4758 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4759 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4761 light->color[0] = max(color[0], 0);
4762 light->color[1] = max(color[1], 0);
4763 light->color[2] = max(color[2], 0);
4765 light->color[0] = color[0];
4766 light->color[1] = color[1];
4767 light->color[2] = color[2];
4768 light->radius = max(radius, 0);
4769 light->style = style;
4770 light->shadow = shadowenable;
4771 light->corona = corona;
4772 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4773 light->coronasizescale = coronasizescale;
4774 light->ambientscale = ambientscale;
4775 light->diffusescale = diffusescale;
4776 light->specularscale = specularscale;
4777 light->flags = flags;
4779 // update renderable light data
4780 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4781 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);
4784 void R_Shadow_FreeWorldLight(dlight_t *light)
4786 if (r_shadow_selectedlight == light)
4787 r_shadow_selectedlight = NULL;
4788 R_RTLight_Uncompile(&light->rtlight);
4789 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4792 void R_Shadow_ClearWorldLights(void)
4796 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4797 for (lightindex = 0;lightindex < range;lightindex++)
4799 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4801 R_Shadow_FreeWorldLight(light);
4803 r_shadow_selectedlight = NULL;
4806 void R_Shadow_SelectLight(dlight_t *light)
4808 if (r_shadow_selectedlight)
4809 r_shadow_selectedlight->selected = false;
4810 r_shadow_selectedlight = light;
4811 if (r_shadow_selectedlight)
4812 r_shadow_selectedlight->selected = true;
4815 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4817 // this is never batched (there can be only one)
4819 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
4820 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4821 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4824 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4829 skinframe_t *skinframe;
4832 // this is never batched (due to the ent parameter changing every time)
4833 // so numsurfaces == 1 and surfacelist[0] == lightnumber
4834 const dlight_t *light = (dlight_t *)ent;
4837 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
4840 VectorScale(light->color, intensity, spritecolor);
4841 if (VectorLength(spritecolor) < 0.1732f)
4842 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
4843 if (VectorLength(spritecolor) > 1.0f)
4844 VectorNormalize(spritecolor);
4846 // draw light sprite
4847 if (light->cubemapname[0] && !light->shadow)
4848 skinframe = r_editlights_sprcubemapnoshadowlight;
4849 else if (light->cubemapname[0])
4850 skinframe = r_editlights_sprcubemaplight;
4851 else if (!light->shadow)
4852 skinframe = r_editlights_sprnoshadowlight;
4854 skinframe = r_editlights_sprlight;
4856 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);
4857 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4859 // draw selection sprite if light is selected
4860 if (light->selected)
4862 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4863 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4864 // VorteX todo: add normalmode/realtime mode light overlay sprites?
4868 void R_Shadow_DrawLightSprites(void)
4872 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4873 for (lightindex = 0;lightindex < range;lightindex++)
4875 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4877 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
4879 if (!r_editlights_lockcursor)
4880 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
4883 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
4888 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
4889 if (lightindex >= range)
4891 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4894 rtlight = &light->rtlight;
4895 //if (!(rtlight->flags & flag))
4897 VectorCopy(rtlight->shadoworigin, origin);
4898 *radius = rtlight->radius;
4899 VectorCopy(rtlight->color, color);
4903 void R_Shadow_SelectLightInView(void)
4905 float bestrating, rating, temp[3];
4909 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4913 if (r_editlights_lockcursor)
4915 for (lightindex = 0;lightindex < range;lightindex++)
4917 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4920 VectorSubtract(light->origin, r_refdef.view.origin, temp);
4921 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
4924 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
4925 if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1.0f)
4927 bestrating = rating;
4932 R_Shadow_SelectLight(best);
4935 void R_Shadow_LoadWorldLights(void)
4937 int n, a, style, shadow, flags;
4938 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
4939 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
4940 if (cl.worldmodel == NULL)
4942 Con_Print("No map loaded.\n");
4945 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
4946 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4956 for (;COM_Parse(t, true) && strcmp(
4957 if (COM_Parse(t, true))
4959 if (com_token[0] == '!')
4962 origin[0] = atof(com_token+1);
4965 origin[0] = atof(com_token);
4970 while (*s && *s != '\n' && *s != '\r')
4976 // check for modifier flags
4983 #if _MSC_VER >= 1400
4984 #define sscanf sscanf_s
4986 cubemapname[sizeof(cubemapname)-1] = 0;
4987 #if MAX_QPATH != 128
4988 #error update this code if MAX_QPATH changes
4990 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
4991 #if _MSC_VER >= 1400
4992 , sizeof(cubemapname)
4994 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
4997 flags = LIGHTFLAG_REALTIMEMODE;
5005 coronasizescale = 0.25f;
5007 VectorClear(angles);
5010 if (a < 9 || !strcmp(cubemapname, "\"\""))
5012 // remove quotes on cubemapname
5013 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
5016 namelen = strlen(cubemapname) - 2;
5017 memmove(cubemapname, cubemapname + 1, namelen);
5018 cubemapname[namelen] = '\0';
5022 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);
5025 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5033 Con_Printf("invalid rtlights file \"%s\"\n", name);
5034 Mem_Free(lightsstring);
5038 void R_Shadow_SaveWorldLights(void)
5042 size_t bufchars, bufmaxchars;
5044 char name[MAX_QPATH];
5045 char line[MAX_INPUTLINE];
5046 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
5047 // I hate lines which are 3 times my screen size :( --blub
5050 if (cl.worldmodel == NULL)
5052 Con_Print("No map loaded.\n");
5055 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
5056 bufchars = bufmaxchars = 0;
5058 for (lightindex = 0;lightindex < range;lightindex++)
5060 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5063 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
5064 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);
5065 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
5066 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]);
5068 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);
5069 if (bufchars + strlen(line) > bufmaxchars)
5071 bufmaxchars = bufchars + strlen(line) + 2048;
5073 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
5077 memcpy(buf, oldbuf, bufchars);
5083 memcpy(buf + bufchars, line, strlen(line));
5084 bufchars += strlen(line);
5088 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
5093 void R_Shadow_LoadLightsFile(void)
5096 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
5097 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
5098 if (cl.worldmodel == NULL)
5100 Con_Print("No map loaded.\n");
5103 dpsnprintf(name, sizeof(name), "%s.lights", cl.worldnamenoextension);
5104 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5112 while (*s && *s != '\n' && *s != '\r')
5118 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);
5122 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);
5125 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
5126 radius = bound(15, radius, 4096);
5127 VectorScale(color, (2.0f / (8388608.0f)), color);
5128 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5136 Con_Printf("invalid lights file \"%s\"\n", name);
5137 Mem_Free(lightsstring);
5141 // tyrlite/hmap2 light types in the delay field
5142 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
5144 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
5156 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
5157 char key[256], value[MAX_INPUTLINE];
5159 if (cl.worldmodel == NULL)
5161 Con_Print("No map loaded.\n");
5164 // try to load a .ent file first
5165 dpsnprintf(key, sizeof(key), "%s.ent", cl.worldnamenoextension);
5166 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
5167 // and if that is not found, fall back to the bsp file entity string
5169 data = cl.worldmodel->brush.entities;
5172 for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
5174 type = LIGHTTYPE_MINUSX;
5175 origin[0] = origin[1] = origin[2] = 0;
5176 originhack[0] = originhack[1] = originhack[2] = 0;
5177 angles[0] = angles[1] = angles[2] = 0;
5178 color[0] = color[1] = color[2] = 1;
5179 light[0] = light[1] = light[2] = 1;light[3] = 300;
5180 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
5190 if (!COM_ParseToken_Simple(&data, false, false))
5192 if (com_token[0] == '}')
5193 break; // end of entity
5194 if (com_token[0] == '_')
5195 strlcpy(key, com_token + 1, sizeof(key));
5197 strlcpy(key, com_token, sizeof(key));
5198 while (key[strlen(key)-1] == ' ') // remove trailing spaces
5199 key[strlen(key)-1] = 0;
5200 if (!COM_ParseToken_Simple(&data, false, false))
5202 strlcpy(value, com_token, sizeof(value));
5204 // now that we have the key pair worked out...
5205 if (!strcmp("light", key))
5207 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5211 light[0] = vec[0] * (1.0f / 256.0f);
5212 light[1] = vec[0] * (1.0f / 256.0f);
5213 light[2] = vec[0] * (1.0f / 256.0f);
5219 light[0] = vec[0] * (1.0f / 255.0f);
5220 light[1] = vec[1] * (1.0f / 255.0f);
5221 light[2] = vec[2] * (1.0f / 255.0f);
5225 else if (!strcmp("delay", key))
5227 else if (!strcmp("origin", key))
5228 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5229 else if (!strcmp("angle", key))
5230 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5231 else if (!strcmp("angles", key))
5232 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5233 else if (!strcmp("color", key))
5234 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5235 else if (!strcmp("wait", key))
5236 fadescale = atof(value);
5237 else if (!strcmp("classname", key))
5239 if (!strncmp(value, "light", 5))
5242 if (!strcmp(value, "light_fluoro"))
5247 overridecolor[0] = 1;
5248 overridecolor[1] = 1;
5249 overridecolor[2] = 1;
5251 if (!strcmp(value, "light_fluorospark"))
5256 overridecolor[0] = 1;
5257 overridecolor[1] = 1;
5258 overridecolor[2] = 1;
5260 if (!strcmp(value, "light_globe"))
5265 overridecolor[0] = 1;
5266 overridecolor[1] = 0.8;
5267 overridecolor[2] = 0.4;
5269 if (!strcmp(value, "light_flame_large_yellow"))
5274 overridecolor[0] = 1;
5275 overridecolor[1] = 0.5;
5276 overridecolor[2] = 0.1;
5278 if (!strcmp(value, "light_flame_small_yellow"))
5283 overridecolor[0] = 1;
5284 overridecolor[1] = 0.5;
5285 overridecolor[2] = 0.1;
5287 if (!strcmp(value, "light_torch_small_white"))
5292 overridecolor[0] = 1;
5293 overridecolor[1] = 0.5;
5294 overridecolor[2] = 0.1;
5296 if (!strcmp(value, "light_torch_small_walltorch"))
5301 overridecolor[0] = 1;
5302 overridecolor[1] = 0.5;
5303 overridecolor[2] = 0.1;
5307 else if (!strcmp("style", key))
5308 style = atoi(value);
5309 else if (!strcmp("skin", key))
5310 skin = (int)atof(value);
5311 else if (!strcmp("pflags", key))
5312 pflags = (int)atof(value);
5313 //else if (!strcmp("effects", key))
5314 // effects = (int)atof(value);
5315 else if (cl.worldmodel->type == mod_brushq3)
5317 if (!strcmp("scale", key))
5318 lightscale = atof(value);
5319 if (!strcmp("fade", key))
5320 fadescale = atof(value);
5325 if (lightscale <= 0)
5329 if (color[0] == color[1] && color[0] == color[2])
5331 color[0] *= overridecolor[0];
5332 color[1] *= overridecolor[1];
5333 color[2] *= overridecolor[2];
5335 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5336 color[0] = color[0] * light[0];
5337 color[1] = color[1] * light[1];
5338 color[2] = color[2] * light[2];
5341 case LIGHTTYPE_MINUSX:
5343 case LIGHTTYPE_RECIPX:
5345 VectorScale(color, (1.0f / 16.0f), color);
5347 case LIGHTTYPE_RECIPXX:
5349 VectorScale(color, (1.0f / 16.0f), color);
5352 case LIGHTTYPE_NONE:
5356 case LIGHTTYPE_MINUSXX:
5359 VectorAdd(origin, originhack, origin);
5361 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);
5364 Mem_Free(entfiledata);
5368 void R_Shadow_SetCursorLocationForView(void)
5371 vec3_t dest, endpos;
5373 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5374 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
5375 if (trace.fraction < 1)
5377 dist = trace.fraction * r_editlights_cursordistance.value;
5378 push = r_editlights_cursorpushback.value;
5382 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5383 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5387 VectorClear( endpos );
5389 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5390 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5391 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5394 void R_Shadow_UpdateWorldLightSelection(void)
5396 if (r_editlights.integer)
5398 R_Shadow_SetCursorLocationForView();
5399 R_Shadow_SelectLightInView();
5402 R_Shadow_SelectLight(NULL);
5405 void R_Shadow_EditLights_Clear_f(void)
5407 R_Shadow_ClearWorldLights();
5410 void R_Shadow_EditLights_Reload_f(void)
5414 strlcpy(r_shadow_mapname, cl.worldname, sizeof(r_shadow_mapname));
5415 R_Shadow_ClearWorldLights();
5416 R_Shadow_LoadWorldLights();
5417 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5419 R_Shadow_LoadLightsFile();
5420 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5421 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5425 void R_Shadow_EditLights_Save_f(void)
5429 R_Shadow_SaveWorldLights();
5432 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
5434 R_Shadow_ClearWorldLights();
5435 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5438 void R_Shadow_EditLights_ImportLightsFile_f(void)
5440 R_Shadow_ClearWorldLights();
5441 R_Shadow_LoadLightsFile();
5444 void R_Shadow_EditLights_Spawn_f(void)
5447 if (!r_editlights.integer)
5449 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5452 if (Cmd_Argc() != 1)
5454 Con_Print("r_editlights_spawn does not take parameters\n");
5457 color[0] = color[1] = color[2] = 1;
5458 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5461 void R_Shadow_EditLights_Edit_f(void)
5463 vec3_t origin, angles, color;
5464 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5465 int style, shadows, flags, normalmode, realtimemode;
5466 char cubemapname[MAX_INPUTLINE];
5467 if (!r_editlights.integer)
5469 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5472 if (!r_shadow_selectedlight)
5474 Con_Print("No selected light.\n");
5477 VectorCopy(r_shadow_selectedlight->origin, origin);
5478 VectorCopy(r_shadow_selectedlight->angles, angles);
5479 VectorCopy(r_shadow_selectedlight->color, color);
5480 radius = r_shadow_selectedlight->radius;
5481 style = r_shadow_selectedlight->style;
5482 if (r_shadow_selectedlight->cubemapname)
5483 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5486 shadows = r_shadow_selectedlight->shadow;
5487 corona = r_shadow_selectedlight->corona;
5488 coronasizescale = r_shadow_selectedlight->coronasizescale;
5489 ambientscale = r_shadow_selectedlight->ambientscale;
5490 diffusescale = r_shadow_selectedlight->diffusescale;
5491 specularscale = r_shadow_selectedlight->specularscale;
5492 flags = r_shadow_selectedlight->flags;
5493 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5494 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5495 if (!strcmp(Cmd_Argv(1), "origin"))
5497 if (Cmd_Argc() != 5)
5499 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5502 origin[0] = atof(Cmd_Argv(2));
5503 origin[1] = atof(Cmd_Argv(3));
5504 origin[2] = atof(Cmd_Argv(4));
5506 else if (!strcmp(Cmd_Argv(1), "originx"))
5508 if (Cmd_Argc() != 3)
5510 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5513 origin[0] = atof(Cmd_Argv(2));
5515 else if (!strcmp(Cmd_Argv(1), "originy"))
5517 if (Cmd_Argc() != 3)
5519 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5522 origin[1] = atof(Cmd_Argv(2));
5524 else if (!strcmp(Cmd_Argv(1), "originz"))
5526 if (Cmd_Argc() != 3)
5528 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5531 origin[2] = atof(Cmd_Argv(2));
5533 else if (!strcmp(Cmd_Argv(1), "move"))
5535 if (Cmd_Argc() != 5)
5537 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5540 origin[0] += atof(Cmd_Argv(2));
5541 origin[1] += atof(Cmd_Argv(3));
5542 origin[2] += atof(Cmd_Argv(4));
5544 else if (!strcmp(Cmd_Argv(1), "movex"))
5546 if (Cmd_Argc() != 3)
5548 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5551 origin[0] += atof(Cmd_Argv(2));
5553 else if (!strcmp(Cmd_Argv(1), "movey"))
5555 if (Cmd_Argc() != 3)
5557 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5560 origin[1] += atof(Cmd_Argv(2));
5562 else if (!strcmp(Cmd_Argv(1), "movez"))
5564 if (Cmd_Argc() != 3)
5566 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5569 origin[2] += atof(Cmd_Argv(2));
5571 else if (!strcmp(Cmd_Argv(1), "angles"))
5573 if (Cmd_Argc() != 5)
5575 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5578 angles[0] = atof(Cmd_Argv(2));
5579 angles[1] = atof(Cmd_Argv(3));
5580 angles[2] = atof(Cmd_Argv(4));
5582 else if (!strcmp(Cmd_Argv(1), "anglesx"))
5584 if (Cmd_Argc() != 3)
5586 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5589 angles[0] = atof(Cmd_Argv(2));
5591 else if (!strcmp(Cmd_Argv(1), "anglesy"))
5593 if (Cmd_Argc() != 3)
5595 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5598 angles[1] = atof(Cmd_Argv(2));
5600 else if (!strcmp(Cmd_Argv(1), "anglesz"))
5602 if (Cmd_Argc() != 3)
5604 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5607 angles[2] = atof(Cmd_Argv(2));
5609 else if (!strcmp(Cmd_Argv(1), "color"))
5611 if (Cmd_Argc() != 5)
5613 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
5616 color[0] = atof(Cmd_Argv(2));
5617 color[1] = atof(Cmd_Argv(3));
5618 color[2] = atof(Cmd_Argv(4));
5620 else if (!strcmp(Cmd_Argv(1), "radius"))
5622 if (Cmd_Argc() != 3)
5624 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5627 radius = atof(Cmd_Argv(2));
5629 else if (!strcmp(Cmd_Argv(1), "colorscale"))
5631 if (Cmd_Argc() == 3)
5633 double scale = atof(Cmd_Argv(2));
5640 if (Cmd_Argc() != 5)
5642 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
5645 color[0] *= atof(Cmd_Argv(2));
5646 color[1] *= atof(Cmd_Argv(3));
5647 color[2] *= atof(Cmd_Argv(4));
5650 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
5652 if (Cmd_Argc() != 3)
5654 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5657 radius *= atof(Cmd_Argv(2));
5659 else if (!strcmp(Cmd_Argv(1), "style"))
5661 if (Cmd_Argc() != 3)
5663 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5666 style = atoi(Cmd_Argv(2));
5668 else if (!strcmp(Cmd_Argv(1), "cubemap"))
5672 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5675 if (Cmd_Argc() == 3)
5676 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
5680 else if (!strcmp(Cmd_Argv(1), "shadows"))
5682 if (Cmd_Argc() != 3)
5684 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5687 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5689 else if (!strcmp(Cmd_Argv(1), "corona"))
5691 if (Cmd_Argc() != 3)
5693 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5696 corona = atof(Cmd_Argv(2));
5698 else if (!strcmp(Cmd_Argv(1), "coronasize"))
5700 if (Cmd_Argc() != 3)
5702 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5705 coronasizescale = atof(Cmd_Argv(2));
5707 else if (!strcmp(Cmd_Argv(1), "ambient"))
5709 if (Cmd_Argc() != 3)
5711 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5714 ambientscale = atof(Cmd_Argv(2));
5716 else if (!strcmp(Cmd_Argv(1), "diffuse"))
5718 if (Cmd_Argc() != 3)
5720 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5723 diffusescale = atof(Cmd_Argv(2));
5725 else if (!strcmp(Cmd_Argv(1), "specular"))
5727 if (Cmd_Argc() != 3)
5729 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5732 specularscale = atof(Cmd_Argv(2));
5734 else if (!strcmp(Cmd_Argv(1), "normalmode"))
5736 if (Cmd_Argc() != 3)
5738 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5741 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5743 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
5745 if (Cmd_Argc() != 3)
5747 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5750 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5754 Con_Print("usage: r_editlights_edit [property] [value]\n");
5755 Con_Print("Selected light's properties:\n");
5756 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5757 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5758 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5759 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
5760 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
5761 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
5762 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5763 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
5764 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
5765 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
5766 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
5767 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
5768 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5769 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5772 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5773 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5776 void R_Shadow_EditLights_EditAll_f(void)
5779 dlight_t *light, *oldselected;
5782 if (!r_editlights.integer)
5784 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5788 oldselected = r_shadow_selectedlight;
5789 // EditLights doesn't seem to have a "remove" command or something so:
5790 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5791 for (lightindex = 0;lightindex < range;lightindex++)
5793 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5796 R_Shadow_SelectLight(light);
5797 R_Shadow_EditLights_Edit_f();
5799 // return to old selected (to not mess editing once selection is locked)
5800 R_Shadow_SelectLight(oldselected);
5803 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
5805 int lightnumber, lightcount;
5806 size_t lightindex, range;
5810 if (!r_editlights.integer)
5812 x = vid_conwidth.value - 240;
5814 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
5817 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5818 for (lightindex = 0;lightindex < range;lightindex++)
5820 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5823 if (light == r_shadow_selectedlight)
5824 lightnumber = lightindex;
5827 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;
5828 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;
5830 if (r_shadow_selectedlight == NULL)
5832 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;
5833 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;
5834 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;
5835 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;
5836 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;
5837 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;
5838 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;
5839 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;
5840 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;
5841 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;
5842 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;
5843 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;
5844 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;
5845 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;
5846 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;
5849 void R_Shadow_EditLights_ToggleShadow_f(void)
5851 if (!r_editlights.integer)
5853 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5856 if (!r_shadow_selectedlight)
5858 Con_Print("No selected light.\n");
5861 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);
5864 void R_Shadow_EditLights_ToggleCorona_f(void)
5866 if (!r_editlights.integer)
5868 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5871 if (!r_shadow_selectedlight)
5873 Con_Print("No selected light.\n");
5876 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);
5879 void R_Shadow_EditLights_Remove_f(void)
5881 if (!r_editlights.integer)
5883 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
5886 if (!r_shadow_selectedlight)
5888 Con_Print("No selected light.\n");
5891 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
5892 r_shadow_selectedlight = NULL;
5895 void R_Shadow_EditLights_Help_f(void)
5898 "Documentation on r_editlights system:\n"
5900 "r_editlights : enable/disable editing mode\n"
5901 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
5902 "r_editlights_cursorpushback : push back cursor this far from surface\n"
5903 "r_editlights_cursorpushoff : push cursor off surface this far\n"
5904 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
5905 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
5907 "r_editlights_help : this help\n"
5908 "r_editlights_clear : remove all lights\n"
5909 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
5910 "r_editlights_lock : lock selection to current light, if already locked - unlock\n"
5911 "r_editlights_save : save to .rtlights file\n"
5912 "r_editlights_spawn : create a light with default settings\n"
5913 "r_editlights_edit command : edit selected light - more documentation below\n"
5914 "r_editlights_remove : remove selected light\n"
5915 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
5916 "r_editlights_importlightentitiesfrommap : reload light entities\n"
5917 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
5919 "origin x y z : set light location\n"
5920 "originx x: set x component of light location\n"
5921 "originy y: set y component of light location\n"
5922 "originz z: set z component of light location\n"
5923 "move x y z : adjust light location\n"
5924 "movex x: adjust x component of light location\n"
5925 "movey y: adjust y component of light location\n"
5926 "movez z: adjust z component of light location\n"
5927 "angles x y z : set light angles\n"
5928 "anglesx x: set x component of light angles\n"
5929 "anglesy y: set y component of light angles\n"
5930 "anglesz z: set z component of light angles\n"
5931 "color r g b : set color of light (can be brighter than 1 1 1)\n"
5932 "radius radius : set radius (size) of light\n"
5933 "colorscale grey : multiply color of light (1 does nothing)\n"
5934 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
5935 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
5936 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
5937 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
5938 "cubemap basename : set filter cubemap of light (not yet supported)\n"
5939 "shadows 1/0 : turn on/off shadows\n"
5940 "corona n : set corona intensity\n"
5941 "coronasize n : set corona size (0-1)\n"
5942 "ambient n : set ambient intensity (0-1)\n"
5943 "diffuse n : set diffuse intensity (0-1)\n"
5944 "specular n : set specular intensity (0-1)\n"
5945 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
5946 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
5947 "<nothing> : print light properties to console\n"
5951 void R_Shadow_EditLights_CopyInfo_f(void)
5953 if (!r_editlights.integer)
5955 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
5958 if (!r_shadow_selectedlight)
5960 Con_Print("No selected light.\n");
5963 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
5964 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
5965 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
5966 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
5967 if (r_shadow_selectedlight->cubemapname)
5968 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
5970 r_shadow_bufferlight.cubemapname[0] = 0;
5971 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
5972 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
5973 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
5974 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
5975 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
5976 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
5977 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
5980 void R_Shadow_EditLights_PasteInfo_f(void)
5982 if (!r_editlights.integer)
5984 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
5987 if (!r_shadow_selectedlight)
5989 Con_Print("No selected light.\n");
5992 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);
5995 void R_Shadow_EditLights_Lock_f(void)
5997 if (!r_editlights.integer)
5999 Con_Print("Cannot lock on light when not in editing mode. Set r_editlights to 1.\n");
6002 if (r_editlights_lockcursor)
6004 r_editlights_lockcursor = false;
6007 if (!r_shadow_selectedlight)
6009 Con_Print("No selected light to lock on.\n");
6012 r_editlights_lockcursor = true;
6015 void R_Shadow_EditLights_Init(void)
6017 Cvar_RegisterVariable(&r_editlights);
6018 Cvar_RegisterVariable(&r_editlights_cursordistance);
6019 Cvar_RegisterVariable(&r_editlights_cursorpushback);
6020 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
6021 Cvar_RegisterVariable(&r_editlights_cursorgrid);
6022 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
6023 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
6024 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
6025 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)");
6026 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
6027 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
6028 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
6029 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)");
6030 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
6031 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
6032 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
6033 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
6034 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
6035 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
6036 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)");
6037 Cmd_AddCommand("r_editlights_lock", R_Shadow_EditLights_Lock_f, "lock selection to current light, if already locked - unlock");
6043 =============================================================================
6047 =============================================================================
6050 void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, const int flags)
6052 int i, numlights, flag;
6053 float f, relativepoint[3], dist, dist2, lightradius2;
6057 VectorClear(diffusecolor);
6058 VectorClear(diffusenormal);
6060 if (flags & LP_LIGHTMAP)
6062 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
6064 ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_refdef.scene.ambient;
6065 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
6068 VectorSet(ambientcolor, 1, 1, 1);
6070 if (flags & LP_RTWORLD)
6072 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
6073 numlights = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
6074 for (i = 0; i < numlights; i++)
6076 dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
6079 light = &dlight->rtlight;
6080 if (!(light->flags & flag))
6083 lightradius2 = light->radius * light->radius;
6084 VectorSubtract(light->shadoworigin, p, relativepoint);
6085 dist2 = VectorLength2(relativepoint);
6086 if (dist2 >= lightradius2)
6088 dist = sqrt(dist2) / light->radius;
6089 f = dist < 1 ? (r_shadow_lightintensityscale.value * ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist))) : 0;
6092 // todo: add to both ambient and diffuse
6093 if (!light->shadow || CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
6094 VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);
6097 if (flags & LP_DYNLIGHT)
6100 for (i = 0;i < r_refdef.scene.numlights;i++)
6102 light = r_refdef.scene.lights[i];
6104 lightradius2 = light->radius * light->radius;
6105 VectorSubtract(light->shadoworigin, p, relativepoint);
6106 dist2 = VectorLength2(relativepoint);
6107 if (dist2 >= lightradius2)
6109 dist = sqrt(dist2) / light->radius;
6110 f = dist < 1 ? (r_shadow_lightintensityscale.value * ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist))) : 0;
6113 // todo: add to both ambient and diffuse
6114 if (!light->shadow || CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
6115 VectorMA(ambientcolor, f, light->color, ambientcolor);