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 GL_AlphaTest(false);
3248 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3249 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3250 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3251 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3254 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
3256 if (!r_refdef.scene.worldmodel->DrawLight)
3259 // set up properties for rendering light onto this entity
3260 RSurf_ActiveWorldEntity();
3261 GL_AlphaTest(false);
3262 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3263 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3264 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3265 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3267 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
3269 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3272 void R_Shadow_DrawEntityLight(entity_render_t *ent)
3274 dp_model_t *model = ent->model;
3275 if (!model->DrawLight)
3278 R_Shadow_SetupEntityLight(ent);
3280 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3282 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3285 void R_Shadow_PrepareLight(rtlight_t *rtlight)
3289 int numleafs, numsurfaces;
3290 int *leaflist, *surfacelist;
3291 unsigned char *leafpvs;
3292 unsigned char *shadowtrispvs;
3293 unsigned char *lighttrispvs;
3294 //unsigned char *surfacesides;
3295 int numlightentities;
3296 int numlightentities_noselfshadow;
3297 int numshadowentities;
3298 int numshadowentities_noselfshadow;
3299 static entity_render_t *lightentities[MAX_EDICTS];
3300 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3301 static entity_render_t *shadowentities[MAX_EDICTS];
3302 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3305 rtlight->draw = false;
3307 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3308 // skip lights that are basically invisible (color 0 0 0)
3309 nolight = VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f);
3311 // loading is done before visibility checks because loading should happen
3312 // all at once at the start of a level, not when it stalls gameplay.
3313 // (especially important to benchmarks)
3315 if (rtlight->isstatic && !nolight && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
3317 if (rtlight->compiled)
3318 R_RTLight_Uncompile(rtlight);
3319 R_RTLight_Compile(rtlight);
3323 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
3325 // look up the light style value at this time
3326 f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3327 VectorScale(rtlight->color, f, rtlight->currentcolor);
3329 if (rtlight->selected)
3331 f = 2 + sin(realtime * M_PI * 4.0);
3332 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3336 // if lightstyle is currently off, don't draw the light
3337 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3340 // skip processing on corona-only lights
3344 // if the light box is offscreen, skip it
3345 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3348 VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
3349 VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
3351 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3353 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3355 // compiled light, world available and can receive realtime lighting
3356 // retrieve leaf information
3357 numleafs = rtlight->static_numleafs;
3358 leaflist = rtlight->static_leaflist;
3359 leafpvs = rtlight->static_leafpvs;
3360 numsurfaces = rtlight->static_numsurfaces;
3361 surfacelist = rtlight->static_surfacelist;
3362 //surfacesides = NULL;
3363 shadowtrispvs = rtlight->static_shadowtrispvs;
3364 lighttrispvs = rtlight->static_lighttrispvs;
3366 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3368 // dynamic light, world available and can receive realtime lighting
3369 // calculate lit surfaces and leafs
3370 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);
3371 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3372 leaflist = r_shadow_buffer_leaflist;
3373 leafpvs = r_shadow_buffer_leafpvs;
3374 surfacelist = r_shadow_buffer_surfacelist;
3375 //surfacesides = r_shadow_buffer_surfacesides;
3376 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3377 lighttrispvs = r_shadow_buffer_lighttrispvs;
3378 // if the reduced leaf bounds are offscreen, skip it
3379 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3390 //surfacesides = NULL;
3391 shadowtrispvs = NULL;
3392 lighttrispvs = NULL;
3394 // check if light is illuminating any visible leafs
3397 for (i = 0;i < numleafs;i++)
3398 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3404 // make a list of lit entities and shadow casting entities
3405 numlightentities = 0;
3406 numlightentities_noselfshadow = 0;
3407 numshadowentities = 0;
3408 numshadowentities_noselfshadow = 0;
3410 // add dynamic entities that are lit by the light
3411 for (i = 0;i < r_refdef.scene.numentities;i++)
3414 entity_render_t *ent = r_refdef.scene.entities[i];
3416 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3418 // skip the object entirely if it is not within the valid
3419 // shadow-casting region (which includes the lit region)
3420 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
3422 if (!(model = ent->model))
3424 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
3426 // this entity wants to receive light, is visible, and is
3427 // inside the light box
3428 // TODO: check if the surfaces in the model can receive light
3429 // so now check if it's in a leaf seen by the light
3430 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))
3432 if (ent->flags & RENDER_NOSELFSHADOW)
3433 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
3435 lightentities[numlightentities++] = ent;
3436 // since it is lit, it probably also casts a shadow...
3437 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3438 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3439 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3441 // note: exterior models without the RENDER_NOSELFSHADOW
3442 // flag still create a RENDER_NOSELFSHADOW shadow but
3443 // are lit normally, this means that they are
3444 // self-shadowing but do not shadow other
3445 // RENDER_NOSELFSHADOW entities such as the gun
3446 // (very weird, but keeps the player shadow off the gun)
3447 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3448 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3450 shadowentities[numshadowentities++] = ent;
3453 else if (ent->flags & RENDER_SHADOW)
3455 // this entity is not receiving light, but may still need to
3457 // TODO: check if the surfaces in the model can cast shadow
3458 // now check if it is in a leaf seen by the light
3459 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))
3461 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3462 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3463 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3465 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3466 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3468 shadowentities[numshadowentities++] = ent;
3473 // return if there's nothing at all to light
3474 if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
3477 // count this light in the r_speeds
3478 r_refdef.stats.lights++;
3480 // flag it as worth drawing later
3481 rtlight->draw = true;
3483 // cache all the animated entities that cast a shadow but are not visible
3484 for (i = 0;i < numshadowentities;i++)
3485 if (!shadowentities[i]->animcache_vertex3f)
3486 R_AnimCache_GetEntity(shadowentities[i], false, false);
3487 for (i = 0;i < numshadowentities_noselfshadow;i++)
3488 if (!shadowentities_noselfshadow[i]->animcache_vertex3f)
3489 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
3491 // allocate some temporary memory for rendering this light later in the frame
3492 // reusable buffers need to be copied, static data can be used as-is
3493 rtlight->cached_numlightentities = numlightentities;
3494 rtlight->cached_numlightentities_noselfshadow = numlightentities_noselfshadow;
3495 rtlight->cached_numshadowentities = numshadowentities;
3496 rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
3497 rtlight->cached_numsurfaces = numsurfaces;
3498 rtlight->cached_lightentities = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
3499 rtlight->cached_lightentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
3500 rtlight->cached_shadowentities = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
3501 rtlight->cached_shadowentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
3502 if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
3504 int numshadowtrispvsbytes = (((r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles) + 7) >> 3);
3505 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
3506 rtlight->cached_shadowtrispvs = (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
3507 rtlight->cached_lighttrispvs = (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
3508 rtlight->cached_surfacelist = (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
3512 // compiled light data
3513 rtlight->cached_shadowtrispvs = shadowtrispvs;
3514 rtlight->cached_lighttrispvs = lighttrispvs;
3515 rtlight->cached_surfacelist = surfacelist;
3519 void R_Shadow_DrawLight(rtlight_t *rtlight)
3523 unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
3524 int numlightentities;
3525 int numlightentities_noselfshadow;
3526 int numshadowentities;
3527 int numshadowentities_noselfshadow;
3528 entity_render_t **lightentities;
3529 entity_render_t **lightentities_noselfshadow;
3530 entity_render_t **shadowentities;
3531 entity_render_t **shadowentities_noselfshadow;
3533 static unsigned char entitysides[MAX_EDICTS];
3534 static unsigned char entitysides_noselfshadow[MAX_EDICTS];
3535 vec3_t nearestpoint;
3537 qboolean castshadows;
3540 // check if we cached this light this frame (meaning it is worth drawing)
3544 numlightentities = rtlight->cached_numlightentities;
3545 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
3546 numshadowentities = rtlight->cached_numshadowentities;
3547 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
3548 numsurfaces = rtlight->cached_numsurfaces;
3549 lightentities = rtlight->cached_lightentities;
3550 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
3551 shadowentities = rtlight->cached_shadowentities;
3552 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
3553 shadowtrispvs = rtlight->cached_shadowtrispvs;
3554 lighttrispvs = rtlight->cached_lighttrispvs;
3555 surfacelist = rtlight->cached_surfacelist;
3557 // set up a scissor rectangle for this light
3558 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3561 // don't let sound skip if going slow
3562 if (r_refdef.scene.extraupdate)
3565 // make this the active rtlight for rendering purposes
3566 R_Shadow_RenderMode_ActiveLight(rtlight);
3568 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
3570 // optionally draw visible shape of the shadow volumes
3571 // for performance analysis by level designers
3572 R_Shadow_RenderMode_VisibleShadowVolumes();
3574 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
3575 for (i = 0;i < numshadowentities;i++)
3576 R_Shadow_DrawEntityShadow(shadowentities[i]);
3577 for (i = 0;i < numshadowentities_noselfshadow;i++)
3578 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3579 R_Shadow_RenderMode_VisibleLighting(false, false);
3582 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
3584 // optionally draw the illuminated areas
3585 // for performance analysis by level designers
3586 R_Shadow_RenderMode_VisibleLighting(false, false);
3588 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3589 for (i = 0;i < numlightentities;i++)
3590 R_Shadow_DrawEntityLight(lightentities[i]);
3591 for (i = 0;i < numlightentities_noselfshadow;i++)
3592 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3595 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
3597 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
3598 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
3599 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
3600 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
3602 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance/rtlight->radius));
3603 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
3604 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
3606 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
3612 int receivermask = 0;
3613 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
3614 Matrix4x4_Abs(&radiustolight);
3616 r_shadow_shadowmaplod = 0;
3617 for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
3618 if ((r_shadow_shadowmapmaxsize >> i) > lodlinear)
3619 r_shadow_shadowmaplod = i;
3621 size = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
3623 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
3625 surfacesides = NULL;
3628 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3630 castermask = rtlight->static_shadowmap_casters;
3631 receivermask = rtlight->static_shadowmap_receivers;
3635 surfacesides = r_shadow_buffer_surfacesides;
3636 for(i = 0;i < numsurfaces;i++)
3638 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
3639 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3640 castermask |= surfacesides[i];
3641 receivermask |= surfacesides[i];
3645 if (receivermask < 0x3F)
3647 for (i = 0;i < numlightentities;i++)
3648 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3649 if (receivermask < 0x3F)
3650 for(i = 0; i < numlightentities_noselfshadow;i++)
3651 receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3654 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
3658 for (i = 0;i < numshadowentities;i++)
3659 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3660 for (i = 0;i < numshadowentities_noselfshadow;i++)
3661 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3664 //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
3666 // render shadow casters into 6 sided depth texture
3667 for (side = 0;side < 6;side++) if (receivermask & (1 << side))
3669 R_Shadow_RenderMode_ShadowMap(side, receivermask, size);
3670 if (! (castermask & (1 << side))) continue;
3672 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
3673 for (i = 0;i < numshadowentities;i++) if (entitysides[i] & (1 << side))
3674 R_Shadow_DrawEntityShadow(shadowentities[i]);
3677 if (numlightentities_noselfshadow)
3679 // render lighting using the depth texture as shadowmap
3680 // draw lighting in the unmasked areas
3681 R_Shadow_RenderMode_Lighting(false, false, true);
3682 for (i = 0;i < numlightentities_noselfshadow;i++)
3683 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3686 // render shadow casters into 6 sided depth texture
3687 if (numshadowentities_noselfshadow)
3689 for (side = 0;side < 6;side++) if ((receivermask & castermask) & (1 << side))
3691 R_Shadow_RenderMode_ShadowMap(side, 0, size);
3692 for (i = 0;i < numshadowentities_noselfshadow;i++) if (entitysides_noselfshadow[i] & (1 << side))
3693 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3697 // render lighting using the depth texture as shadowmap
3698 // draw lighting in the unmasked areas
3699 R_Shadow_RenderMode_Lighting(false, false, true);
3700 // draw lighting in the unmasked areas
3702 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3703 for (i = 0;i < numlightentities;i++)
3704 R_Shadow_DrawEntityLight(lightentities[i]);
3706 else if (castshadows && vid.stencil)
3708 // draw stencil shadow volumes to mask off pixels that are in shadow
3709 // so that they won't receive lighting
3710 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
3711 R_Shadow_ClearStencil();
3714 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
3715 for (i = 0;i < numshadowentities;i++)
3716 R_Shadow_DrawEntityShadow(shadowentities[i]);
3718 // draw lighting in the unmasked areas
3719 R_Shadow_RenderMode_Lighting(true, false, false);
3720 for (i = 0;i < numlightentities_noselfshadow;i++)
3721 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3723 for (i = 0;i < numshadowentities_noselfshadow;i++)
3724 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3726 // draw lighting in the unmasked areas
3727 R_Shadow_RenderMode_Lighting(true, false, false);
3729 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3730 for (i = 0;i < numlightentities;i++)
3731 R_Shadow_DrawEntityLight(lightentities[i]);
3735 // draw lighting in the unmasked areas
3736 R_Shadow_RenderMode_Lighting(false, false, false);
3738 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3739 for (i = 0;i < numlightentities;i++)
3740 R_Shadow_DrawEntityLight(lightentities[i]);
3741 for (i = 0;i < numlightentities_noselfshadow;i++)
3742 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3745 if (r_shadow_usingdeferredprepass)
3747 // when rendering deferred lighting, we simply rasterize the box
3748 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
3749 R_Shadow_RenderMode_DrawDeferredLight(false, true);
3750 else if (castshadows && vid.stencil)
3751 R_Shadow_RenderMode_DrawDeferredLight(true, false);
3753 R_Shadow_RenderMode_DrawDeferredLight(false, false);
3757 static void R_Shadow_FreeDeferred(void)
3759 R_Mesh_DestroyFramebufferObject(r_shadow_prepassgeometryfbo);
3760 r_shadow_prepassgeometryfbo = 0;
3762 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingfbo);
3763 r_shadow_prepasslightingfbo = 0;
3765 if (r_shadow_prepassgeometrydepthtexture)
3766 R_FreeTexture(r_shadow_prepassgeometrydepthtexture);
3767 r_shadow_prepassgeometrydepthtexture = NULL;
3769 if (r_shadow_prepassgeometrydepthcolortexture)
3770 R_FreeTexture(r_shadow_prepassgeometrydepthcolortexture);
3771 r_shadow_prepassgeometrydepthcolortexture = NULL;
3773 if (r_shadow_prepassgeometrynormalmaptexture)
3774 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
3775 r_shadow_prepassgeometrynormalmaptexture = NULL;
3777 if (r_shadow_prepasslightingdiffusetexture)
3778 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
3779 r_shadow_prepasslightingdiffusetexture = NULL;
3781 if (r_shadow_prepasslightingspeculartexture)
3782 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
3783 r_shadow_prepasslightingspeculartexture = NULL;
3786 void R_Shadow_DrawPrepass(void)
3794 entity_render_t *ent;
3795 float clearcolor[4];
3797 GL_AlphaTest(false);
3798 R_Mesh_ResetTextureState();
3800 GL_ColorMask(1,1,1,1);
3801 GL_BlendFunc(GL_ONE, GL_ZERO);
3804 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, r_shadow_prepassgeometrydepthcolortexture, NULL, NULL);
3805 Vector4Set(clearcolor, 0.5f,0.5f,0.5f,1.0f);
3806 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
3807 if (r_timereport_active)
3808 R_TimeReport("prepasscleargeom");
3810 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
3811 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
3812 if (r_timereport_active)
3813 R_TimeReport("prepassworld");
3815 for (i = 0;i < r_refdef.scene.numentities;i++)
3817 if (!r_refdef.viewcache.entityvisible[i])
3819 ent = r_refdef.scene.entities[i];
3820 if (ent->model && ent->model->DrawPrepass != NULL)
3821 ent->model->DrawPrepass(ent);
3824 if (r_timereport_active)
3825 R_TimeReport("prepassmodels");
3827 GL_DepthMask(false);
3828 GL_ColorMask(1,1,1,1);
3831 R_Mesh_SetRenderTargets(r_shadow_prepasslightingfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
3832 Vector4Set(clearcolor, 0, 0, 0, 0);
3833 GL_Clear(GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
3834 if (r_timereport_active)
3835 R_TimeReport("prepassclearlit");
3837 R_Shadow_RenderMode_Begin();
3839 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3840 if (r_shadow_debuglight.integer >= 0)
3842 lightindex = r_shadow_debuglight.integer;
3843 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3844 if (light && (light->flags & flag) && light->rtlight.draw)
3845 R_Shadow_DrawLight(&light->rtlight);
3849 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3850 for (lightindex = 0;lightindex < range;lightindex++)
3852 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3853 if (light && (light->flags & flag) && light->rtlight.draw)
3854 R_Shadow_DrawLight(&light->rtlight);
3857 if (r_refdef.scene.rtdlight)
3858 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
3859 if (r_refdef.scene.lights[lnum]->draw)
3860 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
3862 R_Mesh_ResetRenderTargets();
3864 R_Shadow_RenderMode_End();
3866 if (r_timereport_active)
3867 R_TimeReport("prepasslights");
3870 void R_Shadow_DrawLightSprites(void);
3871 void R_Shadow_PrepareLights(void)
3881 if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4) ||
3882 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
3883 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20) ||
3884 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
3885 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
3886 r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
3887 R_Shadow_FreeShadowMaps();
3889 r_shadow_usingshadowmaportho = false;
3891 switch (vid.renderpath)
3893 case RENDERPATH_GL20:
3894 case RENDERPATH_CGGL:
3895 case RENDERPATH_D3D9:
3896 case RENDERPATH_D3D10:
3897 case RENDERPATH_D3D11:
3898 case RENDERPATH_SOFT:
3899 case RENDERPATH_GLES2:
3900 if (!r_shadow_deferred.integer || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_STENCIL || !vid.support.ext_framebuffer_object || vid.maxdrawbuffers < 2)
3902 r_shadow_usingdeferredprepass = false;
3903 if (r_shadow_prepass_width)
3904 R_Shadow_FreeDeferred();
3905 r_shadow_prepass_width = r_shadow_prepass_height = 0;
3909 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
3911 R_Shadow_FreeDeferred();
3913 r_shadow_usingdeferredprepass = true;
3914 r_shadow_prepass_width = vid.width;
3915 r_shadow_prepass_height = vid.height;
3916 r_shadow_prepassgeometrydepthtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "prepassgeometrydepthmap", vid.width, vid.height, 24, false);
3917 switch (vid.renderpath)
3919 case RENDERPATH_D3D9:
3920 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);
3925 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);
3926 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);
3927 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);
3929 // set up the geometry pass fbo (depth + normalmap)
3930 r_shadow_prepassgeometryfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
3931 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, r_shadow_prepassgeometrydepthcolortexture, NULL, NULL);
3932 // render depth into one texture and normalmap into the other
3933 if (qglDrawBuffersARB)
3935 qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);CHECKGLERROR
3936 qglReadBuffer(GL_NONE);CHECKGLERROR
3937 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
3938 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
3940 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
3941 Cvar_SetValueQuick(&r_shadow_deferred, 0);
3942 r_shadow_usingdeferredprepass = false;
3946 // set up the lighting pass fbo (diffuse + specular)
3947 r_shadow_prepasslightingfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
3948 R_Mesh_SetRenderTargets(r_shadow_prepasslightingfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
3949 // render diffuse into one texture and specular into another,
3950 // with depth and normalmap bound as textures,
3951 // with depth bound as attachment as well
3952 if (qglDrawBuffersARB)
3954 qglDrawBuffersARB(2, r_shadow_prepasslightingdrawbuffers);CHECKGLERROR
3955 qglReadBuffer(GL_NONE);CHECKGLERROR
3956 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
3957 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
3959 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
3960 Cvar_SetValueQuick(&r_shadow_deferred, 0);
3961 r_shadow_usingdeferredprepass = false;
3966 case RENDERPATH_GL13:
3967 case RENDERPATH_GL11:
3968 r_shadow_usingdeferredprepass = false;
3972 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);
3974 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3975 if (r_shadow_debuglight.integer >= 0)
3977 lightindex = r_shadow_debuglight.integer;
3978 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3979 if (light && (light->flags & flag))
3980 R_Shadow_PrepareLight(&light->rtlight);
3984 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3985 for (lightindex = 0;lightindex < range;lightindex++)
3987 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3988 if (light && (light->flags & flag))
3989 R_Shadow_PrepareLight(&light->rtlight);
3992 if (r_refdef.scene.rtdlight)
3994 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
3995 R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
3997 else if(gl_flashblend.integer)
3999 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4001 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
4002 f = (rtlight->style >= 0 ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4003 VectorScale(rtlight->color, f, rtlight->currentcolor);
4007 if (r_editlights.integer)
4008 R_Shadow_DrawLightSprites();
4011 void R_Shadow_DrawLights(void)
4019 R_Shadow_RenderMode_Begin();
4021 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4022 if (r_shadow_debuglight.integer >= 0)
4024 lightindex = r_shadow_debuglight.integer;
4025 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4026 if (light && (light->flags & flag))
4027 R_Shadow_DrawLight(&light->rtlight);
4031 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4032 for (lightindex = 0;lightindex < range;lightindex++)
4034 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4035 if (light && (light->flags & flag))
4036 R_Shadow_DrawLight(&light->rtlight);
4039 if (r_refdef.scene.rtdlight)
4040 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4041 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4043 R_Shadow_RenderMode_End();
4046 extern const float r_screenvertex3f[12];
4047 extern void R_SetupView(qboolean allowwaterclippingplane);
4048 extern void R_ResetViewRendering3D(void);
4049 extern void R_ResetViewRendering2D(void);
4050 extern cvar_t r_shadows;
4051 extern cvar_t r_shadows_darken;
4052 extern cvar_t r_shadows_drawafterrtlighting;
4053 extern cvar_t r_shadows_castfrombmodels;
4054 extern cvar_t r_shadows_throwdistance;
4055 extern cvar_t r_shadows_throwdirection;
4056 extern cvar_t r_shadows_focus;
4057 extern cvar_t r_shadows_shadowmapscale;
4059 void R_Shadow_PrepareModelShadows(void)
4062 float scale, size, radius, dot1, dot2;
4063 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
4064 entity_render_t *ent;
4066 if (!r_refdef.scene.numentities)
4069 switch (r_shadow_shadowmode)
4071 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4072 if (r_shadows.integer >= 2)
4075 case R_SHADOW_SHADOWMODE_STENCIL:
4076 for (i = 0;i < r_refdef.scene.numentities;i++)
4078 ent = r_refdef.scene.entities[i];
4079 if (!ent->animcache_vertex3f && ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4080 R_AnimCache_GetEntity(ent, false, false);
4087 size = 2*r_shadow_shadowmapmaxsize;
4088 scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
4089 radius = 0.5f * size / scale;
4091 Math_atov(r_shadows_throwdirection.string, shadowdir);
4092 VectorNormalize(shadowdir);
4093 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4094 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4095 if (fabs(dot1) <= fabs(dot2))
4096 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4098 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4099 VectorNormalize(shadowforward);
4100 CrossProduct(shadowdir, shadowforward, shadowright);
4101 Math_atov(r_shadows_focus.string, shadowfocus);
4102 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4103 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4104 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4105 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4106 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4108 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4110 shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4111 shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4112 shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4113 shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4114 shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4115 shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4117 for (i = 0;i < r_refdef.scene.numentities;i++)
4119 ent = r_refdef.scene.entities[i];
4120 if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
4122 // cast shadows from anything of the map (submodels are optional)
4123 if (!ent->animcache_vertex3f && ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4124 R_AnimCache_GetEntity(ent, false, false);
4128 void R_DrawModelShadowMaps(void)
4131 float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
4132 entity_render_t *ent;
4133 vec3_t relativelightorigin;
4134 vec3_t relativelightdirection, relativeforward, relativeright;
4135 vec3_t relativeshadowmins, relativeshadowmaxs;
4136 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
4138 matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
4139 r_viewport_t viewport;
4141 float clearcolor[4];
4143 if (!r_refdef.scene.numentities)
4146 switch (r_shadow_shadowmode)
4148 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4154 R_ResetViewRendering3D();
4155 R_Shadow_RenderMode_Begin();
4156 R_Shadow_RenderMode_ActiveLight(NULL);
4158 switch (r_shadow_shadowmode)
4160 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4161 if (!r_shadow_shadowmap2dtexture)
4162 R_Shadow_MakeShadowMap(0, r_shadow_shadowmapmaxsize);
4163 fbo = r_shadow_fbo2d;
4164 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
4165 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
4166 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
4172 size = 2*r_shadow_shadowmapmaxsize;
4173 scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
4174 radius = 0.5f / scale;
4175 nearclip = -r_shadows_throwdistance.value;
4176 farclip = r_shadows_throwdistance.value;
4177 bias = r_shadow_shadowmapping_bias.value * r_shadow_shadowmapping_nearclip.value / (2 * r_shadows_throwdistance.value) * (1024.0f / size);
4179 r_shadow_shadowmap_parameters[0] = size;
4180 r_shadow_shadowmap_parameters[1] = size;
4181 r_shadow_shadowmap_parameters[2] = 1.0;
4182 r_shadow_shadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
4184 Math_atov(r_shadows_throwdirection.string, shadowdir);
4185 VectorNormalize(shadowdir);
4186 Math_atov(r_shadows_focus.string, shadowfocus);
4187 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4188 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4189 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4190 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4191 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4192 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4193 if (fabs(dot1) <= fabs(dot2))
4194 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4196 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4197 VectorNormalize(shadowforward);
4198 VectorM(scale, shadowforward, &m[0]);
4199 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4201 m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
4202 CrossProduct(shadowdir, shadowforward, shadowright);
4203 VectorM(scale, shadowright, &m[4]);
4204 m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
4205 VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
4206 m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
4207 Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
4208 Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
4209 R_Viewport_InitOrtho(&viewport, &cameramatrix, 0, 0, size, size, 0, 0, 1, 1, 0, -1, NULL);
4211 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4213 R_Mesh_SetRenderTargets(fbo, r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
4214 R_SetupShader_DepthOrShadow();
4215 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
4218 R_SetViewport(&viewport);
4219 GL_Scissor(viewport.x, viewport.y, min(viewport.width + r_shadow_shadowmapborder, 2*r_shadow_shadowmapmaxsize), viewport.height + r_shadow_shadowmapborder);
4220 Vector4Set(clearcolor, 1,1,1,1);
4221 // in D3D9 we have to render to a color texture shadowmap
4222 // in GL we render directly to a depth texture only
4223 if (r_shadow_shadowmap2dtexture)
4224 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4226 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4227 // render into a slightly restricted region so that the borders of the
4228 // shadowmap area fade away, rather than streaking across everything
4229 // outside the usable area
4230 GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
4234 R_Mesh_ResetRenderTargets();
4235 R_SetupShader_ShowDepth();
4236 GL_ColorMask(1,1,1,1);
4237 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4240 for (i = 0;i < r_refdef.scene.numentities;i++)
4242 ent = r_refdef.scene.entities[i];
4244 // cast shadows from anything of the map (submodels are optional)
4245 if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4247 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4248 Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
4249 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4250 Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
4251 Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
4252 relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4253 relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4254 relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4255 relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4256 relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4257 relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4258 RSurf_ActiveModelEntity(ent, false, false, false);
4259 ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
4260 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4267 unsigned char *rawpixels = Z_Malloc(viewport.width*viewport.height*4);
4269 qglReadPixels(viewport.x, viewport.y, viewport.width, viewport.height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, rawpixels);
4271 Image_WriteTGABGRA("r_shadows_2.tga", viewport.width, viewport.height, rawpixels);
4272 Cvar_SetValueQuick(&r_test, 0);
4277 R_Shadow_RenderMode_End();
4279 Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
4280 Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
4281 Matrix4x4_CreateScale3(&scalematrix, size, -size, 1);
4282 Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
4283 Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
4284 Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
4286 switch (vid.renderpath)
4288 case RENDERPATH_GL11:
4289 case RENDERPATH_GL13:
4290 case RENDERPATH_GL20:
4291 case RENDERPATH_CGGL:
4292 case RENDERPATH_SOFT:
4293 case RENDERPATH_GLES2:
4295 case RENDERPATH_D3D9:
4296 case RENDERPATH_D3D10:
4297 case RENDERPATH_D3D11:
4298 #ifdef OPENGL_ORIENTATION
4299 r_shadow_shadowmapmatrix.m[0][0] *= -1.0f;
4300 r_shadow_shadowmapmatrix.m[0][1] *= -1.0f;
4301 r_shadow_shadowmapmatrix.m[0][2] *= -1.0f;
4302 r_shadow_shadowmapmatrix.m[0][3] *= -1.0f;
4304 r_shadow_shadowmapmatrix.m[0][0] *= -1.0f;
4305 r_shadow_shadowmapmatrix.m[1][0] *= -1.0f;
4306 r_shadow_shadowmapmatrix.m[2][0] *= -1.0f;
4307 r_shadow_shadowmapmatrix.m[3][0] *= -1.0f;
4312 r_shadow_usingshadowmaportho = true;
4313 switch (r_shadow_shadowmode)
4315 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4316 r_shadow_usingshadowmap2d = true;
4323 void R_DrawModelShadows(void)
4326 float relativethrowdistance;
4327 entity_render_t *ent;
4328 vec3_t relativelightorigin;
4329 vec3_t relativelightdirection;
4330 vec3_t relativeshadowmins, relativeshadowmaxs;
4331 vec3_t tmp, shadowdir;
4333 if (!r_refdef.scene.numentities || !vid.stencil || (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL && r_shadows.integer != 1))
4336 R_ResetViewRendering3D();
4337 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4338 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4339 R_Shadow_RenderMode_Begin();
4340 R_Shadow_RenderMode_ActiveLight(NULL);
4341 r_shadow_lightscissor[0] = r_refdef.view.x;
4342 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
4343 r_shadow_lightscissor[2] = r_refdef.view.width;
4344 r_shadow_lightscissor[3] = r_refdef.view.height;
4345 R_Shadow_RenderMode_StencilShadowVolumes(false);
4348 if (r_shadows.integer == 2)
4350 Math_atov(r_shadows_throwdirection.string, shadowdir);
4351 VectorNormalize(shadowdir);
4354 R_Shadow_ClearStencil();
4356 for (i = 0;i < r_refdef.scene.numentities;i++)
4358 ent = r_refdef.scene.entities[i];
4360 // cast shadows from anything of the map (submodels are optional)
4361 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4363 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4364 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
4365 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
4366 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
4367 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4370 if(ent->entitynumber != 0)
4372 if(ent->entitynumber >= MAX_EDICTS) // csqc entity
4374 // FIXME handle this
4375 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4379 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
4380 int entnum, entnum2, recursion;
4381 entnum = entnum2 = ent->entitynumber;
4382 for(recursion = 32; recursion > 0; --recursion)
4384 entnum2 = cl.entities[entnum].state_current.tagentity;
4385 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
4390 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
4392 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
4393 // transform into modelspace of OUR entity
4394 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
4395 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
4398 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4402 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4405 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
4406 RSurf_ActiveModelEntity(ent, false, false, false);
4407 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4408 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4412 // not really the right mode, but this will disable any silly stencil features
4413 R_Shadow_RenderMode_End();
4415 // set up ortho view for rendering this pass
4416 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4417 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4418 //GL_ScissorTest(true);
4419 //R_EntityMatrix(&identitymatrix);
4420 //R_Mesh_ResetTextureState();
4421 R_ResetViewRendering2D();
4423 // set up a darkening blend on shadowed areas
4424 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4425 //GL_DepthRange(0, 1);
4426 //GL_DepthTest(false);
4427 //GL_DepthMask(false);
4428 //GL_PolygonOffset(0, 0);CHECKGLERROR
4429 GL_Color(0, 0, 0, r_shadows_darken.value);
4430 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4431 //GL_DepthFunc(GL_ALWAYS);
4432 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_NOTEQUAL, 128, 255);
4434 // apply the blend to the shadowed areas
4435 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, NULL);
4436 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
4437 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4439 // restore the viewport
4440 R_SetViewport(&r_refdef.view.viewport);
4442 // restore other state to normal
4443 //R_Shadow_RenderMode_End();
4446 void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4449 vec3_t centerorigin;
4451 // if it's too close, skip it
4452 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
4454 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4457 if (usequery && r_numqueries + 2 <= r_maxqueries)
4459 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4460 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4461 // 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
4462 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4464 switch(vid.renderpath)
4466 case RENDERPATH_GL20:
4467 case RENDERPATH_GL13:
4468 case RENDERPATH_GL11:
4469 case RENDERPATH_CGGL:
4471 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use GL_DepthFunc instead
4472 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
4473 GL_DepthFunc(GL_ALWAYS);
4474 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4475 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL);
4476 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4477 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4478 GL_DepthFunc(GL_LEQUAL);
4479 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
4480 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4481 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL);
4482 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4483 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4486 case RENDERPATH_D3D9:
4487 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4489 case RENDERPATH_D3D10:
4490 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4492 case RENDERPATH_D3D11:
4493 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4495 case RENDERPATH_SOFT:
4496 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4498 case RENDERPATH_GLES2:
4499 //Con_DPrintf("FIXME GLES2 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4503 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4506 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
4508 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4511 GLint allpixels = 0, visiblepixels = 0;
4512 // now we have to check the query result
4513 if (rtlight->corona_queryindex_visiblepixels)
4515 switch(vid.renderpath)
4517 case RENDERPATH_GL20:
4518 case RENDERPATH_GL13:
4519 case RENDERPATH_GL11:
4520 case RENDERPATH_CGGL:
4522 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
4523 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
4526 case RENDERPATH_D3D9:
4527 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4529 case RENDERPATH_D3D10:
4530 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4532 case RENDERPATH_D3D11:
4533 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4535 case RENDERPATH_SOFT:
4536 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4538 case RENDERPATH_GLES2:
4539 //Con_DPrintf("FIXME GLES2 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4542 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
4543 if (visiblepixels < 1 || allpixels < 1)
4545 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
4546 cscale *= rtlight->corona_visibility;
4550 // FIXME: these traces should scan all render entities instead of cl.world
4551 if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
4554 VectorScale(rtlight->currentcolor, cscale, color);
4555 if (VectorLength(color) > (1.0f / 256.0f))
4558 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
4561 VectorNegate(color, color);
4562 switch(vid.renderpath)
4564 case RENDERPATH_GL11:
4565 case RENDERPATH_GL13:
4566 case RENDERPATH_GL20:
4567 case RENDERPATH_CGGL:
4568 case RENDERPATH_GLES2:
4569 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
4571 case RENDERPATH_D3D9:
4573 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_SUBTRACT);
4576 case RENDERPATH_D3D10:
4577 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4579 case RENDERPATH_D3D11:
4580 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4582 case RENDERPATH_SOFT:
4583 DPSOFTRAST_BlendSubtract(true);
4587 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4588 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);
4589 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4592 switch(vid.renderpath)
4594 case RENDERPATH_GL11:
4595 case RENDERPATH_GL13:
4596 case RENDERPATH_GL20:
4597 case RENDERPATH_CGGL:
4598 case RENDERPATH_GLES2:
4599 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
4601 case RENDERPATH_D3D9:
4603 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_ADD);
4606 case RENDERPATH_D3D10:
4607 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4609 case RENDERPATH_D3D11:
4610 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4612 case RENDERPATH_SOFT:
4613 DPSOFTRAST_BlendSubtract(false);
4620 void R_Shadow_DrawCoronas(void)
4623 qboolean usequery = false;
4628 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4630 if (r_waterstate.renderingscene)
4632 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4633 R_EntityMatrix(&identitymatrix);
4635 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4637 // check occlusion of coronas
4638 // use GL_ARB_occlusion_query if available
4639 // otherwise use raytraces
4641 switch (vid.renderpath)
4643 case RENDERPATH_GL11:
4644 case RENDERPATH_GL13:
4645 case RENDERPATH_GL20:
4646 case RENDERPATH_CGGL:
4647 usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
4650 GL_ColorMask(0,0,0,0);
4651 if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
4652 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
4655 r_maxqueries = (range + r_refdef.scene.numlights) * 4;
4656 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
4658 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
4661 RSurf_ActiveWorldEntity();
4662 GL_BlendFunc(GL_ONE, GL_ZERO);
4663 GL_CullFace(GL_NONE);
4664 GL_DepthMask(false);
4665 GL_DepthRange(0, 1);
4666 GL_PolygonOffset(0, 0);
4668 R_Mesh_ResetTextureState();
4669 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
4672 case RENDERPATH_D3D9:
4674 //Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4676 case RENDERPATH_D3D10:
4677 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4679 case RENDERPATH_D3D11:
4680 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4682 case RENDERPATH_SOFT:
4684 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4686 case RENDERPATH_GLES2:
4688 //Con_DPrintf("FIXME GLES2 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4691 for (lightindex = 0;lightindex < range;lightindex++)
4693 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4696 rtlight = &light->rtlight;
4697 rtlight->corona_visibility = 0;
4698 rtlight->corona_queryindex_visiblepixels = 0;
4699 rtlight->corona_queryindex_allpixels = 0;
4700 if (!(rtlight->flags & flag))
4702 if (rtlight->corona <= 0)
4704 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4706 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4708 for (i = 0;i < r_refdef.scene.numlights;i++)
4710 rtlight = r_refdef.scene.lights[i];
4711 rtlight->corona_visibility = 0;
4712 rtlight->corona_queryindex_visiblepixels = 0;
4713 rtlight->corona_queryindex_allpixels = 0;
4714 if (!(rtlight->flags & flag))
4716 if (rtlight->corona <= 0)
4718 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4721 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4723 // now draw the coronas using the query data for intensity info
4724 for (lightindex = 0;lightindex < range;lightindex++)
4726 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4729 rtlight = &light->rtlight;
4730 if (rtlight->corona_visibility <= 0)
4732 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4734 for (i = 0;i < r_refdef.scene.numlights;i++)
4736 rtlight = r_refdef.scene.lights[i];
4737 if (rtlight->corona_visibility <= 0)
4739 if (gl_flashblend.integer)
4740 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4742 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4748 dlight_t *R_Shadow_NewWorldLight(void)
4750 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4753 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)
4756 // validate parameters
4757 if (style < 0 || style >= MAX_LIGHTSTYLES)
4759 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
4765 // copy to light properties
4766 VectorCopy(origin, light->origin);
4767 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4768 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4769 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4771 light->color[0] = max(color[0], 0);
4772 light->color[1] = max(color[1], 0);
4773 light->color[2] = max(color[2], 0);
4775 light->color[0] = color[0];
4776 light->color[1] = color[1];
4777 light->color[2] = color[2];
4778 light->radius = max(radius, 0);
4779 light->style = style;
4780 light->shadow = shadowenable;
4781 light->corona = corona;
4782 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4783 light->coronasizescale = coronasizescale;
4784 light->ambientscale = ambientscale;
4785 light->diffusescale = diffusescale;
4786 light->specularscale = specularscale;
4787 light->flags = flags;
4789 // update renderable light data
4790 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4791 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);
4794 void R_Shadow_FreeWorldLight(dlight_t *light)
4796 if (r_shadow_selectedlight == light)
4797 r_shadow_selectedlight = NULL;
4798 R_RTLight_Uncompile(&light->rtlight);
4799 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4802 void R_Shadow_ClearWorldLights(void)
4806 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4807 for (lightindex = 0;lightindex < range;lightindex++)
4809 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4811 R_Shadow_FreeWorldLight(light);
4813 r_shadow_selectedlight = NULL;
4816 void R_Shadow_SelectLight(dlight_t *light)
4818 if (r_shadow_selectedlight)
4819 r_shadow_selectedlight->selected = false;
4820 r_shadow_selectedlight = light;
4821 if (r_shadow_selectedlight)
4822 r_shadow_selectedlight->selected = true;
4825 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4827 // this is never batched (there can be only one)
4829 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
4830 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4831 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4834 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4839 skinframe_t *skinframe;
4842 // this is never batched (due to the ent parameter changing every time)
4843 // so numsurfaces == 1 and surfacelist[0] == lightnumber
4844 const dlight_t *light = (dlight_t *)ent;
4847 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
4850 VectorScale(light->color, intensity, spritecolor);
4851 if (VectorLength(spritecolor) < 0.1732f)
4852 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
4853 if (VectorLength(spritecolor) > 1.0f)
4854 VectorNormalize(spritecolor);
4856 // draw light sprite
4857 if (light->cubemapname[0] && !light->shadow)
4858 skinframe = r_editlights_sprcubemapnoshadowlight;
4859 else if (light->cubemapname[0])
4860 skinframe = r_editlights_sprcubemaplight;
4861 else if (!light->shadow)
4862 skinframe = r_editlights_sprnoshadowlight;
4864 skinframe = r_editlights_sprlight;
4866 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);
4867 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4869 // draw selection sprite if light is selected
4870 if (light->selected)
4872 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4873 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4874 // VorteX todo: add normalmode/realtime mode light overlay sprites?
4878 void R_Shadow_DrawLightSprites(void)
4882 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4883 for (lightindex = 0;lightindex < range;lightindex++)
4885 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4887 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
4889 if (!r_editlights_lockcursor)
4890 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
4893 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
4898 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
4899 if (lightindex >= range)
4901 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4904 rtlight = &light->rtlight;
4905 //if (!(rtlight->flags & flag))
4907 VectorCopy(rtlight->shadoworigin, origin);
4908 *radius = rtlight->radius;
4909 VectorCopy(rtlight->color, color);
4913 void R_Shadow_SelectLightInView(void)
4915 float bestrating, rating, temp[3];
4919 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4923 if (r_editlights_lockcursor)
4925 for (lightindex = 0;lightindex < range;lightindex++)
4927 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4930 VectorSubtract(light->origin, r_refdef.view.origin, temp);
4931 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
4934 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
4935 if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1.0f)
4937 bestrating = rating;
4942 R_Shadow_SelectLight(best);
4945 void R_Shadow_LoadWorldLights(void)
4947 int n, a, style, shadow, flags;
4948 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
4949 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
4950 if (cl.worldmodel == NULL)
4952 Con_Print("No map loaded.\n");
4955 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
4956 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4966 for (;COM_Parse(t, true) && strcmp(
4967 if (COM_Parse(t, true))
4969 if (com_token[0] == '!')
4972 origin[0] = atof(com_token+1);
4975 origin[0] = atof(com_token);
4980 while (*s && *s != '\n' && *s != '\r')
4986 // check for modifier flags
4993 #if _MSC_VER >= 1400
4994 #define sscanf sscanf_s
4996 cubemapname[sizeof(cubemapname)-1] = 0;
4997 #if MAX_QPATH != 128
4998 #error update this code if MAX_QPATH changes
5000 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
5001 #if _MSC_VER >= 1400
5002 , sizeof(cubemapname)
5004 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
5007 flags = LIGHTFLAG_REALTIMEMODE;
5015 coronasizescale = 0.25f;
5017 VectorClear(angles);
5020 if (a < 9 || !strcmp(cubemapname, "\"\""))
5022 // remove quotes on cubemapname
5023 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
5026 namelen = strlen(cubemapname) - 2;
5027 memmove(cubemapname, cubemapname + 1, namelen);
5028 cubemapname[namelen] = '\0';
5032 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);
5035 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5043 Con_Printf("invalid rtlights file \"%s\"\n", name);
5044 Mem_Free(lightsstring);
5048 void R_Shadow_SaveWorldLights(void)
5052 size_t bufchars, bufmaxchars;
5054 char name[MAX_QPATH];
5055 char line[MAX_INPUTLINE];
5056 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
5057 // I hate lines which are 3 times my screen size :( --blub
5060 if (cl.worldmodel == NULL)
5062 Con_Print("No map loaded.\n");
5065 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
5066 bufchars = bufmaxchars = 0;
5068 for (lightindex = 0;lightindex < range;lightindex++)
5070 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5073 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
5074 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);
5075 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
5076 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]);
5078 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);
5079 if (bufchars + strlen(line) > bufmaxchars)
5081 bufmaxchars = bufchars + strlen(line) + 2048;
5083 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
5087 memcpy(buf, oldbuf, bufchars);
5093 memcpy(buf + bufchars, line, strlen(line));
5094 bufchars += strlen(line);
5098 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
5103 void R_Shadow_LoadLightsFile(void)
5106 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
5107 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
5108 if (cl.worldmodel == NULL)
5110 Con_Print("No map loaded.\n");
5113 dpsnprintf(name, sizeof(name), "%s.lights", cl.worldnamenoextension);
5114 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5122 while (*s && *s != '\n' && *s != '\r')
5128 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);
5132 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);
5135 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
5136 radius = bound(15, radius, 4096);
5137 VectorScale(color, (2.0f / (8388608.0f)), color);
5138 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5146 Con_Printf("invalid lights file \"%s\"\n", name);
5147 Mem_Free(lightsstring);
5151 // tyrlite/hmap2 light types in the delay field
5152 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
5154 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
5166 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
5167 char key[256], value[MAX_INPUTLINE];
5169 if (cl.worldmodel == NULL)
5171 Con_Print("No map loaded.\n");
5174 // try to load a .ent file first
5175 dpsnprintf(key, sizeof(key), "%s.ent", cl.worldnamenoextension);
5176 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
5177 // and if that is not found, fall back to the bsp file entity string
5179 data = cl.worldmodel->brush.entities;
5182 for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
5184 type = LIGHTTYPE_MINUSX;
5185 origin[0] = origin[1] = origin[2] = 0;
5186 originhack[0] = originhack[1] = originhack[2] = 0;
5187 angles[0] = angles[1] = angles[2] = 0;
5188 color[0] = color[1] = color[2] = 1;
5189 light[0] = light[1] = light[2] = 1;light[3] = 300;
5190 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
5200 if (!COM_ParseToken_Simple(&data, false, false))
5202 if (com_token[0] == '}')
5203 break; // end of entity
5204 if (com_token[0] == '_')
5205 strlcpy(key, com_token + 1, sizeof(key));
5207 strlcpy(key, com_token, sizeof(key));
5208 while (key[strlen(key)-1] == ' ') // remove trailing spaces
5209 key[strlen(key)-1] = 0;
5210 if (!COM_ParseToken_Simple(&data, false, false))
5212 strlcpy(value, com_token, sizeof(value));
5214 // now that we have the key pair worked out...
5215 if (!strcmp("light", key))
5217 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5221 light[0] = vec[0] * (1.0f / 256.0f);
5222 light[1] = vec[0] * (1.0f / 256.0f);
5223 light[2] = vec[0] * (1.0f / 256.0f);
5229 light[0] = vec[0] * (1.0f / 255.0f);
5230 light[1] = vec[1] * (1.0f / 255.0f);
5231 light[2] = vec[2] * (1.0f / 255.0f);
5235 else if (!strcmp("delay", key))
5237 else if (!strcmp("origin", key))
5238 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5239 else if (!strcmp("angle", key))
5240 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5241 else if (!strcmp("angles", key))
5242 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5243 else if (!strcmp("color", key))
5244 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5245 else if (!strcmp("wait", key))
5246 fadescale = atof(value);
5247 else if (!strcmp("classname", key))
5249 if (!strncmp(value, "light", 5))
5252 if (!strcmp(value, "light_fluoro"))
5257 overridecolor[0] = 1;
5258 overridecolor[1] = 1;
5259 overridecolor[2] = 1;
5261 if (!strcmp(value, "light_fluorospark"))
5266 overridecolor[0] = 1;
5267 overridecolor[1] = 1;
5268 overridecolor[2] = 1;
5270 if (!strcmp(value, "light_globe"))
5275 overridecolor[0] = 1;
5276 overridecolor[1] = 0.8;
5277 overridecolor[2] = 0.4;
5279 if (!strcmp(value, "light_flame_large_yellow"))
5284 overridecolor[0] = 1;
5285 overridecolor[1] = 0.5;
5286 overridecolor[2] = 0.1;
5288 if (!strcmp(value, "light_flame_small_yellow"))
5293 overridecolor[0] = 1;
5294 overridecolor[1] = 0.5;
5295 overridecolor[2] = 0.1;
5297 if (!strcmp(value, "light_torch_small_white"))
5302 overridecolor[0] = 1;
5303 overridecolor[1] = 0.5;
5304 overridecolor[2] = 0.1;
5306 if (!strcmp(value, "light_torch_small_walltorch"))
5311 overridecolor[0] = 1;
5312 overridecolor[1] = 0.5;
5313 overridecolor[2] = 0.1;
5317 else if (!strcmp("style", key))
5318 style = atoi(value);
5319 else if (!strcmp("skin", key))
5320 skin = (int)atof(value);
5321 else if (!strcmp("pflags", key))
5322 pflags = (int)atof(value);
5323 //else if (!strcmp("effects", key))
5324 // effects = (int)atof(value);
5325 else if (cl.worldmodel->type == mod_brushq3)
5327 if (!strcmp("scale", key))
5328 lightscale = atof(value);
5329 if (!strcmp("fade", key))
5330 fadescale = atof(value);
5335 if (lightscale <= 0)
5339 if (color[0] == color[1] && color[0] == color[2])
5341 color[0] *= overridecolor[0];
5342 color[1] *= overridecolor[1];
5343 color[2] *= overridecolor[2];
5345 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5346 color[0] = color[0] * light[0];
5347 color[1] = color[1] * light[1];
5348 color[2] = color[2] * light[2];
5351 case LIGHTTYPE_MINUSX:
5353 case LIGHTTYPE_RECIPX:
5355 VectorScale(color, (1.0f / 16.0f), color);
5357 case LIGHTTYPE_RECIPXX:
5359 VectorScale(color, (1.0f / 16.0f), color);
5362 case LIGHTTYPE_NONE:
5366 case LIGHTTYPE_MINUSXX:
5369 VectorAdd(origin, originhack, origin);
5371 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);
5374 Mem_Free(entfiledata);
5378 void R_Shadow_SetCursorLocationForView(void)
5381 vec3_t dest, endpos;
5383 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5384 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
5385 if (trace.fraction < 1)
5387 dist = trace.fraction * r_editlights_cursordistance.value;
5388 push = r_editlights_cursorpushback.value;
5392 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5393 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5397 VectorClear( endpos );
5399 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5400 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5401 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5404 void R_Shadow_UpdateWorldLightSelection(void)
5406 if (r_editlights.integer)
5408 R_Shadow_SetCursorLocationForView();
5409 R_Shadow_SelectLightInView();
5412 R_Shadow_SelectLight(NULL);
5415 void R_Shadow_EditLights_Clear_f(void)
5417 R_Shadow_ClearWorldLights();
5420 void R_Shadow_EditLights_Reload_f(void)
5424 strlcpy(r_shadow_mapname, cl.worldname, sizeof(r_shadow_mapname));
5425 R_Shadow_ClearWorldLights();
5426 R_Shadow_LoadWorldLights();
5427 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5429 R_Shadow_LoadLightsFile();
5430 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5431 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5435 void R_Shadow_EditLights_Save_f(void)
5439 R_Shadow_SaveWorldLights();
5442 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
5444 R_Shadow_ClearWorldLights();
5445 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5448 void R_Shadow_EditLights_ImportLightsFile_f(void)
5450 R_Shadow_ClearWorldLights();
5451 R_Shadow_LoadLightsFile();
5454 void R_Shadow_EditLights_Spawn_f(void)
5457 if (!r_editlights.integer)
5459 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5462 if (Cmd_Argc() != 1)
5464 Con_Print("r_editlights_spawn does not take parameters\n");
5467 color[0] = color[1] = color[2] = 1;
5468 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5471 void R_Shadow_EditLights_Edit_f(void)
5473 vec3_t origin, angles, color;
5474 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5475 int style, shadows, flags, normalmode, realtimemode;
5476 char cubemapname[MAX_INPUTLINE];
5477 if (!r_editlights.integer)
5479 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5482 if (!r_shadow_selectedlight)
5484 Con_Print("No selected light.\n");
5487 VectorCopy(r_shadow_selectedlight->origin, origin);
5488 VectorCopy(r_shadow_selectedlight->angles, angles);
5489 VectorCopy(r_shadow_selectedlight->color, color);
5490 radius = r_shadow_selectedlight->radius;
5491 style = r_shadow_selectedlight->style;
5492 if (r_shadow_selectedlight->cubemapname)
5493 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5496 shadows = r_shadow_selectedlight->shadow;
5497 corona = r_shadow_selectedlight->corona;
5498 coronasizescale = r_shadow_selectedlight->coronasizescale;
5499 ambientscale = r_shadow_selectedlight->ambientscale;
5500 diffusescale = r_shadow_selectedlight->diffusescale;
5501 specularscale = r_shadow_selectedlight->specularscale;
5502 flags = r_shadow_selectedlight->flags;
5503 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5504 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5505 if (!strcmp(Cmd_Argv(1), "origin"))
5507 if (Cmd_Argc() != 5)
5509 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5512 origin[0] = atof(Cmd_Argv(2));
5513 origin[1] = atof(Cmd_Argv(3));
5514 origin[2] = atof(Cmd_Argv(4));
5516 else if (!strcmp(Cmd_Argv(1), "originx"))
5518 if (Cmd_Argc() != 3)
5520 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5523 origin[0] = atof(Cmd_Argv(2));
5525 else if (!strcmp(Cmd_Argv(1), "originy"))
5527 if (Cmd_Argc() != 3)
5529 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5532 origin[1] = atof(Cmd_Argv(2));
5534 else if (!strcmp(Cmd_Argv(1), "originz"))
5536 if (Cmd_Argc() != 3)
5538 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5541 origin[2] = atof(Cmd_Argv(2));
5543 else if (!strcmp(Cmd_Argv(1), "move"))
5545 if (Cmd_Argc() != 5)
5547 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5550 origin[0] += atof(Cmd_Argv(2));
5551 origin[1] += atof(Cmd_Argv(3));
5552 origin[2] += atof(Cmd_Argv(4));
5554 else if (!strcmp(Cmd_Argv(1), "movex"))
5556 if (Cmd_Argc() != 3)
5558 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5561 origin[0] += atof(Cmd_Argv(2));
5563 else if (!strcmp(Cmd_Argv(1), "movey"))
5565 if (Cmd_Argc() != 3)
5567 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5570 origin[1] += atof(Cmd_Argv(2));
5572 else if (!strcmp(Cmd_Argv(1), "movez"))
5574 if (Cmd_Argc() != 3)
5576 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5579 origin[2] += atof(Cmd_Argv(2));
5581 else if (!strcmp(Cmd_Argv(1), "angles"))
5583 if (Cmd_Argc() != 5)
5585 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5588 angles[0] = atof(Cmd_Argv(2));
5589 angles[1] = atof(Cmd_Argv(3));
5590 angles[2] = atof(Cmd_Argv(4));
5592 else if (!strcmp(Cmd_Argv(1), "anglesx"))
5594 if (Cmd_Argc() != 3)
5596 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5599 angles[0] = atof(Cmd_Argv(2));
5601 else if (!strcmp(Cmd_Argv(1), "anglesy"))
5603 if (Cmd_Argc() != 3)
5605 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5608 angles[1] = atof(Cmd_Argv(2));
5610 else if (!strcmp(Cmd_Argv(1), "anglesz"))
5612 if (Cmd_Argc() != 3)
5614 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5617 angles[2] = atof(Cmd_Argv(2));
5619 else if (!strcmp(Cmd_Argv(1), "color"))
5621 if (Cmd_Argc() != 5)
5623 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
5626 color[0] = atof(Cmd_Argv(2));
5627 color[1] = atof(Cmd_Argv(3));
5628 color[2] = atof(Cmd_Argv(4));
5630 else if (!strcmp(Cmd_Argv(1), "radius"))
5632 if (Cmd_Argc() != 3)
5634 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5637 radius = atof(Cmd_Argv(2));
5639 else if (!strcmp(Cmd_Argv(1), "colorscale"))
5641 if (Cmd_Argc() == 3)
5643 double scale = atof(Cmd_Argv(2));
5650 if (Cmd_Argc() != 5)
5652 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
5655 color[0] *= atof(Cmd_Argv(2));
5656 color[1] *= atof(Cmd_Argv(3));
5657 color[2] *= atof(Cmd_Argv(4));
5660 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
5662 if (Cmd_Argc() != 3)
5664 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5667 radius *= atof(Cmd_Argv(2));
5669 else if (!strcmp(Cmd_Argv(1), "style"))
5671 if (Cmd_Argc() != 3)
5673 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5676 style = atoi(Cmd_Argv(2));
5678 else if (!strcmp(Cmd_Argv(1), "cubemap"))
5682 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5685 if (Cmd_Argc() == 3)
5686 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
5690 else if (!strcmp(Cmd_Argv(1), "shadows"))
5692 if (Cmd_Argc() != 3)
5694 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5697 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5699 else if (!strcmp(Cmd_Argv(1), "corona"))
5701 if (Cmd_Argc() != 3)
5703 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5706 corona = atof(Cmd_Argv(2));
5708 else if (!strcmp(Cmd_Argv(1), "coronasize"))
5710 if (Cmd_Argc() != 3)
5712 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5715 coronasizescale = atof(Cmd_Argv(2));
5717 else if (!strcmp(Cmd_Argv(1), "ambient"))
5719 if (Cmd_Argc() != 3)
5721 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5724 ambientscale = atof(Cmd_Argv(2));
5726 else if (!strcmp(Cmd_Argv(1), "diffuse"))
5728 if (Cmd_Argc() != 3)
5730 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5733 diffusescale = atof(Cmd_Argv(2));
5735 else if (!strcmp(Cmd_Argv(1), "specular"))
5737 if (Cmd_Argc() != 3)
5739 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5742 specularscale = atof(Cmd_Argv(2));
5744 else if (!strcmp(Cmd_Argv(1), "normalmode"))
5746 if (Cmd_Argc() != 3)
5748 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5751 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5753 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
5755 if (Cmd_Argc() != 3)
5757 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5760 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5764 Con_Print("usage: r_editlights_edit [property] [value]\n");
5765 Con_Print("Selected light's properties:\n");
5766 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5767 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5768 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5769 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
5770 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
5771 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
5772 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5773 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
5774 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
5775 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
5776 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
5777 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
5778 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5779 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5782 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5783 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5786 void R_Shadow_EditLights_EditAll_f(void)
5789 dlight_t *light, *oldselected;
5792 if (!r_editlights.integer)
5794 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5798 oldselected = r_shadow_selectedlight;
5799 // EditLights doesn't seem to have a "remove" command or something so:
5800 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5801 for (lightindex = 0;lightindex < range;lightindex++)
5803 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5806 R_Shadow_SelectLight(light);
5807 R_Shadow_EditLights_Edit_f();
5809 // return to old selected (to not mess editing once selection is locked)
5810 R_Shadow_SelectLight(oldselected);
5813 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
5815 int lightnumber, lightcount;
5816 size_t lightindex, range;
5820 if (!r_editlights.integer)
5822 x = vid_conwidth.value - 240;
5824 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
5827 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5828 for (lightindex = 0;lightindex < range;lightindex++)
5830 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5833 if (light == r_shadow_selectedlight)
5834 lightnumber = lightindex;
5837 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;
5838 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;
5840 if (r_shadow_selectedlight == NULL)
5842 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;
5843 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;
5844 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;
5845 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;
5846 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;
5847 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;
5848 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;
5849 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;
5850 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;
5851 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;
5852 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;
5853 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;
5854 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;
5855 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;
5856 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;
5859 void R_Shadow_EditLights_ToggleShadow_f(void)
5861 if (!r_editlights.integer)
5863 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5866 if (!r_shadow_selectedlight)
5868 Con_Print("No selected light.\n");
5871 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);
5874 void R_Shadow_EditLights_ToggleCorona_f(void)
5876 if (!r_editlights.integer)
5878 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5881 if (!r_shadow_selectedlight)
5883 Con_Print("No selected light.\n");
5886 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);
5889 void R_Shadow_EditLights_Remove_f(void)
5891 if (!r_editlights.integer)
5893 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
5896 if (!r_shadow_selectedlight)
5898 Con_Print("No selected light.\n");
5901 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
5902 r_shadow_selectedlight = NULL;
5905 void R_Shadow_EditLights_Help_f(void)
5908 "Documentation on r_editlights system:\n"
5910 "r_editlights : enable/disable editing mode\n"
5911 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
5912 "r_editlights_cursorpushback : push back cursor this far from surface\n"
5913 "r_editlights_cursorpushoff : push cursor off surface this far\n"
5914 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
5915 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
5917 "r_editlights_help : this help\n"
5918 "r_editlights_clear : remove all lights\n"
5919 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
5920 "r_editlights_lock : lock selection to current light, if already locked - unlock\n"
5921 "r_editlights_save : save to .rtlights file\n"
5922 "r_editlights_spawn : create a light with default settings\n"
5923 "r_editlights_edit command : edit selected light - more documentation below\n"
5924 "r_editlights_remove : remove selected light\n"
5925 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
5926 "r_editlights_importlightentitiesfrommap : reload light entities\n"
5927 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
5929 "origin x y z : set light location\n"
5930 "originx x: set x component of light location\n"
5931 "originy y: set y component of light location\n"
5932 "originz z: set z component of light location\n"
5933 "move x y z : adjust light location\n"
5934 "movex x: adjust x component of light location\n"
5935 "movey y: adjust y component of light location\n"
5936 "movez z: adjust z component of light location\n"
5937 "angles x y z : set light angles\n"
5938 "anglesx x: set x component of light angles\n"
5939 "anglesy y: set y component of light angles\n"
5940 "anglesz z: set z component of light angles\n"
5941 "color r g b : set color of light (can be brighter than 1 1 1)\n"
5942 "radius radius : set radius (size) of light\n"
5943 "colorscale grey : multiply color of light (1 does nothing)\n"
5944 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
5945 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
5946 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
5947 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
5948 "cubemap basename : set filter cubemap of light (not yet supported)\n"
5949 "shadows 1/0 : turn on/off shadows\n"
5950 "corona n : set corona intensity\n"
5951 "coronasize n : set corona size (0-1)\n"
5952 "ambient n : set ambient intensity (0-1)\n"
5953 "diffuse n : set diffuse intensity (0-1)\n"
5954 "specular n : set specular intensity (0-1)\n"
5955 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
5956 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
5957 "<nothing> : print light properties to console\n"
5961 void R_Shadow_EditLights_CopyInfo_f(void)
5963 if (!r_editlights.integer)
5965 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
5968 if (!r_shadow_selectedlight)
5970 Con_Print("No selected light.\n");
5973 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
5974 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
5975 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
5976 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
5977 if (r_shadow_selectedlight->cubemapname)
5978 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
5980 r_shadow_bufferlight.cubemapname[0] = 0;
5981 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
5982 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
5983 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
5984 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
5985 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
5986 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
5987 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
5990 void R_Shadow_EditLights_PasteInfo_f(void)
5992 if (!r_editlights.integer)
5994 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
5997 if (!r_shadow_selectedlight)
5999 Con_Print("No selected light.\n");
6002 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);
6005 void R_Shadow_EditLights_Lock_f(void)
6007 if (!r_editlights.integer)
6009 Con_Print("Cannot lock on light when not in editing mode. Set r_editlights to 1.\n");
6012 if (r_editlights_lockcursor)
6014 r_editlights_lockcursor = false;
6017 if (!r_shadow_selectedlight)
6019 Con_Print("No selected light to lock on.\n");
6022 r_editlights_lockcursor = true;
6025 void R_Shadow_EditLights_Init(void)
6027 Cvar_RegisterVariable(&r_editlights);
6028 Cvar_RegisterVariable(&r_editlights_cursordistance);
6029 Cvar_RegisterVariable(&r_editlights_cursorpushback);
6030 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
6031 Cvar_RegisterVariable(&r_editlights_cursorgrid);
6032 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
6033 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
6034 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
6035 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)");
6036 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
6037 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
6038 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
6039 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)");
6040 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
6041 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
6042 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
6043 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
6044 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
6045 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
6046 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)");
6047 Cmd_AddCommand("r_editlights_lock", R_Shadow_EditLights_Lock_f, "lock selection to current light, if already locked - unlock");
6053 =============================================================================
6057 =============================================================================
6060 void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, const int flags)
6062 int i, numlights, flag;
6063 float f, relativepoint[3], dist, dist2, lightradius2;
6067 VectorClear(diffusecolor);
6068 VectorClear(diffusenormal);
6070 if (flags & LP_LIGHTMAP)
6072 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
6074 ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_refdef.scene.ambient;
6075 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
6078 VectorSet(ambientcolor, 1, 1, 1);
6080 if (flags & LP_RTWORLD)
6082 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
6083 numlights = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
6084 for (i = 0; i < numlights; i++)
6086 dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
6089 light = &dlight->rtlight;
6090 if (!(light->flags & flag))
6093 lightradius2 = light->radius * light->radius;
6094 VectorSubtract(light->shadoworigin, p, relativepoint);
6095 dist2 = VectorLength2(relativepoint);
6096 if (dist2 >= lightradius2)
6098 dist = sqrt(dist2) / light->radius;
6099 f = dist < 1 ? (r_shadow_lightintensityscale.value * ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist))) : 0;
6102 // todo: add to both ambient and diffuse
6103 if (!light->shadow || CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
6104 VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);
6107 if (flags & LP_DYNLIGHT)
6110 for (i = 0;i < r_refdef.scene.numlights;i++)
6112 light = r_refdef.scene.lights[i];
6114 lightradius2 = light->radius * light->radius;
6115 VectorSubtract(light->shadoworigin, p, relativepoint);
6116 dist2 = VectorLength2(relativepoint);
6117 if (dist2 >= lightradius2)
6119 dist = sqrt(dist2) / light->radius;
6120 f = dist < 1 ? (r_shadow_lightintensityscale.value * ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist))) : 0;
6123 // todo: add to both ambient and diffuse
6124 if (!light->shadow || CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
6125 VectorMA(ambientcolor, f, light->color, ambientcolor);