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", "0", "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 checksm 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:
444 qboolean R_Shadow_ShadowMappingEnabled(void)
446 switch (r_shadow_shadowmode)
448 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
455 void R_Shadow_FreeShadowMaps(void)
457 R_Shadow_SetShadowMode();
459 R_Mesh_DestroyFramebufferObject(r_shadow_fbo2d);
463 if (r_shadow_shadowmap2dtexture)
464 R_FreeTexture(r_shadow_shadowmap2dtexture);
465 r_shadow_shadowmap2dtexture = NULL;
467 if (r_shadow_shadowmap2dcolortexture)
468 R_FreeTexture(r_shadow_shadowmap2dcolortexture);
469 r_shadow_shadowmap2dcolortexture = NULL;
471 if (r_shadow_shadowmapvsdcttexture)
472 R_FreeTexture(r_shadow_shadowmapvsdcttexture);
473 r_shadow_shadowmapvsdcttexture = NULL;
476 void r_shadow_start(void)
478 // allocate vertex processing arrays
479 r_shadow_attenuationgradienttexture = NULL;
480 r_shadow_attenuation2dtexture = NULL;
481 r_shadow_attenuation3dtexture = NULL;
482 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
483 r_shadow_shadowmap2dtexture = NULL;
484 r_shadow_shadowmap2dcolortexture = NULL;
485 r_shadow_shadowmapvsdcttexture = NULL;
486 r_shadow_shadowmapmaxsize = 0;
487 r_shadow_shadowmapsize = 0;
488 r_shadow_shadowmaplod = 0;
489 r_shadow_shadowmapfilterquality = -1;
490 r_shadow_shadowmapdepthbits = 0;
491 r_shadow_shadowmapvsdct = false;
492 r_shadow_shadowmapsampler = false;
493 r_shadow_shadowmappcf = 0;
496 R_Shadow_FreeShadowMaps();
498 r_shadow_texturepool = NULL;
499 r_shadow_filters_texturepool = NULL;
500 R_Shadow_ValidateCvars();
501 R_Shadow_MakeTextures();
502 maxshadowtriangles = 0;
503 shadowelements = NULL;
504 maxshadowvertices = 0;
505 shadowvertex3f = NULL;
513 shadowmarklist = NULL;
518 shadowsideslist = NULL;
519 r_shadow_buffer_numleafpvsbytes = 0;
520 r_shadow_buffer_visitingleafpvs = NULL;
521 r_shadow_buffer_leafpvs = NULL;
522 r_shadow_buffer_leaflist = NULL;
523 r_shadow_buffer_numsurfacepvsbytes = 0;
524 r_shadow_buffer_surfacepvs = NULL;
525 r_shadow_buffer_surfacelist = NULL;
526 r_shadow_buffer_surfacesides = NULL;
527 r_shadow_buffer_numshadowtrispvsbytes = 0;
528 r_shadow_buffer_shadowtrispvs = NULL;
529 r_shadow_buffer_numlighttrispvsbytes = 0;
530 r_shadow_buffer_lighttrispvs = NULL;
532 r_shadow_usingdeferredprepass = false;
533 r_shadow_prepass_width = r_shadow_prepass_height = 0;
536 static void R_Shadow_FreeDeferred(void);
537 void r_shadow_shutdown(void)
540 R_Shadow_UncompileWorldLights();
542 R_Shadow_FreeShadowMaps();
544 r_shadow_usingdeferredprepass = false;
545 if (r_shadow_prepass_width)
546 R_Shadow_FreeDeferred();
547 r_shadow_prepass_width = r_shadow_prepass_height = 0;
550 r_shadow_attenuationgradienttexture = NULL;
551 r_shadow_attenuation2dtexture = NULL;
552 r_shadow_attenuation3dtexture = NULL;
553 R_FreeTexturePool(&r_shadow_texturepool);
554 R_FreeTexturePool(&r_shadow_filters_texturepool);
555 maxshadowtriangles = 0;
557 Mem_Free(shadowelements);
558 shadowelements = NULL;
560 Mem_Free(shadowvertex3f);
561 shadowvertex3f = NULL;
564 Mem_Free(vertexupdate);
567 Mem_Free(vertexremap);
573 Mem_Free(shadowmark);
576 Mem_Free(shadowmarklist);
577 shadowmarklist = NULL;
582 Mem_Free(shadowsides);
585 Mem_Free(shadowsideslist);
586 shadowsideslist = NULL;
587 r_shadow_buffer_numleafpvsbytes = 0;
588 if (r_shadow_buffer_visitingleafpvs)
589 Mem_Free(r_shadow_buffer_visitingleafpvs);
590 r_shadow_buffer_visitingleafpvs = NULL;
591 if (r_shadow_buffer_leafpvs)
592 Mem_Free(r_shadow_buffer_leafpvs);
593 r_shadow_buffer_leafpvs = NULL;
594 if (r_shadow_buffer_leaflist)
595 Mem_Free(r_shadow_buffer_leaflist);
596 r_shadow_buffer_leaflist = NULL;
597 r_shadow_buffer_numsurfacepvsbytes = 0;
598 if (r_shadow_buffer_surfacepvs)
599 Mem_Free(r_shadow_buffer_surfacepvs);
600 r_shadow_buffer_surfacepvs = NULL;
601 if (r_shadow_buffer_surfacelist)
602 Mem_Free(r_shadow_buffer_surfacelist);
603 r_shadow_buffer_surfacelist = NULL;
604 if (r_shadow_buffer_surfacesides)
605 Mem_Free(r_shadow_buffer_surfacesides);
606 r_shadow_buffer_surfacesides = NULL;
607 r_shadow_buffer_numshadowtrispvsbytes = 0;
608 if (r_shadow_buffer_shadowtrispvs)
609 Mem_Free(r_shadow_buffer_shadowtrispvs);
610 r_shadow_buffer_numlighttrispvsbytes = 0;
611 if (r_shadow_buffer_lighttrispvs)
612 Mem_Free(r_shadow_buffer_lighttrispvs);
615 void r_shadow_newmap(void)
617 if (r_shadow_lightcorona) R_SkinFrame_MarkUsed(r_shadow_lightcorona);
618 if (r_editlights_sprcursor) R_SkinFrame_MarkUsed(r_editlights_sprcursor);
619 if (r_editlights_sprlight) R_SkinFrame_MarkUsed(r_editlights_sprlight);
620 if (r_editlights_sprnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprnoshadowlight);
621 if (r_editlights_sprcubemaplight) R_SkinFrame_MarkUsed(r_editlights_sprcubemaplight);
622 if (r_editlights_sprcubemapnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprcubemapnoshadowlight);
623 if (r_editlights_sprselection) R_SkinFrame_MarkUsed(r_editlights_sprselection);
624 if (strncmp(cl.worldname, r_shadow_mapname, sizeof(r_shadow_mapname)))
625 R_Shadow_EditLights_Reload_f();
628 void R_Shadow_Init(void)
630 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
631 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
632 Cvar_RegisterVariable(&r_shadow_usebihculling);
633 Cvar_RegisterVariable(&r_shadow_usenormalmap);
634 Cvar_RegisterVariable(&r_shadow_debuglight);
635 Cvar_RegisterVariable(&r_shadow_deferred);
636 Cvar_RegisterVariable(&r_shadow_deferred_8bitrange);
637 // Cvar_RegisterVariable(&r_shadow_deferred_fp);
638 Cvar_RegisterVariable(&r_shadow_gloss);
639 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
640 Cvar_RegisterVariable(&r_shadow_glossintensity);
641 Cvar_RegisterVariable(&r_shadow_glossexponent);
642 Cvar_RegisterVariable(&r_shadow_gloss2exponent);
643 Cvar_RegisterVariable(&r_shadow_glossexact);
644 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
645 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
646 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
647 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
648 Cvar_RegisterVariable(&r_shadow_projectdistance);
649 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
650 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
651 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
652 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
653 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
654 Cvar_RegisterVariable(&r_shadow_realtime_world);
655 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
656 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
657 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
658 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
659 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
660 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
661 Cvar_RegisterVariable(&r_shadow_scissor);
662 Cvar_RegisterVariable(&r_shadow_shadowmapping);
663 Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
664 Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
665 Cvar_RegisterVariable(&r_shadow_shadowmapping_depthbits);
666 Cvar_RegisterVariable(&r_shadow_shadowmapping_precision);
667 Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
668 Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
669 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
670 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
671 Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
672 Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
673 Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
674 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonfactor);
675 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonoffset);
676 Cvar_RegisterVariable(&r_shadow_sortsurfaces);
677 Cvar_RegisterVariable(&r_shadow_polygonfactor);
678 Cvar_RegisterVariable(&r_shadow_polygonoffset);
679 Cvar_RegisterVariable(&r_shadow_texture3d);
680 Cvar_RegisterVariable(&r_coronas);
681 Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
682 Cvar_RegisterVariable(&r_coronas_occlusionquery);
683 Cvar_RegisterVariable(&gl_flashblend);
684 Cvar_RegisterVariable(&gl_ext_separatestencil);
685 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
686 if (gamemode == GAME_TENEBRAE)
688 Cvar_SetValue("r_shadow_gloss", 2);
689 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
691 R_Shadow_EditLights_Init();
692 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
693 maxshadowtriangles = 0;
694 shadowelements = NULL;
695 maxshadowvertices = 0;
696 shadowvertex3f = NULL;
704 shadowmarklist = NULL;
709 shadowsideslist = NULL;
710 r_shadow_buffer_numleafpvsbytes = 0;
711 r_shadow_buffer_visitingleafpvs = NULL;
712 r_shadow_buffer_leafpvs = NULL;
713 r_shadow_buffer_leaflist = NULL;
714 r_shadow_buffer_numsurfacepvsbytes = 0;
715 r_shadow_buffer_surfacepvs = NULL;
716 r_shadow_buffer_surfacelist = NULL;
717 r_shadow_buffer_surfacesides = NULL;
718 r_shadow_buffer_shadowtrispvs = NULL;
719 r_shadow_buffer_lighttrispvs = NULL;
720 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap, NULL, NULL);
723 matrix4x4_t matrix_attenuationxyz =
726 {0.5, 0.0, 0.0, 0.5},
727 {0.0, 0.5, 0.0, 0.5},
728 {0.0, 0.0, 0.5, 0.5},
733 matrix4x4_t matrix_attenuationz =
736 {0.0, 0.0, 0.5, 0.5},
737 {0.0, 0.0, 0.0, 0.5},
738 {0.0, 0.0, 0.0, 0.5},
743 void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles, int vertscale, int triscale)
745 numvertices = ((numvertices + 255) & ~255) * vertscale;
746 numtriangles = ((numtriangles + 255) & ~255) * triscale;
747 // make sure shadowelements is big enough for this volume
748 if (maxshadowtriangles < numtriangles)
750 maxshadowtriangles = numtriangles;
752 Mem_Free(shadowelements);
753 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[3]));
755 // make sure shadowvertex3f is big enough for this volume
756 if (maxshadowvertices < numvertices)
758 maxshadowvertices = numvertices;
760 Mem_Free(shadowvertex3f);
761 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[3]));
765 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
767 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
768 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
769 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
770 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
771 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
773 if (r_shadow_buffer_visitingleafpvs)
774 Mem_Free(r_shadow_buffer_visitingleafpvs);
775 if (r_shadow_buffer_leafpvs)
776 Mem_Free(r_shadow_buffer_leafpvs);
777 if (r_shadow_buffer_leaflist)
778 Mem_Free(r_shadow_buffer_leaflist);
779 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
780 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
781 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
782 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
784 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
786 if (r_shadow_buffer_surfacepvs)
787 Mem_Free(r_shadow_buffer_surfacepvs);
788 if (r_shadow_buffer_surfacelist)
789 Mem_Free(r_shadow_buffer_surfacelist);
790 if (r_shadow_buffer_surfacesides)
791 Mem_Free(r_shadow_buffer_surfacesides);
792 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
793 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
794 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
795 r_shadow_buffer_surfacesides = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
797 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
799 if (r_shadow_buffer_shadowtrispvs)
800 Mem_Free(r_shadow_buffer_shadowtrispvs);
801 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
802 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
804 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
806 if (r_shadow_buffer_lighttrispvs)
807 Mem_Free(r_shadow_buffer_lighttrispvs);
808 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
809 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
813 void R_Shadow_PrepareShadowMark(int numtris)
815 // make sure shadowmark is big enough for this volume
816 if (maxshadowmark < numtris)
818 maxshadowmark = numtris;
820 Mem_Free(shadowmark);
822 Mem_Free(shadowmarklist);
823 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
824 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
828 // if shadowmarkcount wrapped we clear the array and adjust accordingly
829 if (shadowmarkcount == 0)
832 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
837 void R_Shadow_PrepareShadowSides(int numtris)
839 if (maxshadowsides < numtris)
841 maxshadowsides = numtris;
843 Mem_Free(shadowsides);
845 Mem_Free(shadowsideslist);
846 shadowsides = (unsigned char *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsides));
847 shadowsideslist = (int *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsideslist));
852 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)
855 int outtriangles = 0, outvertices = 0;
858 float ratio, direction[3], projectvector[3];
860 if (projectdirection)
861 VectorScale(projectdirection, projectdistance, projectvector);
863 VectorClear(projectvector);
865 // create the vertices
866 if (projectdirection)
868 for (i = 0;i < numshadowmarktris;i++)
870 element = inelement3i + shadowmarktris[i] * 3;
871 for (j = 0;j < 3;j++)
873 if (vertexupdate[element[j]] != vertexupdatenum)
875 vertexupdate[element[j]] = vertexupdatenum;
876 vertexremap[element[j]] = outvertices;
877 vertex = invertex3f + element[j] * 3;
878 // project one copy of the vertex according to projectvector
879 VectorCopy(vertex, outvertex3f);
880 VectorAdd(vertex, projectvector, (outvertex3f + 3));
889 for (i = 0;i < numshadowmarktris;i++)
891 element = inelement3i + shadowmarktris[i] * 3;
892 for (j = 0;j < 3;j++)
894 if (vertexupdate[element[j]] != vertexupdatenum)
896 vertexupdate[element[j]] = vertexupdatenum;
897 vertexremap[element[j]] = outvertices;
898 vertex = invertex3f + element[j] * 3;
899 // project one copy of the vertex to the sphere radius of the light
900 // (FIXME: would projecting it to the light box be better?)
901 VectorSubtract(vertex, projectorigin, direction);
902 ratio = projectdistance / VectorLength(direction);
903 VectorCopy(vertex, outvertex3f);
904 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
912 if (r_shadow_frontsidecasting.integer)
914 for (i = 0;i < numshadowmarktris;i++)
916 int remappedelement[3];
918 const int *neighbortriangle;
920 markindex = shadowmarktris[i] * 3;
921 element = inelement3i + markindex;
922 neighbortriangle = inneighbor3i + markindex;
923 // output the front and back triangles
924 outelement3i[0] = vertexremap[element[0]];
925 outelement3i[1] = vertexremap[element[1]];
926 outelement3i[2] = vertexremap[element[2]];
927 outelement3i[3] = vertexremap[element[2]] + 1;
928 outelement3i[4] = vertexremap[element[1]] + 1;
929 outelement3i[5] = vertexremap[element[0]] + 1;
933 // output the sides (facing outward from this triangle)
934 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
936 remappedelement[0] = vertexremap[element[0]];
937 remappedelement[1] = vertexremap[element[1]];
938 outelement3i[0] = remappedelement[1];
939 outelement3i[1] = remappedelement[0];
940 outelement3i[2] = remappedelement[0] + 1;
941 outelement3i[3] = remappedelement[1];
942 outelement3i[4] = remappedelement[0] + 1;
943 outelement3i[5] = remappedelement[1] + 1;
948 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
950 remappedelement[1] = vertexremap[element[1]];
951 remappedelement[2] = vertexremap[element[2]];
952 outelement3i[0] = remappedelement[2];
953 outelement3i[1] = remappedelement[1];
954 outelement3i[2] = remappedelement[1] + 1;
955 outelement3i[3] = remappedelement[2];
956 outelement3i[4] = remappedelement[1] + 1;
957 outelement3i[5] = remappedelement[2] + 1;
962 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
964 remappedelement[0] = vertexremap[element[0]];
965 remappedelement[2] = vertexremap[element[2]];
966 outelement3i[0] = remappedelement[0];
967 outelement3i[1] = remappedelement[2];
968 outelement3i[2] = remappedelement[2] + 1;
969 outelement3i[3] = remappedelement[0];
970 outelement3i[4] = remappedelement[2] + 1;
971 outelement3i[5] = remappedelement[0] + 1;
980 for (i = 0;i < numshadowmarktris;i++)
982 int remappedelement[3];
984 const int *neighbortriangle;
986 markindex = shadowmarktris[i] * 3;
987 element = inelement3i + markindex;
988 neighbortriangle = inneighbor3i + markindex;
989 // output the front and back triangles
990 outelement3i[0] = vertexremap[element[2]];
991 outelement3i[1] = vertexremap[element[1]];
992 outelement3i[2] = vertexremap[element[0]];
993 outelement3i[3] = vertexremap[element[0]] + 1;
994 outelement3i[4] = vertexremap[element[1]] + 1;
995 outelement3i[5] = vertexremap[element[2]] + 1;
999 // output the sides (facing outward from this triangle)
1000 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
1002 remappedelement[0] = vertexremap[element[0]];
1003 remappedelement[1] = vertexremap[element[1]];
1004 outelement3i[0] = remappedelement[0];
1005 outelement3i[1] = remappedelement[1];
1006 outelement3i[2] = remappedelement[1] + 1;
1007 outelement3i[3] = remappedelement[0];
1008 outelement3i[4] = remappedelement[1] + 1;
1009 outelement3i[5] = remappedelement[0] + 1;
1014 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1016 remappedelement[1] = vertexremap[element[1]];
1017 remappedelement[2] = vertexremap[element[2]];
1018 outelement3i[0] = remappedelement[1];
1019 outelement3i[1] = remappedelement[2];
1020 outelement3i[2] = remappedelement[2] + 1;
1021 outelement3i[3] = remappedelement[1];
1022 outelement3i[4] = remappedelement[2] + 1;
1023 outelement3i[5] = remappedelement[1] + 1;
1028 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1030 remappedelement[0] = vertexremap[element[0]];
1031 remappedelement[2] = vertexremap[element[2]];
1032 outelement3i[0] = remappedelement[2];
1033 outelement3i[1] = remappedelement[0];
1034 outelement3i[2] = remappedelement[0] + 1;
1035 outelement3i[3] = remappedelement[2];
1036 outelement3i[4] = remappedelement[0] + 1;
1037 outelement3i[5] = remappedelement[2] + 1;
1045 *outnumvertices = outvertices;
1046 return outtriangles;
1049 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)
1052 int outtriangles = 0, outvertices = 0;
1054 const float *vertex;
1055 float ratio, direction[3], projectvector[3];
1058 if (projectdirection)
1059 VectorScale(projectdirection, projectdistance, projectvector);
1061 VectorClear(projectvector);
1063 for (i = 0;i < numshadowmarktris;i++)
1065 int remappedelement[3];
1067 const int *neighbortriangle;
1069 markindex = shadowmarktris[i] * 3;
1070 neighbortriangle = inneighbor3i + markindex;
1071 side[0] = shadowmark[neighbortriangle[0]] == shadowmarkcount;
1072 side[1] = shadowmark[neighbortriangle[1]] == shadowmarkcount;
1073 side[2] = shadowmark[neighbortriangle[2]] == shadowmarkcount;
1074 if (side[0] + side[1] + side[2] == 0)
1078 element = inelement3i + markindex;
1080 // create the vertices
1081 for (j = 0;j < 3;j++)
1083 if (side[j] + side[j+1] == 0)
1086 if (vertexupdate[k] != vertexupdatenum)
1088 vertexupdate[k] = vertexupdatenum;
1089 vertexremap[k] = outvertices;
1090 vertex = invertex3f + k * 3;
1091 VectorCopy(vertex, outvertex3f);
1092 if (projectdirection)
1094 // project one copy of the vertex according to projectvector
1095 VectorAdd(vertex, projectvector, (outvertex3f + 3));
1099 // project one copy of the vertex to the sphere radius of the light
1100 // (FIXME: would projecting it to the light box be better?)
1101 VectorSubtract(vertex, projectorigin, direction);
1102 ratio = projectdistance / VectorLength(direction);
1103 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1110 // output the sides (facing outward from this triangle)
1113 remappedelement[0] = vertexremap[element[0]];
1114 remappedelement[1] = vertexremap[element[1]];
1115 outelement3i[0] = remappedelement[1];
1116 outelement3i[1] = remappedelement[0];
1117 outelement3i[2] = remappedelement[0] + 1;
1118 outelement3i[3] = remappedelement[1];
1119 outelement3i[4] = remappedelement[0] + 1;
1120 outelement3i[5] = remappedelement[1] + 1;
1127 remappedelement[1] = vertexremap[element[1]];
1128 remappedelement[2] = vertexremap[element[2]];
1129 outelement3i[0] = remappedelement[2];
1130 outelement3i[1] = remappedelement[1];
1131 outelement3i[2] = remappedelement[1] + 1;
1132 outelement3i[3] = remappedelement[2];
1133 outelement3i[4] = remappedelement[1] + 1;
1134 outelement3i[5] = remappedelement[2] + 1;
1141 remappedelement[0] = vertexremap[element[0]];
1142 remappedelement[2] = vertexremap[element[2]];
1143 outelement3i[0] = remappedelement[0];
1144 outelement3i[1] = remappedelement[2];
1145 outelement3i[2] = remappedelement[2] + 1;
1146 outelement3i[3] = remappedelement[0];
1147 outelement3i[4] = remappedelement[2] + 1;
1148 outelement3i[5] = remappedelement[0] + 1;
1155 *outnumvertices = outvertices;
1156 return outtriangles;
1159 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)
1165 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1167 tend = firsttriangle + numtris;
1168 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1170 // surface box entirely inside light box, no box cull
1171 if (projectdirection)
1173 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1175 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
1176 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1177 shadowmarklist[numshadowmark++] = t;
1182 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1183 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
1184 shadowmarklist[numshadowmark++] = t;
1189 // surface box not entirely inside light box, cull each triangle
1190 if (projectdirection)
1192 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1194 v[0] = invertex3f + e[0] * 3;
1195 v[1] = invertex3f + e[1] * 3;
1196 v[2] = invertex3f + e[2] * 3;
1197 TriangleNormal(v[0], v[1], v[2], normal);
1198 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1199 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1200 shadowmarklist[numshadowmark++] = t;
1205 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1207 v[0] = invertex3f + e[0] * 3;
1208 v[1] = invertex3f + e[1] * 3;
1209 v[2] = invertex3f + e[2] * 3;
1210 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1211 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1212 shadowmarklist[numshadowmark++] = t;
1218 qboolean R_Shadow_UseZPass(vec3_t mins, vec3_t maxs)
1223 if (r_shadow_compilingrtlight || !r_shadow_frontsidecasting.integer || !r_shadow_usezpassifpossible.integer)
1225 // check if the shadow volume intersects the near plane
1227 // a ray between the eye and light origin may intersect the caster,
1228 // indicating that the shadow may touch the eye location, however we must
1229 // test the near plane (a polygon), not merely the eye location, so it is
1230 // easiest to enlarge the caster bounding shape slightly for this.
1236 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)
1238 int i, tris, outverts;
1239 if (projectdistance < 0.1)
1241 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
1244 if (!numverts || !nummarktris)
1246 // make sure shadowelements is big enough for this volume
1247 if (maxshadowtriangles < nummarktris*8 || maxshadowvertices < numverts*2)
1248 R_Shadow_ResizeShadowArrays(numverts, nummarktris, 2, 8);
1250 if (maxvertexupdate < numverts)
1252 maxvertexupdate = numverts;
1254 Mem_Free(vertexupdate);
1256 Mem_Free(vertexremap);
1257 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1258 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1259 vertexupdatenum = 0;
1262 if (vertexupdatenum == 0)
1264 vertexupdatenum = 1;
1265 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
1266 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
1269 for (i = 0;i < nummarktris;i++)
1270 shadowmark[marktris[i]] = shadowmarkcount;
1272 if (r_shadow_compilingrtlight)
1274 // if we're compiling an rtlight, capture the mesh
1275 //tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1276 //Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zpass, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1277 tris = R_Shadow_ConstructShadowVolume_ZFail(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_zfail, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1280 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
1282 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1283 R_Mesh_PrepareVertices_Vertex3f(outverts, shadowvertex3f, NULL);
1284 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1288 // decide which type of shadow to generate and set stencil mode
1289 R_Shadow_RenderMode_StencilShadowVolumes(R_Shadow_UseZPass(trismins, trismaxs));
1290 // generate the sides or a solid volume, depending on type
1291 if (r_shadow_rendermode >= R_SHADOW_RENDERMODE_ZPASS_STENCIL && r_shadow_rendermode <= R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE)
1292 tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1294 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1295 r_refdef.stats.lights_dynamicshadowtriangles += tris;
1296 r_refdef.stats.lights_shadowtriangles += tris;
1297 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
1299 // increment stencil if frontface is infront of depthbuffer
1300 GL_CullFace(r_refdef.view.cullface_front);
1301 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
1302 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1303 // decrement stencil if backface is infront of depthbuffer
1304 GL_CullFace(r_refdef.view.cullface_back);
1305 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
1307 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
1309 // decrement stencil if backface is behind depthbuffer
1310 GL_CullFace(r_refdef.view.cullface_front);
1311 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
1312 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1313 // increment stencil if frontface is behind depthbuffer
1314 GL_CullFace(r_refdef.view.cullface_back);
1315 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
1317 R_Mesh_PrepareVertices_Vertex3f(outverts, shadowvertex3f, NULL);
1318 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1322 int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias)
1324 // p1, p2, p3 are in the cubemap's local coordinate system
1325 // bias = border/(size - border)
1328 float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1329 dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2),
1330 dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3);
1331 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1333 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1334 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1335 | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1336 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1338 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1339 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1340 | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1342 dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1343 dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2),
1344 dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3);
1345 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1347 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1348 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1349 | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1350 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1352 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1353 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1354 | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1356 dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1357 dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2),
1358 dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3);
1359 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1361 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1362 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1363 | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1364 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1366 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1367 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1368 | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1373 int R_Shadow_CalcBBoxSideMask(const vec3_t mins, const vec3_t maxs, const matrix4x4_t *worldtolight, const matrix4x4_t *radiustolight, float bias)
1375 vec3_t center, radius, lightcenter, lightradius, pmin, pmax;
1376 float dp1, dn1, ap1, an1, dp2, dn2, ap2, an2;
1379 VectorSubtract(maxs, mins, radius);
1380 VectorScale(radius, 0.5f, radius);
1381 VectorAdd(mins, radius, center);
1382 Matrix4x4_Transform(worldtolight, center, lightcenter);
1383 Matrix4x4_Transform3x3(radiustolight, radius, lightradius);
1384 VectorSubtract(lightcenter, lightradius, pmin);
1385 VectorAdd(lightcenter, lightradius, pmax);
1387 dp1 = pmax[0] + pmax[1], dn1 = pmax[0] - pmin[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1388 dp2 = pmin[0] + pmin[1], dn2 = pmin[0] - pmax[1], ap2 = fabs(dp2), an2 = fabs(dn2);
1389 if(ap1 > bias*an1 && ap2 > bias*an2)
1391 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1392 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1393 if(an1 > bias*ap1 && an2 > bias*ap2)
1395 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1396 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1398 dp1 = pmax[1] + pmax[2], dn1 = pmax[1] - pmin[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1399 dp2 = pmin[1] + pmin[2], dn2 = pmin[1] - pmax[2], ap2 = fabs(dp2), an2 = fabs(dn2);
1400 if(ap1 > bias*an1 && ap2 > bias*an2)
1402 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1403 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1404 if(an1 > bias*ap1 && an2 > bias*ap2)
1406 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1407 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1409 dp1 = pmax[2] + pmax[0], dn1 = pmax[2] - pmin[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1410 dp2 = pmin[2] + pmin[0], dn2 = pmin[2] - pmax[0], ap2 = fabs(dp2), an2 = fabs(dn2);
1411 if(ap1 > bias*an1 && ap2 > bias*an2)
1413 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1414 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1415 if(an1 > bias*ap1 && an2 > bias*ap2)
1417 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1418 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1423 #define R_Shadow_CalcEntitySideMask(ent, worldtolight, radiustolight, bias) R_Shadow_CalcBBoxSideMask((ent)->mins, (ent)->maxs, worldtolight, radiustolight, bias)
1425 int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
1427 // p is in the cubemap's local coordinate system
1428 // bias = border/(size - border)
1429 float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn);
1430 float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn);
1431 float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn);
1433 if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
1434 if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
1435 if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
1436 if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
1437 if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
1438 if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
1442 int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
1446 int sides = 0x3F, masks[6] = { 3<<4, 3<<4, 3<<0, 3<<0, 3<<2, 3<<2 };
1447 float scale = (size - 2*border)/size, len;
1448 float bias = border / (float)(size - border), dp, dn, ap, an;
1449 // check if cone enclosing side would cross frustum plane
1450 scale = 2 / (scale*scale + 2);
1451 for (i = 0;i < 5;i++)
1453 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) > -0.03125)
1455 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[i].normal, n);
1456 len = scale*VectorLength2(n);
1457 if(n[0]*n[0] > len) sides &= n[0] < 0 ? ~(1<<0) : ~(2 << 0);
1458 if(n[1]*n[1] > len) sides &= n[1] < 0 ? ~(1<<2) : ~(2 << 2);
1459 if(n[2]*n[2] > len) sides &= n[2] < 0 ? ~(1<<4) : ~(2 << 4);
1461 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[4]) >= r_refdef.farclip - r_refdef.nearclip + 0.03125)
1463 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[4].normal, n);
1464 len = scale*VectorLength(n);
1465 if(n[0]*n[0] > len) sides &= n[0] >= 0 ? ~(1<<0) : ~(2 << 0);
1466 if(n[1]*n[1] > len) sides &= n[1] >= 0 ? ~(1<<2) : ~(2 << 2);
1467 if(n[2]*n[2] > len) sides &= n[2] >= 0 ? ~(1<<4) : ~(2 << 4);
1469 // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results
1470 // check if frustum corners/origin cross plane sides
1472 // infinite version, assumes frustum corners merely give direction and extend to infinite distance
1473 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.origin, p);
1474 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1475 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1476 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1477 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1478 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1479 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1480 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1481 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1482 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1483 for (i = 0;i < 4;i++)
1485 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.frustumcorner[i], n);
1486 VectorSubtract(n, p, n);
1487 dp = n[0] + n[1], dn = n[0] - n[1], ap = fabs(dp), an = fabs(dn);
1488 if(ap > 0) masks[0] |= dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2);
1489 if(an > 0) masks[1] |= dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2);
1490 dp = n[1] + n[2], dn = n[1] - n[2], ap = fabs(dp), an = fabs(dn);
1491 if(ap > 0) masks[2] |= dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4);
1492 if(an > 0) masks[3] |= dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4);
1493 dp = n[2] + n[0], dn = n[2] - n[0], ap = fabs(dp), an = fabs(dn);
1494 if(ap > 0) masks[4] |= dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0);
1495 if(an > 0) masks[5] |= dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0);
1498 // finite version, assumes corners are a finite distance from origin dependent on far plane
1499 for (i = 0;i < 5;i++)
1501 Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p);
1502 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1503 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1504 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1505 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1506 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1507 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1508 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1509 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1510 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1513 return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5];
1516 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)
1524 int mask, surfacemask = 0;
1525 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1527 bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
1528 tend = firsttriangle + numtris;
1529 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1531 // surface box entirely inside light box, no box cull
1532 if (projectdirection)
1534 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1536 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1537 TriangleNormal(v[0], v[1], v[2], normal);
1538 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1540 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1541 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1542 surfacemask |= mask;
1545 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;
1546 shadowsides[numshadowsides] = mask;
1547 shadowsideslist[numshadowsides++] = t;
1554 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1556 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1557 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]))
1559 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1560 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1561 surfacemask |= mask;
1564 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;
1565 shadowsides[numshadowsides] = mask;
1566 shadowsideslist[numshadowsides++] = t;
1574 // surface box not entirely inside light box, cull each triangle
1575 if (projectdirection)
1577 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1579 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1580 TriangleNormal(v[0], v[1], v[2], normal);
1581 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1582 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1584 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1585 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1586 surfacemask |= mask;
1589 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;
1590 shadowsides[numshadowsides] = mask;
1591 shadowsideslist[numshadowsides++] = t;
1598 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1600 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1601 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1602 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1604 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1605 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1606 surfacemask |= mask;
1609 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;
1610 shadowsides[numshadowsides] = mask;
1611 shadowsideslist[numshadowsides++] = t;
1620 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)
1622 int i, j, outtriangles = 0;
1623 int *outelement3i[6];
1624 if (!numverts || !numsidetris || !r_shadow_compilingrtlight)
1626 outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5];
1627 // make sure shadowelements is big enough for this mesh
1628 if (maxshadowtriangles < outtriangles)
1629 R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1);
1631 // compute the offset and size of the separate index lists for each cubemap side
1633 for (i = 0;i < 6;i++)
1635 outelement3i[i] = shadowelements + outtriangles * 3;
1636 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles;
1637 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i];
1638 outtriangles += sidetotals[i];
1641 // gather up the (sparse) triangles into separate index lists for each cubemap side
1642 for (i = 0;i < numsidetris;i++)
1644 const int *element = elements + sidetris[i] * 3;
1645 for (j = 0;j < 6;j++)
1647 if (sides[i] & (1 << j))
1649 outelement3i[j][0] = element[0];
1650 outelement3i[j][1] = element[1];
1651 outelement3i[j][2] = element[2];
1652 outelement3i[j] += 3;
1657 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, outtriangles, shadowelements);
1660 static void R_Shadow_MakeTextures_MakeCorona(void)
1664 unsigned char pixels[32][32][4];
1665 for (y = 0;y < 32;y++)
1667 dy = (y - 15.5f) * (1.0f / 16.0f);
1668 for (x = 0;x < 32;x++)
1670 dx = (x - 15.5f) * (1.0f / 16.0f);
1671 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1672 a = bound(0, a, 255);
1673 pixels[y][x][0] = a;
1674 pixels[y][x][1] = a;
1675 pixels[y][x][2] = a;
1676 pixels[y][x][3] = 255;
1679 r_shadow_lightcorona = R_SkinFrame_LoadInternalBGRA("lightcorona", TEXF_FORCELINEAR, &pixels[0][0][0], 32, 32);
1682 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1684 float dist = sqrt(x*x+y*y+z*z);
1685 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1686 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1687 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1690 static void R_Shadow_MakeTextures(void)
1693 float intensity, dist;
1695 R_Shadow_FreeShadowMaps();
1696 R_FreeTexturePool(&r_shadow_texturepool);
1697 r_shadow_texturepool = R_AllocTexturePool();
1698 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1699 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1700 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1701 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1702 for (x = 0;x <= ATTENTABLESIZE;x++)
1704 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1705 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1706 r_shadow_attentable[x] = bound(0, intensity, 1);
1708 // 1D gradient texture
1709 for (x = 0;x < ATTEN1DSIZE;x++)
1710 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1711 r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1712 // 2D circle texture
1713 for (y = 0;y < ATTEN2DSIZE;y++)
1714 for (x = 0;x < ATTEN2DSIZE;x++)
1715 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);
1716 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1717 // 3D sphere texture
1718 if (r_shadow_texture3d.integer && vid.support.ext_texture_3d)
1720 for (z = 0;z < ATTEN3DSIZE;z++)
1721 for (y = 0;y < ATTEN3DSIZE;y++)
1722 for (x = 0;x < ATTEN3DSIZE;x++)
1723 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));
1724 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);
1727 r_shadow_attenuation3dtexture = NULL;
1730 R_Shadow_MakeTextures_MakeCorona();
1732 // Editor light sprites
1733 r_editlights_sprcursor = R_SkinFrame_LoadInternal8bit("gfx/editlights/cursor", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1750 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1751 r_editlights_sprlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/light", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1768 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1769 r_editlights_sprnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/noshadow", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1786 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1787 r_editlights_sprcubemaplight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemaplight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1804 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1805 r_editlights_sprcubemapnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemapnoshadowlight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1822 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1823 r_editlights_sprselection = R_SkinFrame_LoadInternal8bit("gfx/editlights/selection", TEXF_ALPHA | TEXF_CLAMP, (unsigned char *)
1840 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1843 void R_Shadow_ValidateCvars(void)
1845 if (r_shadow_texture3d.integer && !vid.support.ext_texture_3d)
1846 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1847 if (gl_ext_separatestencil.integer && !vid.support.ati_separate_stencil)
1848 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
1849 if (gl_ext_stenciltwoside.integer && !vid.support.ext_stencil_two_side)
1850 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1853 void R_Shadow_RenderMode_Begin(void)
1859 R_Shadow_ValidateCvars();
1861 if (!r_shadow_attenuation2dtexture
1862 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1863 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1864 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1865 R_Shadow_MakeTextures();
1868 R_Mesh_ResetTextureState();
1869 GL_BlendFunc(GL_ONE, GL_ZERO);
1870 GL_DepthRange(0, 1);
1871 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1873 GL_DepthMask(false);
1874 GL_Color(0, 0, 0, 1);
1875 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1877 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1879 if (gl_ext_separatestencil.integer && vid.support.ati_separate_stencil)
1881 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
1882 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
1884 else if (gl_ext_stenciltwoside.integer && vid.support.ext_stencil_two_side)
1886 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
1887 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
1891 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
1892 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
1895 switch(vid.renderpath)
1897 case RENDERPATH_GL20:
1898 case RENDERPATH_CGGL:
1899 case RENDERPATH_D3D9:
1900 case RENDERPATH_D3D10:
1901 case RENDERPATH_D3D11:
1902 case RENDERPATH_SOFT:
1903 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1905 case RENDERPATH_GL13:
1906 case RENDERPATH_GL11:
1907 if (r_textureunits.integer >= 2 && vid.texunits >= 2 && r_shadow_texture3d.integer && r_shadow_attenuation3dtexture)
1908 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN;
1909 else if (r_textureunits.integer >= 3 && vid.texunits >= 3)
1910 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN;
1911 else if (r_textureunits.integer >= 2 && vid.texunits >= 2)
1912 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN;
1914 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1920 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
1921 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
1922 r_shadow_drawbuffer = drawbuffer;
1923 r_shadow_readbuffer = readbuffer;
1925 r_shadow_cullface_front = r_refdef.view.cullface_front;
1926 r_shadow_cullface_back = r_refdef.view.cullface_back;
1929 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
1931 rsurface.rtlight = rtlight;
1934 void R_Shadow_RenderMode_Reset(void)
1936 R_Mesh_ResetRenderTargets();
1937 R_SetViewport(&r_refdef.view.viewport);
1938 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
1939 R_Mesh_ResetTextureState();
1940 GL_DepthRange(0, 1);
1942 GL_DepthMask(false);
1943 GL_DepthFunc(GL_LEQUAL);
1944 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1945 r_refdef.view.cullface_front = r_shadow_cullface_front;
1946 r_refdef.view.cullface_back = r_shadow_cullface_back;
1947 GL_CullFace(r_refdef.view.cullface_back);
1948 GL_Color(1, 1, 1, 1);
1949 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
1950 GL_BlendFunc(GL_ONE, GL_ZERO);
1951 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
1952 r_shadow_usingshadowmap2d = false;
1953 r_shadow_usingshadowmaportho = false;
1954 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
1957 void R_Shadow_ClearStencil(void)
1959 GL_Clear(GL_STENCIL_BUFFER_BIT, NULL, 1.0f, 128);
1960 r_refdef.stats.lights_clears++;
1963 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
1965 r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
1966 if (r_shadow_rendermode == mode)
1968 R_Shadow_RenderMode_Reset();
1969 GL_DepthFunc(GL_LESS);
1970 GL_ColorMask(0, 0, 0, 0);
1971 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1972 GL_CullFace(GL_NONE);
1973 R_SetupShader_DepthOrShadow();
1974 r_shadow_rendermode = mode;
1979 case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
1980 case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
1981 R_SetStencilSeparate(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, GL_ALWAYS, 128, 255);
1983 case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
1984 case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
1985 R_SetStencilSeparate(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, GL_ALWAYS, 128, 255);
1990 static void R_Shadow_MakeVSDCT(void)
1992 // maps to a 2x3 texture rectangle with normalized coordinates
1997 // stores abs(dir.xy), offset.xy/2.5
1998 unsigned char data[4*6] =
2000 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
2001 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
2002 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
2003 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
2004 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
2005 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
2007 r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
2010 static void R_Shadow_MakeShadowMap(int side, int size)
2012 switch (r_shadow_shadowmode)
2014 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2015 if (r_shadow_shadowmap2dtexture) return;
2016 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);
2017 r_shadow_shadowmap2dcolortexture = NULL;
2018 switch(vid.renderpath)
2021 case RENDERPATH_D3D9:
2022 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);
2023 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
2027 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2dtexture, NULL, NULL, NULL, NULL);
2035 // render depth into the fbo, do not render color at all
2036 // validate the fbo now
2040 qglDrawBuffer(GL_NONE);CHECKGLERROR
2041 qglReadBuffer(GL_NONE);CHECKGLERROR
2042 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2043 if (status != GL_FRAMEBUFFER_COMPLETE_EXT && (r_shadow_shadowmapping.integer || r_shadow_deferred.integer))
2045 Con_Printf("R_Shadow_MakeShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2046 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2047 Cvar_SetValueQuick(&r_shadow_deferred, 0);
2052 void R_Shadow_RenderMode_ShadowMap(int side, int clear, int size)
2054 float nearclip, farclip, bias;
2055 r_viewport_t viewport;
2058 float clearcolor[4];
2059 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
2061 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
2062 r_shadow_shadowmap_parameters[1] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
2063 r_shadow_shadowmap_parameters[3] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
2064 r_shadow_shadowmapside = side;
2065 r_shadow_shadowmapsize = size;
2067 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2068 r_shadow_shadowmap_parameters[2] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2069 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
2070 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D) goto init_done;
2072 // complex unrolled cube approach (more flexible)
2073 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2074 R_Shadow_MakeVSDCT();
2075 if (!r_shadow_shadowmap2dtexture)
2076 R_Shadow_MakeShadowMap(side, r_shadow_shadowmapmaxsize);
2077 if (r_shadow_shadowmap2dtexture) fbo = r_shadow_fbo2d;
2078 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
2079 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
2080 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
2082 R_Mesh_ResetTextureState();
2083 R_Mesh_ResetRenderTargets();
2084 R_Shadow_RenderMode_Reset();
2087 R_Mesh_SetRenderTargets(fbo, r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
2088 R_SetupShader_DepthOrShadow();
2091 R_SetupShader_ShowDepth();
2092 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
2097 R_SetViewport(&viewport);
2098 flipped = (side & 1) ^ (side >> 2);
2099 r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
2100 r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
2101 switch(vid.renderpath)
2103 case RENDERPATH_GL11:
2104 case RENDERPATH_GL13:
2105 case RENDERPATH_GL20:
2106 case RENDERPATH_CGGL:
2107 case RENDERPATH_SOFT:
2108 GL_CullFace(r_refdef.view.cullface_back);
2109 // OpenGL lets us scissor larger than the viewport, so go ahead and clear all views at once
2110 if ((clear & ((2 << side) - 1)) == (1 << side)) // only clear if the side is the first in the mask
2112 // get tightest scissor rectangle that encloses all viewports in the clear mask
2113 int x1 = clear & 0x15 ? 0 : size;
2114 int x2 = clear & 0x2A ? 2 * size : size;
2115 int y1 = clear & 0x03 ? 0 : (clear & 0xC ? size : 2 * size);
2116 int y2 = clear & 0x30 ? 3 * size : (clear & 0xC ? 2 * size : size);
2117 GL_Scissor(x1, y1, x2 - x1, y2 - y1);
2118 GL_Clear(GL_DEPTH_BUFFER_BIT, NULL, 1.0f, 0);
2120 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2122 case RENDERPATH_D3D9:
2123 case RENDERPATH_D3D10:
2124 case RENDERPATH_D3D11:
2125 Vector4Set(clearcolor, 1,1,1,1);
2126 // completely different meaning than in OpenGL path
2127 r_shadow_shadowmap_parameters[1] = 0;
2128 r_shadow_shadowmap_parameters[3] = -bias;
2129 // we invert the cull mode because we flip the projection matrix
2130 // NOTE: this actually does nothing because the DrawShadowMap code sets it to doublesided...
2131 GL_CullFace(r_refdef.view.cullface_front);
2132 // D3D considers it an error to use a scissor larger than the viewport... clear just this view
2133 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2134 if (r_shadow_shadowmapsampler)
2136 GL_ColorMask(0,0,0,0);
2138 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
2142 GL_ColorMask(1,1,1,1);
2144 GL_Clear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
2150 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
2152 R_Mesh_ResetTextureState();
2153 R_Mesh_ResetRenderTargets();
2156 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2157 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2158 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2159 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2161 R_Shadow_RenderMode_Reset();
2162 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2164 GL_DepthFunc(GL_EQUAL);
2165 // do global setup needed for the chosen lighting mode
2166 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2167 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2168 r_shadow_usingshadowmap2d = shadowmapping;
2169 r_shadow_rendermode = r_shadow_lightingrendermode;
2170 // only draw light where this geometry was already rendered AND the
2171 // stencil is 128 (values other than this mean shadow)
2173 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2175 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
2178 static const unsigned short bboxelements[36] =
2188 static const float bboxpoints[8][3] =
2200 void R_Shadow_RenderMode_DrawDeferredLight(qboolean stenciltest, qboolean shadowmapping)
2203 float vertex3f[8*3];
2204 const matrix4x4_t *matrix = &rsurface.rtlight->matrix_lighttoworld;
2205 // do global setup needed for the chosen lighting mode
2206 R_Shadow_RenderMode_Reset();
2207 r_shadow_rendermode = r_shadow_lightingrendermode;
2208 R_EntityMatrix(&identitymatrix);
2209 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2210 // only draw light where this geometry was already rendered AND the
2211 // stencil is 128 (values other than this mean shadow)
2212 R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2213 R_Mesh_SetRenderTargets(r_shadow_prepasslightingfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
2215 r_shadow_usingshadowmap2d = shadowmapping;
2217 // render the lighting
2218 R_SetupShader_DeferredLight(rsurface.rtlight);
2219 for (i = 0;i < 8;i++)
2220 Matrix4x4_Transform(matrix, bboxpoints[i], vertex3f + i*3);
2221 GL_ColorMask(1,1,1,1);
2222 GL_DepthMask(false);
2223 GL_DepthRange(0, 1);
2224 GL_PolygonOffset(0, 0);
2226 GL_DepthFunc(GL_GREATER);
2227 GL_CullFace(r_refdef.view.cullface_back);
2228 R_Mesh_PrepareVertices_Vertex3f(8, vertex3f, NULL);
2229 R_Mesh_Draw(0, 8, 0, 12, NULL, NULL, 0, bboxelements, NULL, 0);
2232 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
2234 R_Shadow_RenderMode_Reset();
2235 GL_BlendFunc(GL_ONE, GL_ONE);
2236 GL_DepthRange(0, 1);
2237 GL_DepthTest(r_showshadowvolumes.integer < 2);
2238 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
2239 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2240 GL_CullFace(GL_NONE);
2241 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
2244 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
2246 R_Shadow_RenderMode_Reset();
2247 GL_BlendFunc(GL_ONE, GL_ONE);
2248 GL_DepthRange(0, 1);
2249 GL_DepthTest(r_showlighting.integer < 2);
2250 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2252 GL_DepthFunc(GL_EQUAL);
2253 R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2254 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2257 void R_Shadow_RenderMode_End(void)
2259 R_Shadow_RenderMode_Reset();
2260 R_Shadow_RenderMode_ActiveLight(NULL);
2262 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2263 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2266 int bboxedges[12][2] =
2285 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2287 if (!r_shadow_scissor.integer)
2289 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2290 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2291 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2292 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2295 if(R_ScissorForBBox(mins, maxs, r_shadow_lightscissor))
2296 return true; // invisible
2297 if(r_shadow_lightscissor[0] != r_refdef.view.viewport.x
2298 || r_shadow_lightscissor[1] != r_refdef.view.viewport.y
2299 || r_shadow_lightscissor[2] != r_refdef.view.viewport.width
2300 || r_shadow_lightscissor[3] != r_refdef.view.viewport.height)
2301 r_refdef.stats.lights_scissored++;
2305 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, const float *diffusecolor, const float *ambientcolor)
2308 const float *vertex3f;
2309 const float *normal3f;
2311 float dist, dot, distintensity, shadeintensity, v[3], n[3];
2312 switch (r_shadow_rendermode)
2314 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2315 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2316 if (VectorLength2(diffusecolor) > 0)
2318 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)
2320 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2321 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2322 if ((dot = DotProduct(n, v)) < 0)
2324 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2325 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
2328 VectorCopy(ambientcolor, color4f);
2329 if (r_refdef.fogenabled)
2332 f = RSurf_FogVertex(vertex3f);
2333 VectorScale(color4f, f, color4f);
2340 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
2342 VectorCopy(ambientcolor, color4f);
2343 if (r_refdef.fogenabled)
2346 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2347 f = RSurf_FogVertex(vertex3f);
2348 VectorScale(color4f + 4*i, f, color4f);
2354 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2355 if (VectorLength2(diffusecolor) > 0)
2357 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)
2359 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2360 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2362 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2363 if ((dot = DotProduct(n, v)) < 0)
2365 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2366 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2367 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2368 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2372 color4f[0] = ambientcolor[0] * distintensity;
2373 color4f[1] = ambientcolor[1] * distintensity;
2374 color4f[2] = ambientcolor[2] * distintensity;
2376 if (r_refdef.fogenabled)
2379 f = RSurf_FogVertex(vertex3f);
2380 VectorScale(color4f, f, color4f);
2384 VectorClear(color4f);
2390 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
2392 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2393 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2395 color4f[0] = ambientcolor[0] * distintensity;
2396 color4f[1] = ambientcolor[1] * distintensity;
2397 color4f[2] = ambientcolor[2] * distintensity;
2398 if (r_refdef.fogenabled)
2401 f = RSurf_FogVertex(vertex3f);
2402 VectorScale(color4f, f, color4f);
2406 VectorClear(color4f);
2411 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2412 if (VectorLength2(diffusecolor) > 0)
2414 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)
2416 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2417 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2419 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2420 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2421 if ((dot = DotProduct(n, v)) < 0)
2423 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2424 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2425 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2426 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2430 color4f[0] = ambientcolor[0] * distintensity;
2431 color4f[1] = ambientcolor[1] * distintensity;
2432 color4f[2] = ambientcolor[2] * distintensity;
2434 if (r_refdef.fogenabled)
2437 f = RSurf_FogVertex(vertex3f);
2438 VectorScale(color4f, f, color4f);
2442 VectorClear(color4f);
2448 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
2450 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2451 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2453 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2454 color4f[0] = ambientcolor[0] * distintensity;
2455 color4f[1] = ambientcolor[1] * distintensity;
2456 color4f[2] = ambientcolor[2] * distintensity;
2457 if (r_refdef.fogenabled)
2460 f = RSurf_FogVertex(vertex3f);
2461 VectorScale(color4f, f, color4f);
2465 VectorClear(color4f);
2475 static void R_Shadow_RenderLighting_VisibleLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
2477 // used to display how many times a surface is lit for level design purposes
2478 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
2479 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
2483 static void R_Shadow_RenderLighting_Light_GLSL(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale, float specularscale)
2485 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2486 R_SetupShader_Surface(lightcolor, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT, texturenumsurfaces, texturesurfacelist, NULL);
2487 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2488 GL_DepthFunc(GL_EQUAL);
2490 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2491 GL_DepthFunc(GL_LEQUAL);
2494 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
2501 int newnumtriangles;
2505 int maxtriangles = 4096;
2506 static int newelements[4096*3];
2507 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, diffusecolor2, ambientcolor2);
2508 for (renders = 0;renders < 4;renders++)
2513 newnumtriangles = 0;
2515 // due to low fillrate on the cards this vertex lighting path is
2516 // designed for, we manually cull all triangles that do not
2517 // contain a lit vertex
2518 // this builds batches of triangles from multiple surfaces and
2519 // renders them at once
2520 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
2522 if (VectorLength2(rsurface.passcolor4f + e[0] * 4) + VectorLength2(rsurface.passcolor4f + e[1] * 4) + VectorLength2(rsurface.passcolor4f + e[2] * 4) >= 0.01)
2524 if (newnumtriangles)
2526 newfirstvertex = min(newfirstvertex, e[0]);
2527 newlastvertex = max(newlastvertex, e[0]);
2531 newfirstvertex = e[0];
2532 newlastvertex = e[0];
2534 newfirstvertex = min(newfirstvertex, e[1]);
2535 newlastvertex = max(newlastvertex, e[1]);
2536 newfirstvertex = min(newfirstvertex, e[2]);
2537 newlastvertex = max(newlastvertex, e[2]);
2543 if (newnumtriangles >= maxtriangles)
2545 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
2546 newnumtriangles = 0;
2552 if (newnumtriangles >= 1)
2554 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
2557 // if we couldn't find any lit triangles, exit early
2560 // now reduce the intensity for the next overbright pass
2561 // we have to clamp to 0 here incase the drivers have improper
2562 // handling of negative colors
2563 // (some old drivers even have improper handling of >1 color)
2565 for (i = 0, c = rsurface.passcolor4f + 4 * firstvertex;i < numvertices;i++, c += 4)
2567 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
2569 c[0] = max(0, c[0] - 1);
2570 c[1] = max(0, c[1] - 1);
2571 c[2] = max(0, c[2] - 1);
2583 static void R_Shadow_RenderLighting_Light_Vertex(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale)
2585 // OpenGL 1.1 path (anything)
2586 float ambientcolorbase[3], diffusecolorbase[3];
2587 float ambientcolorpants[3], diffusecolorpants[3];
2588 float ambientcolorshirt[3], diffusecolorshirt[3];
2589 const float *surfacecolor = rsurface.texture->dlightcolor;
2590 const float *surfacepants = rsurface.colormap_pantscolor;
2591 const float *surfaceshirt = rsurface.colormap_shirtcolor;
2592 rtexture_t *basetexture = rsurface.texture->basetexture;
2593 rtexture_t *pantstexture = rsurface.texture->pantstexture;
2594 rtexture_t *shirttexture = rsurface.texture->shirttexture;
2595 qboolean dopants = pantstexture && VectorLength2(surfacepants) >= (1.0f / 1048576.0f);
2596 qboolean doshirt = shirttexture && VectorLength2(surfaceshirt) >= (1.0f / 1048576.0f);
2597 ambientscale *= 2 * r_refdef.view.colorscale;
2598 diffusescale *= 2 * r_refdef.view.colorscale;
2599 ambientcolorbase[0] = lightcolor[0] * ambientscale * surfacecolor[0];ambientcolorbase[1] = lightcolor[1] * ambientscale * surfacecolor[1];ambientcolorbase[2] = lightcolor[2] * ambientscale * surfacecolor[2];
2600 diffusecolorbase[0] = lightcolor[0] * diffusescale * surfacecolor[0];diffusecolorbase[1] = lightcolor[1] * diffusescale * surfacecolor[1];diffusecolorbase[2] = lightcolor[2] * diffusescale * surfacecolor[2];
2601 ambientcolorpants[0] = ambientcolorbase[0] * surfacepants[0];ambientcolorpants[1] = ambientcolorbase[1] * surfacepants[1];ambientcolorpants[2] = ambientcolorbase[2] * surfacepants[2];
2602 diffusecolorpants[0] = diffusecolorbase[0] * surfacepants[0];diffusecolorpants[1] = diffusecolorbase[1] * surfacepants[1];diffusecolorpants[2] = diffusecolorbase[2] * surfacepants[2];
2603 ambientcolorshirt[0] = ambientcolorbase[0] * surfaceshirt[0];ambientcolorshirt[1] = ambientcolorbase[1] * surfaceshirt[1];ambientcolorshirt[2] = ambientcolorbase[2] * surfaceshirt[2];
2604 diffusecolorshirt[0] = diffusecolorbase[0] * surfaceshirt[0];diffusecolorshirt[1] = diffusecolorbase[1] * surfaceshirt[1];diffusecolorshirt[2] = diffusecolorbase[2] * surfaceshirt[2];
2605 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | (diffusescale > 0 ? BATCHNEED_ARRAY_NORMAL : 0) | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
2606 rsurface.passcolor4f = R_FrameData_Alloc((rsurface.batchfirstvertex + rsurface.batchnumvertices) * sizeof(float[4]));
2607 R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
2608 R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.passcolor4f, 0, 0);
2609 R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
2610 R_Mesh_TexBind(0, basetexture);
2611 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
2612 R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
2613 switch(r_shadow_rendermode)
2615 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2616 R_Mesh_TexBind(1, r_shadow_attenuation3dtexture);
2617 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
2618 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
2619 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
2621 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2622 R_Mesh_TexBind(2, r_shadow_attenuation2dtexture);
2623 R_Mesh_TexMatrix(2, &rsurface.entitytoattenuationz);
2624 R_Mesh_TexCombine(2, GL_MODULATE, GL_MODULATE, 1, 1);
2625 R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
2627 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2628 R_Mesh_TexBind(1, r_shadow_attenuation2dtexture);
2629 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
2630 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
2631 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
2633 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2638 //R_Mesh_TexBind(0, basetexture);
2639 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorbase, ambientcolorbase);
2642 R_Mesh_TexBind(0, pantstexture);
2643 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorpants, ambientcolorpants);
2647 R_Mesh_TexBind(0, shirttexture);
2648 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorshirt, ambientcolorshirt);
2652 extern cvar_t gl_lightmaps;
2653 void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
2655 float ambientscale, diffusescale, specularscale;
2657 float lightcolor[3];
2658 VectorCopy(rsurface.rtlight->currentcolor, lightcolor);
2659 ambientscale = rsurface.rtlight->ambientscale;
2660 diffusescale = rsurface.rtlight->diffusescale;
2661 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
2662 if (!r_shadow_usenormalmap.integer)
2664 ambientscale += 1.0f * diffusescale;
2668 if ((ambientscale + diffusescale) * VectorLength2(lightcolor) + specularscale * VectorLength2(lightcolor) < (1.0f / 1048576.0f))
2670 negated = (lightcolor[0] + lightcolor[1] + lightcolor[2] < 0) && vid.support.ext_blend_subtract;
2673 VectorNegate(lightcolor, lightcolor);
2674 switch(vid.renderpath)
2676 case RENDERPATH_GL11:
2677 case RENDERPATH_GL13:
2678 case RENDERPATH_GL20:
2679 case RENDERPATH_CGGL:
2680 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
2682 case RENDERPATH_D3D9:
2684 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_SUBTRACT);
2687 case RENDERPATH_D3D10:
2688 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2690 case RENDERPATH_D3D11:
2691 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2693 case RENDERPATH_SOFT:
2694 DPSOFTRAST_BlendSubtract(true);
2698 RSurf_SetupDepthAndCulling();
2699 switch (r_shadow_rendermode)
2701 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2702 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2703 R_Shadow_RenderLighting_VisibleLighting(texturenumsurfaces, texturesurfacelist);
2705 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2706 R_Shadow_RenderLighting_Light_GLSL(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale, specularscale);
2708 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2709 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2710 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2711 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2712 R_Shadow_RenderLighting_Light_Vertex(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale);
2715 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2720 switch(vid.renderpath)
2722 case RENDERPATH_GL11:
2723 case RENDERPATH_GL13:
2724 case RENDERPATH_GL20:
2725 case RENDERPATH_CGGL:
2726 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
2728 case RENDERPATH_D3D9:
2730 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_ADD);
2733 case RENDERPATH_D3D10:
2734 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2736 case RENDERPATH_D3D11:
2737 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2739 case RENDERPATH_SOFT:
2740 DPSOFTRAST_BlendSubtract(false);
2746 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)
2748 matrix4x4_t tempmatrix = *matrix;
2749 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
2751 // if this light has been compiled before, free the associated data
2752 R_RTLight_Uncompile(rtlight);
2754 // clear it completely to avoid any lingering data
2755 memset(rtlight, 0, sizeof(*rtlight));
2757 // copy the properties
2758 rtlight->matrix_lighttoworld = tempmatrix;
2759 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
2760 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
2761 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
2762 VectorCopy(color, rtlight->color);
2763 rtlight->cubemapname[0] = 0;
2764 if (cubemapname && cubemapname[0])
2765 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
2766 rtlight->shadow = shadow;
2767 rtlight->corona = corona;
2768 rtlight->style = style;
2769 rtlight->isstatic = isstatic;
2770 rtlight->coronasizescale = coronasizescale;
2771 rtlight->ambientscale = ambientscale;
2772 rtlight->diffusescale = diffusescale;
2773 rtlight->specularscale = specularscale;
2774 rtlight->flags = flags;
2776 // compute derived data
2777 //rtlight->cullradius = rtlight->radius;
2778 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2779 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2780 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2781 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2782 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2783 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2784 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2787 // compiles rtlight geometry
2788 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2789 void R_RTLight_Compile(rtlight_t *rtlight)
2792 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
2793 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
2794 entity_render_t *ent = r_refdef.scene.worldentity;
2795 dp_model_t *model = r_refdef.scene.worldmodel;
2796 unsigned char *data;
2799 // compile the light
2800 rtlight->compiled = true;
2801 rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
2802 rtlight->static_numleafs = 0;
2803 rtlight->static_numleafpvsbytes = 0;
2804 rtlight->static_leaflist = NULL;
2805 rtlight->static_leafpvs = NULL;
2806 rtlight->static_numsurfaces = 0;
2807 rtlight->static_surfacelist = NULL;
2808 rtlight->static_shadowmap_receivers = 0x3F;
2809 rtlight->static_shadowmap_casters = 0x3F;
2810 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2811 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2812 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2813 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2814 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2815 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2817 if (model && model->GetLightInfo)
2819 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
2820 r_shadow_compilingrtlight = rtlight;
2821 R_FrameData_SetMark();
2822 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);
2823 R_FrameData_ReturnToMark();
2824 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2825 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
2826 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
2827 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
2828 rtlight->static_numsurfaces = numsurfaces;
2829 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
2830 rtlight->static_numleafs = numleafs;
2831 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
2832 rtlight->static_numleafpvsbytes = numleafpvsbytes;
2833 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
2834 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
2835 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
2836 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
2837 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
2838 if (rtlight->static_numsurfaces)
2839 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
2840 if (rtlight->static_numleafs)
2841 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
2842 if (rtlight->static_numleafpvsbytes)
2843 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
2844 if (rtlight->static_numshadowtrispvsbytes)
2845 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
2846 if (rtlight->static_numlighttrispvsbytes)
2847 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
2848 R_FrameData_SetMark();
2849 switch (rtlight->shadowmode)
2851 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2852 if (model->CompileShadowMap && rtlight->shadow)
2853 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2856 if (model->CompileShadowVolume && rtlight->shadow)
2857 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2860 R_FrameData_ReturnToMark();
2861 // now we're done compiling the rtlight
2862 r_shadow_compilingrtlight = NULL;
2866 // use smallest available cullradius - box radius or light radius
2867 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2868 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2870 shadowzpasstris = 0;
2871 if (rtlight->static_meshchain_shadow_zpass)
2872 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
2873 shadowzpasstris += mesh->numtriangles;
2875 shadowzfailtris = 0;
2876 if (rtlight->static_meshchain_shadow_zfail)
2877 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
2878 shadowzfailtris += mesh->numtriangles;
2881 if (rtlight->static_numlighttrispvsbytes)
2882 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
2883 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
2887 if (rtlight->static_numlighttrispvsbytes)
2888 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
2889 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
2892 if (developer_extra.integer)
2893 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);
2896 void R_RTLight_Uncompile(rtlight_t *rtlight)
2898 if (rtlight->compiled)
2900 if (rtlight->static_meshchain_shadow_zpass)
2901 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
2902 rtlight->static_meshchain_shadow_zpass = NULL;
2903 if (rtlight->static_meshchain_shadow_zfail)
2904 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
2905 rtlight->static_meshchain_shadow_zfail = NULL;
2906 if (rtlight->static_meshchain_shadow_shadowmap)
2907 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
2908 rtlight->static_meshchain_shadow_shadowmap = NULL;
2909 // these allocations are grouped
2910 if (rtlight->static_surfacelist)
2911 Mem_Free(rtlight->static_surfacelist);
2912 rtlight->static_numleafs = 0;
2913 rtlight->static_numleafpvsbytes = 0;
2914 rtlight->static_leaflist = NULL;
2915 rtlight->static_leafpvs = NULL;
2916 rtlight->static_numsurfaces = 0;
2917 rtlight->static_surfacelist = NULL;
2918 rtlight->static_numshadowtrispvsbytes = 0;
2919 rtlight->static_shadowtrispvs = NULL;
2920 rtlight->static_numlighttrispvsbytes = 0;
2921 rtlight->static_lighttrispvs = NULL;
2922 rtlight->compiled = false;
2926 void R_Shadow_UncompileWorldLights(void)
2930 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
2931 for (lightindex = 0;lightindex < range;lightindex++)
2933 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
2936 R_RTLight_Uncompile(&light->rtlight);
2940 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
2944 // reset the count of frustum planes
2945 // see rtlight->cached_frustumplanes definition for how much this array
2947 rtlight->cached_numfrustumplanes = 0;
2949 // haven't implemented a culling path for ortho rendering
2950 if (!r_refdef.view.useperspective)
2952 // check if the light is on screen and copy the 4 planes if it is
2953 for (i = 0;i < 4;i++)
2954 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
2957 for (i = 0;i < 4;i++)
2958 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
2963 // generate a deformed frustum that includes the light origin, this is
2964 // used to cull shadow casting surfaces that can not possibly cast a
2965 // shadow onto the visible light-receiving surfaces, which can be a
2968 // if the light origin is onscreen the result will be 4 planes exactly
2969 // if the light origin is offscreen on only one axis the result will
2970 // be exactly 5 planes (split-side case)
2971 // if the light origin is offscreen on two axes the result will be
2972 // exactly 4 planes (stretched corner case)
2973 for (i = 0;i < 4;i++)
2975 // quickly reject standard frustum planes that put the light
2976 // origin outside the frustum
2977 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
2980 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
2982 // if all the standard frustum planes were accepted, the light is onscreen
2983 // otherwise we need to generate some more planes below...
2984 if (rtlight->cached_numfrustumplanes < 4)
2986 // at least one of the stock frustum planes failed, so we need to
2987 // create one or two custom planes to enclose the light origin
2988 for (i = 0;i < 4;i++)
2990 // create a plane using the view origin and light origin, and a
2991 // single point from the frustum corner set
2992 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
2993 VectorNormalize(plane.normal);
2994 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
2995 // see if this plane is backwards and flip it if so
2996 for (j = 0;j < 4;j++)
2997 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3001 VectorNegate(plane.normal, plane.normal);
3003 // flipped plane, test again to see if it is now valid
3004 for (j = 0;j < 4;j++)
3005 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3007 // if the plane is still not valid, then it is dividing the
3008 // frustum and has to be rejected
3012 // we have created a valid plane, compute extra info
3013 PlaneClassify(&plane);
3015 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3017 // if we've found 5 frustum planes then we have constructed a
3018 // proper split-side case and do not need to keep searching for
3019 // planes to enclose the light origin
3020 if (rtlight->cached_numfrustumplanes == 5)
3028 for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
3030 plane = rtlight->cached_frustumplanes[i];
3031 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));
3036 // now add the light-space box planes if the light box is rotated, as any
3037 // caster outside the oriented light box is irrelevant (even if it passed
3038 // the worldspace light box, which is axial)
3039 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3041 for (i = 0;i < 6;i++)
3045 v[i >> 1] = (i & 1) ? -1 : 1;
3046 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3047 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3048 plane.dist = VectorNormalizeLength(plane.normal);
3049 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3050 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3056 // add the world-space reduced box planes
3057 for (i = 0;i < 6;i++)
3059 VectorClear(plane.normal);
3060 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3061 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
3062 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3071 // reduce all plane distances to tightly fit the rtlight cull box, which
3073 VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3074 VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3075 VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3076 VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3077 VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3078 VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3079 VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3080 VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3081 oldnum = rtlight->cached_numfrustumplanes;
3082 rtlight->cached_numfrustumplanes = 0;
3083 for (j = 0;j < oldnum;j++)
3085 // find the nearest point on the box to this plane
3086 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
3087 for (i = 1;i < 8;i++)
3089 dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
3090 if (bestdist > dist)
3093 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);
3094 // if the nearest point is near or behind the plane, we want this
3095 // plane, otherwise the plane is useless as it won't cull anything
3096 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
3098 PlaneClassify(&rtlight->cached_frustumplanes[j]);
3099 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
3106 void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
3110 RSurf_ActiveWorldEntity();
3112 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3115 GL_CullFace(GL_NONE);
3116 mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3117 for (;mesh;mesh = mesh->next)
3119 if (!mesh->sidetotals[r_shadow_shadowmapside])
3121 r_refdef.stats.lights_shadowtriangles += mesh->sidetotals[r_shadow_shadowmapside];
3122 if (mesh->vertex3fbuffer)
3123 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vertex3fbuffer);
3125 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer);
3126 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);
3130 else if (r_refdef.scene.worldentity->model)
3131 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);
3133 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3136 void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3138 qboolean zpass = false;
3141 int surfacelistindex;
3142 msurface_t *surface;
3144 // if triangle neighbors are disabled, shadowvolumes are disabled
3145 if (r_refdef.scene.worldmodel->brush.shadowmesh ? !r_refdef.scene.worldmodel->brush.shadowmesh->neighbor3i : !r_refdef.scene.worldmodel->surfmesh.data_neighbor3i)
3148 RSurf_ActiveWorldEntity();
3150 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3153 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
3155 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
3156 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
3158 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
3159 for (;mesh;mesh = mesh->next)
3161 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
3162 if (mesh->vertex3fbuffer)
3163 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vertex3fbuffer);
3165 R_Mesh_PrepareVertices_Vertex3f(mesh->numverts, mesh->vertex3f, mesh->vbo_vertexbuffer);
3166 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
3168 // increment stencil if frontface is infront of depthbuffer
3169 GL_CullFace(r_refdef.view.cullface_back);
3170 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
3171 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);
3172 // decrement stencil if backface is infront of depthbuffer
3173 GL_CullFace(r_refdef.view.cullface_front);
3174 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
3176 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
3178 // decrement stencil if backface is behind depthbuffer
3179 GL_CullFace(r_refdef.view.cullface_front);
3180 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
3181 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);
3182 // increment stencil if frontface is behind depthbuffer
3183 GL_CullFace(r_refdef.view.cullface_back);
3184 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
3186 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);
3190 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh)
3192 // use the shadow trispvs calculated earlier by GetLightInfo to cull world triangles on this dynamic light
3193 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
3194 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
3196 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
3197 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
3198 if (CHECKPVSBIT(trispvs, t))
3199 shadowmarklist[numshadowmark++] = t;
3201 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);
3203 else if (numsurfaces)
3205 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);
3208 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3211 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3213 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3214 vec_t relativeshadowradius;
3215 RSurf_ActiveModelEntity(ent, false, false, false);
3216 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3217 // we need to re-init the shader for each entity because the matrix changed
3218 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3219 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3220 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3221 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3222 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3223 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3224 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3225 switch (r_shadow_rendermode)
3227 case R_SHADOW_RENDERMODE_SHADOWMAP2D:
3228 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
3231 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3234 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3237 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3239 // set up properties for rendering light onto this entity
3240 RSurf_ActiveModelEntity(ent, true, true, false);
3241 GL_AlphaTest(false);
3242 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3243 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3244 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3245 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3248 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
3250 if (!r_refdef.scene.worldmodel->DrawLight)
3253 // set up properties for rendering light onto this entity
3254 RSurf_ActiveWorldEntity();
3255 GL_AlphaTest(false);
3256 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3257 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3258 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3259 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3261 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
3263 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3266 void R_Shadow_DrawEntityLight(entity_render_t *ent)
3268 dp_model_t *model = ent->model;
3269 if (!model->DrawLight)
3272 R_Shadow_SetupEntityLight(ent);
3274 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3276 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3279 void R_Shadow_PrepareLight(rtlight_t *rtlight)
3283 int numleafs, numsurfaces;
3284 int *leaflist, *surfacelist;
3285 unsigned char *leafpvs;
3286 unsigned char *shadowtrispvs;
3287 unsigned char *lighttrispvs;
3288 //unsigned char *surfacesides;
3289 int numlightentities;
3290 int numlightentities_noselfshadow;
3291 int numshadowentities;
3292 int numshadowentities_noselfshadow;
3293 static entity_render_t *lightentities[MAX_EDICTS];
3294 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3295 static entity_render_t *shadowentities[MAX_EDICTS];
3296 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3299 rtlight->draw = false;
3301 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3302 // skip lights that are basically invisible (color 0 0 0)
3303 nolight = VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f);
3305 // loading is done before visibility checks because loading should happen
3306 // all at once at the start of a level, not when it stalls gameplay.
3307 // (especially important to benchmarks)
3309 if (rtlight->isstatic && !nolight && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
3311 if (rtlight->compiled)
3312 R_RTLight_Uncompile(rtlight);
3313 R_RTLight_Compile(rtlight);
3317 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
3319 // look up the light style value at this time
3320 f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3321 VectorScale(rtlight->color, f, rtlight->currentcolor);
3323 if (rtlight->selected)
3325 f = 2 + sin(realtime * M_PI * 4.0);
3326 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3330 // if lightstyle is currently off, don't draw the light
3331 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3334 // skip processing on corona-only lights
3338 // if the light box is offscreen, skip it
3339 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3342 VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
3343 VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
3345 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3347 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3349 // compiled light, world available and can receive realtime lighting
3350 // retrieve leaf information
3351 numleafs = rtlight->static_numleafs;
3352 leaflist = rtlight->static_leaflist;
3353 leafpvs = rtlight->static_leafpvs;
3354 numsurfaces = rtlight->static_numsurfaces;
3355 surfacelist = rtlight->static_surfacelist;
3356 //surfacesides = NULL;
3357 shadowtrispvs = rtlight->static_shadowtrispvs;
3358 lighttrispvs = rtlight->static_lighttrispvs;
3360 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3362 // dynamic light, world available and can receive realtime lighting
3363 // calculate lit surfaces and leafs
3364 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);
3365 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3366 leaflist = r_shadow_buffer_leaflist;
3367 leafpvs = r_shadow_buffer_leafpvs;
3368 surfacelist = r_shadow_buffer_surfacelist;
3369 //surfacesides = r_shadow_buffer_surfacesides;
3370 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3371 lighttrispvs = r_shadow_buffer_lighttrispvs;
3372 // if the reduced leaf bounds are offscreen, skip it
3373 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3384 //surfacesides = NULL;
3385 shadowtrispvs = NULL;
3386 lighttrispvs = NULL;
3388 // check if light is illuminating any visible leafs
3391 for (i = 0;i < numleafs;i++)
3392 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3398 // make a list of lit entities and shadow casting entities
3399 numlightentities = 0;
3400 numlightentities_noselfshadow = 0;
3401 numshadowentities = 0;
3402 numshadowentities_noselfshadow = 0;
3404 // add dynamic entities that are lit by the light
3405 for (i = 0;i < r_refdef.scene.numentities;i++)
3408 entity_render_t *ent = r_refdef.scene.entities[i];
3410 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3412 // skip the object entirely if it is not within the valid
3413 // shadow-casting region (which includes the lit region)
3414 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
3416 if (!(model = ent->model))
3418 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
3420 // this entity wants to receive light, is visible, and is
3421 // inside the light box
3422 // TODO: check if the surfaces in the model can receive light
3423 // so now check if it's in a leaf seen by the light
3424 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))
3426 if (ent->flags & RENDER_NOSELFSHADOW)
3427 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
3429 lightentities[numlightentities++] = ent;
3430 // since it is lit, it probably also casts a shadow...
3431 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3432 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3433 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3435 // note: exterior models without the RENDER_NOSELFSHADOW
3436 // flag still create a RENDER_NOSELFSHADOW shadow but
3437 // are lit normally, this means that they are
3438 // self-shadowing but do not shadow other
3439 // RENDER_NOSELFSHADOW entities such as the gun
3440 // (very weird, but keeps the player shadow off the gun)
3441 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3442 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3444 shadowentities[numshadowentities++] = ent;
3447 else if (ent->flags & RENDER_SHADOW)
3449 // this entity is not receiving light, but may still need to
3451 // TODO: check if the surfaces in the model can cast shadow
3452 // now check if it is in a leaf seen by the light
3453 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))
3455 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3456 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3457 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3459 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3460 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3462 shadowentities[numshadowentities++] = ent;
3467 // return if there's nothing at all to light
3468 if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
3471 // count this light in the r_speeds
3472 r_refdef.stats.lights++;
3474 // flag it as worth drawing later
3475 rtlight->draw = true;
3477 // cache all the animated entities that cast a shadow but are not visible
3478 for (i = 0;i < numshadowentities;i++)
3479 if (!shadowentities[i]->animcache_vertex3f)
3480 R_AnimCache_GetEntity(shadowentities[i], false, false);
3481 for (i = 0;i < numshadowentities_noselfshadow;i++)
3482 if (!shadowentities_noselfshadow[i]->animcache_vertex3f)
3483 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
3485 // allocate some temporary memory for rendering this light later in the frame
3486 // reusable buffers need to be copied, static data can be used as-is
3487 rtlight->cached_numlightentities = numlightentities;
3488 rtlight->cached_numlightentities_noselfshadow = numlightentities_noselfshadow;
3489 rtlight->cached_numshadowentities = numshadowentities;
3490 rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
3491 rtlight->cached_numsurfaces = numsurfaces;
3492 rtlight->cached_lightentities = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
3493 rtlight->cached_lightentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
3494 rtlight->cached_shadowentities = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
3495 rtlight->cached_shadowentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
3496 if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
3498 int numshadowtrispvsbytes = (((r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles) + 7) >> 3);
3499 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
3500 rtlight->cached_shadowtrispvs = (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
3501 rtlight->cached_lighttrispvs = (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
3502 rtlight->cached_surfacelist = (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
3506 // compiled light data
3507 rtlight->cached_shadowtrispvs = shadowtrispvs;
3508 rtlight->cached_lighttrispvs = lighttrispvs;
3509 rtlight->cached_surfacelist = surfacelist;
3513 void R_Shadow_DrawLight(rtlight_t *rtlight)
3517 unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
3518 int numlightentities;
3519 int numlightentities_noselfshadow;
3520 int numshadowentities;
3521 int numshadowentities_noselfshadow;
3522 entity_render_t **lightentities;
3523 entity_render_t **lightentities_noselfshadow;
3524 entity_render_t **shadowentities;
3525 entity_render_t **shadowentities_noselfshadow;
3527 static unsigned char entitysides[MAX_EDICTS];
3528 static unsigned char entitysides_noselfshadow[MAX_EDICTS];
3529 vec3_t nearestpoint;
3531 qboolean castshadows;
3534 // check if we cached this light this frame (meaning it is worth drawing)
3538 numlightentities = rtlight->cached_numlightentities;
3539 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
3540 numshadowentities = rtlight->cached_numshadowentities;
3541 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
3542 numsurfaces = rtlight->cached_numsurfaces;
3543 lightentities = rtlight->cached_lightentities;
3544 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
3545 shadowentities = rtlight->cached_shadowentities;
3546 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
3547 shadowtrispvs = rtlight->cached_shadowtrispvs;
3548 lighttrispvs = rtlight->cached_lighttrispvs;
3549 surfacelist = rtlight->cached_surfacelist;
3551 // set up a scissor rectangle for this light
3552 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3555 // don't let sound skip if going slow
3556 if (r_refdef.scene.extraupdate)
3559 // make this the active rtlight for rendering purposes
3560 R_Shadow_RenderMode_ActiveLight(rtlight);
3562 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
3564 // optionally draw visible shape of the shadow volumes
3565 // for performance analysis by level designers
3566 R_Shadow_RenderMode_VisibleShadowVolumes();
3568 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
3569 for (i = 0;i < numshadowentities;i++)
3570 R_Shadow_DrawEntityShadow(shadowentities[i]);
3571 for (i = 0;i < numshadowentities_noselfshadow;i++)
3572 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3573 R_Shadow_RenderMode_VisibleLighting(false, false);
3576 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
3578 // optionally draw the illuminated areas
3579 // for performance analysis by level designers
3580 R_Shadow_RenderMode_VisibleLighting(false, false);
3582 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3583 for (i = 0;i < numlightentities;i++)
3584 R_Shadow_DrawEntityLight(lightentities[i]);
3585 for (i = 0;i < numlightentities_noselfshadow;i++)
3586 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3589 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
3591 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
3592 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
3593 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
3594 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
3596 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance/rtlight->radius));
3597 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
3598 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
3600 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
3606 int receivermask = 0;
3607 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
3608 Matrix4x4_Abs(&radiustolight);
3610 r_shadow_shadowmaplod = 0;
3611 for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
3612 if ((r_shadow_shadowmapmaxsize >> i) > lodlinear)
3613 r_shadow_shadowmaplod = i;
3615 size = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
3617 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
3619 surfacesides = NULL;
3622 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3624 castermask = rtlight->static_shadowmap_casters;
3625 receivermask = rtlight->static_shadowmap_receivers;
3629 surfacesides = r_shadow_buffer_surfacesides;
3630 for(i = 0;i < numsurfaces;i++)
3632 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
3633 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3634 castermask |= surfacesides[i];
3635 receivermask |= surfacesides[i];
3639 if (receivermask < 0x3F)
3641 for (i = 0;i < numlightentities;i++)
3642 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3643 if (receivermask < 0x3F)
3644 for(i = 0; i < numlightentities_noselfshadow;i++)
3645 receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3648 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
3652 for (i = 0;i < numshadowentities;i++)
3653 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3654 for (i = 0;i < numshadowentities_noselfshadow;i++)
3655 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3658 //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
3660 // render shadow casters into 6 sided depth texture
3661 for (side = 0;side < 6;side++) if (receivermask & (1 << side))
3663 R_Shadow_RenderMode_ShadowMap(side, receivermask, size);
3664 if (! (castermask & (1 << side))) continue;
3666 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
3667 for (i = 0;i < numshadowentities;i++) if (entitysides[i] & (1 << side))
3668 R_Shadow_DrawEntityShadow(shadowentities[i]);
3671 if (numlightentities_noselfshadow)
3673 // render lighting using the depth texture as shadowmap
3674 // draw lighting in the unmasked areas
3675 R_Shadow_RenderMode_Lighting(false, false, true);
3676 for (i = 0;i < numlightentities_noselfshadow;i++)
3677 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3680 // render shadow casters into 6 sided depth texture
3681 if (numshadowentities_noselfshadow)
3683 for (side = 0;side < 6;side++) if ((receivermask & castermask) & (1 << side))
3685 R_Shadow_RenderMode_ShadowMap(side, 0, size);
3686 for (i = 0;i < numshadowentities_noselfshadow;i++) if (entitysides_noselfshadow[i] & (1 << side))
3687 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3691 // render lighting using the depth texture as shadowmap
3692 // draw lighting in the unmasked areas
3693 R_Shadow_RenderMode_Lighting(false, false, true);
3694 // draw lighting in the unmasked areas
3696 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3697 for (i = 0;i < numlightentities;i++)
3698 R_Shadow_DrawEntityLight(lightentities[i]);
3700 else if (castshadows && vid.stencil)
3702 // draw stencil shadow volumes to mask off pixels that are in shadow
3703 // so that they won't receive lighting
3704 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
3705 R_Shadow_ClearStencil();
3708 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
3709 for (i = 0;i < numshadowentities;i++)
3710 R_Shadow_DrawEntityShadow(shadowentities[i]);
3712 // draw lighting in the unmasked areas
3713 R_Shadow_RenderMode_Lighting(true, false, false);
3714 for (i = 0;i < numlightentities_noselfshadow;i++)
3715 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3717 for (i = 0;i < numshadowentities_noselfshadow;i++)
3718 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3720 // draw lighting in the unmasked areas
3721 R_Shadow_RenderMode_Lighting(true, false, false);
3723 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3724 for (i = 0;i < numlightentities;i++)
3725 R_Shadow_DrawEntityLight(lightentities[i]);
3729 // draw lighting in the unmasked areas
3730 R_Shadow_RenderMode_Lighting(false, false, false);
3732 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3733 for (i = 0;i < numlightentities;i++)
3734 R_Shadow_DrawEntityLight(lightentities[i]);
3735 for (i = 0;i < numlightentities_noselfshadow;i++)
3736 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3739 if (r_shadow_usingdeferredprepass)
3741 // when rendering deferred lighting, we simply rasterize the box
3742 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
3743 R_Shadow_RenderMode_DrawDeferredLight(false, true);
3744 else if (castshadows && vid.stencil)
3745 R_Shadow_RenderMode_DrawDeferredLight(true, false);
3747 R_Shadow_RenderMode_DrawDeferredLight(false, false);
3751 static void R_Shadow_FreeDeferred(void)
3753 R_Mesh_DestroyFramebufferObject(r_shadow_prepassgeometryfbo);
3754 r_shadow_prepassgeometryfbo = 0;
3756 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingfbo);
3757 r_shadow_prepasslightingfbo = 0;
3759 if (r_shadow_prepassgeometrydepthtexture)
3760 R_FreeTexture(r_shadow_prepassgeometrydepthtexture);
3761 r_shadow_prepassgeometrydepthtexture = NULL;
3763 if (r_shadow_prepassgeometrydepthcolortexture)
3764 R_FreeTexture(r_shadow_prepassgeometrydepthcolortexture);
3765 r_shadow_prepassgeometrydepthcolortexture = NULL;
3767 if (r_shadow_prepassgeometrynormalmaptexture)
3768 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
3769 r_shadow_prepassgeometrynormalmaptexture = NULL;
3771 if (r_shadow_prepasslightingdiffusetexture)
3772 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
3773 r_shadow_prepasslightingdiffusetexture = NULL;
3775 if (r_shadow_prepasslightingspeculartexture)
3776 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
3777 r_shadow_prepasslightingspeculartexture = NULL;
3780 void R_Shadow_DrawPrepass(void)
3788 entity_render_t *ent;
3789 float clearcolor[4];
3791 GL_AlphaTest(false);
3792 R_Mesh_ResetTextureState();
3794 GL_ColorMask(1,1,1,1);
3795 GL_BlendFunc(GL_ONE, GL_ZERO);
3798 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, r_shadow_prepassgeometrydepthcolortexture, NULL, NULL);
3799 Vector4Set(clearcolor, 0.5f,0.5f,0.5f,1.0f);
3800 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
3801 if (r_timereport_active)
3802 R_TimeReport("prepasscleargeom");
3804 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
3805 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
3806 if (r_timereport_active)
3807 R_TimeReport("prepassworld");
3809 for (i = 0;i < r_refdef.scene.numentities;i++)
3811 if (!r_refdef.viewcache.entityvisible[i])
3813 ent = r_refdef.scene.entities[i];
3814 if (ent->model && ent->model->DrawPrepass != NULL)
3815 ent->model->DrawPrepass(ent);
3818 if (r_timereport_active)
3819 R_TimeReport("prepassmodels");
3821 GL_DepthMask(false);
3822 GL_ColorMask(1,1,1,1);
3825 R_Mesh_SetRenderTargets(r_shadow_prepasslightingfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
3826 Vector4Set(clearcolor, 0, 0, 0, 0);
3827 GL_Clear(GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
3828 if (r_timereport_active)
3829 R_TimeReport("prepassclearlit");
3831 R_Shadow_RenderMode_Begin();
3833 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3834 if (r_shadow_debuglight.integer >= 0)
3836 lightindex = r_shadow_debuglight.integer;
3837 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3838 if (light && (light->flags & flag) && light->rtlight.draw)
3839 R_Shadow_DrawLight(&light->rtlight);
3843 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3844 for (lightindex = 0;lightindex < range;lightindex++)
3846 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3847 if (light && (light->flags & flag) && light->rtlight.draw)
3848 R_Shadow_DrawLight(&light->rtlight);
3851 if (r_refdef.scene.rtdlight)
3852 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
3853 if (r_refdef.scene.lights[lnum]->draw)
3854 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
3856 R_Mesh_ResetRenderTargets();
3858 R_Shadow_RenderMode_End();
3860 if (r_timereport_active)
3861 R_TimeReport("prepasslights");
3864 void R_Shadow_DrawLightSprites(void);
3865 void R_Shadow_PrepareLights(void)
3875 if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4) ||
3876 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
3877 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20) ||
3878 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
3879 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
3880 r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
3881 R_Shadow_FreeShadowMaps();
3883 r_shadow_usingshadowmaportho = false;
3885 switch (vid.renderpath)
3887 case RENDERPATH_GL20:
3888 case RENDERPATH_CGGL:
3889 case RENDERPATH_D3D9:
3890 case RENDERPATH_D3D10:
3891 case RENDERPATH_D3D11:
3892 case RENDERPATH_SOFT:
3893 if (!r_shadow_deferred.integer || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_STENCIL || !vid.support.ext_framebuffer_object || vid.maxdrawbuffers < 2)
3895 r_shadow_usingdeferredprepass = false;
3896 if (r_shadow_prepass_width)
3897 R_Shadow_FreeDeferred();
3898 r_shadow_prepass_width = r_shadow_prepass_height = 0;
3902 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
3904 R_Shadow_FreeDeferred();
3906 r_shadow_usingdeferredprepass = true;
3907 r_shadow_prepass_width = vid.width;
3908 r_shadow_prepass_height = vid.height;
3909 r_shadow_prepassgeometrydepthtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "prepassgeometrydepthmap", vid.width, vid.height, 24, false);
3910 switch (vid.renderpath)
3912 case RENDERPATH_D3D9:
3913 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);
3918 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);
3919 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);
3920 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);
3922 // set up the geometry pass fbo (depth + normalmap)
3923 r_shadow_prepassgeometryfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
3924 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, r_shadow_prepassgeometrydepthcolortexture, NULL, NULL);
3925 // render depth into one texture and normalmap into the other
3926 if (qglDrawBuffersARB)
3928 qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);CHECKGLERROR
3929 qglReadBuffer(GL_NONE);CHECKGLERROR
3930 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
3931 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
3933 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
3934 Cvar_SetValueQuick(&r_shadow_deferred, 0);
3935 r_shadow_usingdeferredprepass = false;
3939 // set up the lighting pass fbo (diffuse + specular)
3940 r_shadow_prepasslightingfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
3941 R_Mesh_SetRenderTargets(r_shadow_prepasslightingfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
3942 // render diffuse into one texture and specular into another,
3943 // with depth and normalmap bound as textures,
3944 // with depth bound as attachment as well
3945 if (qglDrawBuffersARB)
3947 qglDrawBuffersARB(2, r_shadow_prepasslightingdrawbuffers);CHECKGLERROR
3948 qglReadBuffer(GL_NONE);CHECKGLERROR
3949 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
3950 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
3952 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
3953 Cvar_SetValueQuick(&r_shadow_deferred, 0);
3954 r_shadow_usingdeferredprepass = false;
3959 case RENDERPATH_GL13:
3960 case RENDERPATH_GL11:
3961 r_shadow_usingdeferredprepass = false;
3965 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);
3967 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3968 if (r_shadow_debuglight.integer >= 0)
3970 lightindex = r_shadow_debuglight.integer;
3971 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3972 if (light && (light->flags & flag))
3973 R_Shadow_PrepareLight(&light->rtlight);
3977 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3978 for (lightindex = 0;lightindex < range;lightindex++)
3980 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3981 if (light && (light->flags & flag))
3982 R_Shadow_PrepareLight(&light->rtlight);
3985 if (r_refdef.scene.rtdlight)
3987 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
3988 R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
3990 else if(gl_flashblend.integer)
3992 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
3994 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
3995 f = (rtlight->style >= 0 ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3996 VectorScale(rtlight->color, f, rtlight->currentcolor);
4000 if (r_editlights.integer)
4001 R_Shadow_DrawLightSprites();
4004 void R_Shadow_DrawLights(void)
4012 R_Shadow_RenderMode_Begin();
4014 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4015 if (r_shadow_debuglight.integer >= 0)
4017 lightindex = r_shadow_debuglight.integer;
4018 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4019 if (light && (light->flags & flag))
4020 R_Shadow_DrawLight(&light->rtlight);
4024 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4025 for (lightindex = 0;lightindex < range;lightindex++)
4027 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4028 if (light && (light->flags & flag))
4029 R_Shadow_DrawLight(&light->rtlight);
4032 if (r_refdef.scene.rtdlight)
4033 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4034 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4036 R_Shadow_RenderMode_End();
4039 extern const float r_screenvertex3f[12];
4040 extern void R_SetupView(qboolean allowwaterclippingplane);
4041 extern void R_ResetViewRendering3D(void);
4042 extern void R_ResetViewRendering2D(void);
4043 extern cvar_t r_shadows;
4044 extern cvar_t r_shadows_darken;
4045 extern cvar_t r_shadows_drawafterrtlighting;
4046 extern cvar_t r_shadows_castfrombmodels;
4047 extern cvar_t r_shadows_throwdistance;
4048 extern cvar_t r_shadows_throwdirection;
4049 extern cvar_t r_shadows_focus;
4050 extern cvar_t r_shadows_shadowmapscale;
4052 void R_Shadow_PrepareModelShadows(void)
4055 float scale, size, radius, dot1, dot2;
4056 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
4057 entity_render_t *ent;
4059 if (!r_refdef.scene.numentities)
4062 switch (r_shadow_shadowmode)
4064 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4065 if (r_shadows.integer >= 2)
4068 case R_SHADOW_SHADOWMODE_STENCIL:
4069 for (i = 0;i < r_refdef.scene.numentities;i++)
4071 ent = r_refdef.scene.entities[i];
4072 if (!ent->animcache_vertex3f && ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4073 R_AnimCache_GetEntity(ent, false, false);
4080 size = 2*r_shadow_shadowmapmaxsize;
4081 scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
4082 radius = 0.5f * size / scale;
4084 Math_atov(r_shadows_throwdirection.string, shadowdir);
4085 VectorNormalize(shadowdir);
4086 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4087 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4088 if (fabs(dot1) <= fabs(dot2))
4089 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4091 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4092 VectorNormalize(shadowforward);
4093 CrossProduct(shadowdir, shadowforward, shadowright);
4094 Math_atov(r_shadows_focus.string, shadowfocus);
4095 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4096 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4097 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4098 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4099 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4101 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4103 shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4104 shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4105 shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4106 shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4107 shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4108 shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4110 for (i = 0;i < r_refdef.scene.numentities;i++)
4112 ent = r_refdef.scene.entities[i];
4113 if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
4115 // cast shadows from anything of the map (submodels are optional)
4116 if (!ent->animcache_vertex3f && ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4117 R_AnimCache_GetEntity(ent, false, false);
4121 void R_DrawModelShadowMaps(void)
4124 float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
4125 entity_render_t *ent;
4126 vec3_t relativelightorigin;
4127 vec3_t relativelightdirection, relativeforward, relativeright;
4128 vec3_t relativeshadowmins, relativeshadowmaxs;
4129 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
4131 matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
4132 r_viewport_t viewport;
4134 float clearcolor[4];
4136 if (!r_refdef.scene.numentities)
4139 switch (r_shadow_shadowmode)
4141 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4147 R_ResetViewRendering3D();
4148 R_Shadow_RenderMode_Begin();
4149 R_Shadow_RenderMode_ActiveLight(NULL);
4151 switch (r_shadow_shadowmode)
4153 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4154 if (!r_shadow_shadowmap2dtexture)
4155 R_Shadow_MakeShadowMap(0, r_shadow_shadowmapmaxsize);
4156 fbo = r_shadow_fbo2d;
4157 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
4158 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
4159 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
4165 size = 2*r_shadow_shadowmapmaxsize;
4166 scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
4167 radius = 0.5f / scale;
4168 nearclip = -r_shadows_throwdistance.value;
4169 farclip = r_shadows_throwdistance.value;
4170 bias = r_shadow_shadowmapping_bias.value * r_shadow_shadowmapping_nearclip.value / (2 * r_shadows_throwdistance.value) * (1024.0f / size);
4172 r_shadow_shadowmap_parameters[0] = size;
4173 r_shadow_shadowmap_parameters[1] = size;
4174 r_shadow_shadowmap_parameters[2] = 1.0;
4175 r_shadow_shadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
4177 Math_atov(r_shadows_throwdirection.string, shadowdir);
4178 VectorNormalize(shadowdir);
4179 Math_atov(r_shadows_focus.string, shadowfocus);
4180 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4181 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4182 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4183 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4184 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4185 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4186 if (fabs(dot1) <= fabs(dot2))
4187 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4189 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4190 VectorNormalize(shadowforward);
4191 VectorM(scale, shadowforward, &m[0]);
4192 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4194 m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
4195 CrossProduct(shadowdir, shadowforward, shadowright);
4196 VectorM(scale, shadowright, &m[4]);
4197 m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
4198 VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
4199 m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
4200 Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
4201 Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
4202 R_Viewport_InitOrtho(&viewport, &cameramatrix, 0, 0, size, size, 0, 0, 1, 1, 0, -1, NULL);
4204 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4206 R_Mesh_SetRenderTargets(fbo, r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
4207 R_SetupShader_DepthOrShadow();
4208 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
4211 R_SetViewport(&viewport);
4212 GL_Scissor(viewport.x, viewport.y, min(viewport.width + r_shadow_shadowmapborder, 2*r_shadow_shadowmapmaxsize), viewport.height + r_shadow_shadowmapborder);
4213 Vector4Set(clearcolor, 1,1,1,1);
4214 // in D3D9 we have to render to a color texture shadowmap
4215 // in GL we render directly to a depth texture only
4216 if (r_shadow_shadowmap2dtexture)
4217 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4219 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4220 // render into a slightly restricted region so that the borders of the
4221 // shadowmap area fade away, rather than streaking across everything
4222 // outside the usable area
4223 GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
4227 R_Mesh_ResetRenderTargets();
4228 R_SetupShader_ShowDepth();
4229 GL_ColorMask(1,1,1,1);
4230 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4233 for (i = 0;i < r_refdef.scene.numentities;i++)
4235 ent = r_refdef.scene.entities[i];
4237 // cast shadows from anything of the map (submodels are optional)
4238 if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4240 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4241 Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
4242 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4243 Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
4244 Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
4245 relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4246 relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4247 relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4248 relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4249 relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4250 relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4251 RSurf_ActiveModelEntity(ent, false, false, false);
4252 ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
4253 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4260 unsigned char *rawpixels = Z_Malloc(viewport.width*viewport.height*4);
4262 qglReadPixels(viewport.x, viewport.y, viewport.width, viewport.height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, rawpixels);
4264 Image_WriteTGABGRA("r_shadows_2.tga", viewport.width, viewport.height, rawpixels);
4265 Cvar_SetValueQuick(&r_test, 0);
4270 R_Shadow_RenderMode_End();
4272 Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
4273 Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
4274 Matrix4x4_CreateScale3(&scalematrix, size, -size, 1);
4275 Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
4276 Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
4277 Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
4279 switch (vid.renderpath)
4281 case RENDERPATH_GL11:
4282 case RENDERPATH_GL13:
4283 case RENDERPATH_GL20:
4284 case RENDERPATH_CGGL:
4285 case RENDERPATH_SOFT:
4287 case RENDERPATH_D3D9:
4288 case RENDERPATH_D3D10:
4289 case RENDERPATH_D3D11:
4290 #ifdef OPENGL_ORIENTATION
4291 r_shadow_shadowmapmatrix.m[0][0] *= -1.0f;
4292 r_shadow_shadowmapmatrix.m[0][1] *= -1.0f;
4293 r_shadow_shadowmapmatrix.m[0][2] *= -1.0f;
4294 r_shadow_shadowmapmatrix.m[0][3] *= -1.0f;
4296 r_shadow_shadowmapmatrix.m[0][0] *= -1.0f;
4297 r_shadow_shadowmapmatrix.m[1][0] *= -1.0f;
4298 r_shadow_shadowmapmatrix.m[2][0] *= -1.0f;
4299 r_shadow_shadowmapmatrix.m[3][0] *= -1.0f;
4304 r_shadow_usingshadowmaportho = true;
4305 switch (r_shadow_shadowmode)
4307 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4308 r_shadow_usingshadowmap2d = true;
4315 void R_DrawModelShadows(void)
4318 float relativethrowdistance;
4319 entity_render_t *ent;
4320 vec3_t relativelightorigin;
4321 vec3_t relativelightdirection;
4322 vec3_t relativeshadowmins, relativeshadowmaxs;
4323 vec3_t tmp, shadowdir;
4325 if (!r_refdef.scene.numentities || !vid.stencil || (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL && r_shadows.integer != 1))
4328 R_ResetViewRendering3D();
4329 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4330 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4331 R_Shadow_RenderMode_Begin();
4332 R_Shadow_RenderMode_ActiveLight(NULL);
4333 r_shadow_lightscissor[0] = r_refdef.view.x;
4334 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
4335 r_shadow_lightscissor[2] = r_refdef.view.width;
4336 r_shadow_lightscissor[3] = r_refdef.view.height;
4337 R_Shadow_RenderMode_StencilShadowVolumes(false);
4340 if (r_shadows.integer == 2)
4342 Math_atov(r_shadows_throwdirection.string, shadowdir);
4343 VectorNormalize(shadowdir);
4346 R_Shadow_ClearStencil();
4348 for (i = 0;i < r_refdef.scene.numentities;i++)
4350 ent = r_refdef.scene.entities[i];
4352 // cast shadows from anything of the map (submodels are optional)
4353 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4355 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4356 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
4357 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
4358 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
4359 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4362 if(ent->entitynumber != 0)
4364 if(ent->entitynumber >= MAX_EDICTS) // csqc entity
4366 // FIXME handle this
4367 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4371 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
4372 int entnum, entnum2, recursion;
4373 entnum = entnum2 = ent->entitynumber;
4374 for(recursion = 32; recursion > 0; --recursion)
4376 entnum2 = cl.entities[entnum].state_current.tagentity;
4377 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
4382 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
4384 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
4385 // transform into modelspace of OUR entity
4386 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
4387 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
4390 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4394 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4397 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
4398 RSurf_ActiveModelEntity(ent, false, false, false);
4399 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4400 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4404 // not really the right mode, but this will disable any silly stencil features
4405 R_Shadow_RenderMode_End();
4407 // set up ortho view for rendering this pass
4408 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4409 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4410 //GL_ScissorTest(true);
4411 //R_EntityMatrix(&identitymatrix);
4412 //R_Mesh_ResetTextureState();
4413 R_ResetViewRendering2D();
4415 // set up a darkening blend on shadowed areas
4416 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4417 //GL_DepthRange(0, 1);
4418 //GL_DepthTest(false);
4419 //GL_DepthMask(false);
4420 //GL_PolygonOffset(0, 0);CHECKGLERROR
4421 GL_Color(0, 0, 0, r_shadows_darken.value);
4422 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4423 //GL_DepthFunc(GL_ALWAYS);
4424 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_NOTEQUAL, 128, 255);
4426 // apply the blend to the shadowed areas
4427 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, NULL);
4428 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
4429 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4431 // restore the viewport
4432 R_SetViewport(&r_refdef.view.viewport);
4434 // restore other state to normal
4435 //R_Shadow_RenderMode_End();
4438 void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4441 vec3_t centerorigin;
4443 // if it's too close, skip it
4444 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
4446 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4449 if (usequery && r_numqueries + 2 <= r_maxqueries)
4451 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4452 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4453 // 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
4454 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4456 switch(vid.renderpath)
4458 case RENDERPATH_GL20:
4459 case RENDERPATH_GL13:
4460 case RENDERPATH_GL11:
4461 case RENDERPATH_CGGL:
4463 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use GL_DepthFunc instead
4464 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
4465 GL_DepthFunc(GL_ALWAYS);
4466 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4467 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL);
4468 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4469 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4470 GL_DepthFunc(GL_LEQUAL);
4471 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
4472 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4473 R_Mesh_PrepareVertices_Vertex3f(4, vertex3f, NULL);
4474 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4475 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4478 case RENDERPATH_D3D9:
4479 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4481 case RENDERPATH_D3D10:
4482 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4484 case RENDERPATH_D3D11:
4485 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4487 case RENDERPATH_SOFT:
4488 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4492 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4495 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
4497 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4500 GLint allpixels = 0, visiblepixels = 0;
4501 // now we have to check the query result
4502 if (rtlight->corona_queryindex_visiblepixels)
4504 switch(vid.renderpath)
4506 case RENDERPATH_GL20:
4507 case RENDERPATH_GL13:
4508 case RENDERPATH_GL11:
4509 case RENDERPATH_CGGL:
4511 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
4512 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
4515 case RENDERPATH_D3D9:
4516 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4518 case RENDERPATH_D3D10:
4519 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4521 case RENDERPATH_D3D11:
4522 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4524 case RENDERPATH_SOFT:
4525 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4528 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
4529 if (visiblepixels < 1 || allpixels < 1)
4531 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
4532 cscale *= rtlight->corona_visibility;
4536 // FIXME: these traces should scan all render entities instead of cl.world
4537 if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
4540 VectorScale(rtlight->currentcolor, cscale, color);
4541 if (VectorLength(color) > (1.0f / 256.0f))
4544 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
4547 VectorNegate(color, color);
4548 switch(vid.renderpath)
4550 case RENDERPATH_GL11:
4551 case RENDERPATH_GL13:
4552 case RENDERPATH_GL20:
4553 case RENDERPATH_CGGL:
4554 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
4556 case RENDERPATH_D3D9:
4558 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_SUBTRACT);
4561 case RENDERPATH_D3D10:
4562 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4564 case RENDERPATH_D3D11:
4565 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4567 case RENDERPATH_SOFT:
4568 DPSOFTRAST_BlendSubtract(true);
4572 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4573 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);
4574 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4577 switch(vid.renderpath)
4579 case RENDERPATH_GL11:
4580 case RENDERPATH_GL13:
4581 case RENDERPATH_GL20:
4582 case RENDERPATH_CGGL:
4583 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
4585 case RENDERPATH_D3D9:
4587 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_ADD);
4590 case RENDERPATH_D3D10:
4591 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4593 case RENDERPATH_D3D11:
4594 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4596 case RENDERPATH_SOFT:
4597 DPSOFTRAST_BlendSubtract(false);
4604 void R_Shadow_DrawCoronas(void)
4607 qboolean usequery = false;
4612 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4614 if (r_waterstate.renderingscene)
4616 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4617 R_EntityMatrix(&identitymatrix);
4619 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4621 // check occlusion of coronas
4622 // use GL_ARB_occlusion_query if available
4623 // otherwise use raytraces
4625 switch (vid.renderpath)
4627 case RENDERPATH_GL11:
4628 case RENDERPATH_GL13:
4629 case RENDERPATH_GL20:
4630 case RENDERPATH_CGGL:
4631 usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
4634 GL_ColorMask(0,0,0,0);
4635 if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
4636 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
4639 r_maxqueries = (range + r_refdef.scene.numlights) * 4;
4640 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
4642 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
4645 RSurf_ActiveWorldEntity();
4646 GL_BlendFunc(GL_ONE, GL_ZERO);
4647 GL_CullFace(GL_NONE);
4648 GL_DepthMask(false);
4649 GL_DepthRange(0, 1);
4650 GL_PolygonOffset(0, 0);
4652 R_Mesh_ResetTextureState();
4653 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
4656 case RENDERPATH_D3D9:
4658 //Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4660 case RENDERPATH_D3D10:
4661 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4663 case RENDERPATH_D3D11:
4664 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4666 case RENDERPATH_SOFT:
4667 //Con_DPrintf("FIXME SOFT %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4670 for (lightindex = 0;lightindex < range;lightindex++)
4672 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4675 rtlight = &light->rtlight;
4676 rtlight->corona_visibility = 0;
4677 rtlight->corona_queryindex_visiblepixels = 0;
4678 rtlight->corona_queryindex_allpixels = 0;
4679 if (!(rtlight->flags & flag))
4681 if (rtlight->corona <= 0)
4683 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4685 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4687 for (i = 0;i < r_refdef.scene.numlights;i++)
4689 rtlight = r_refdef.scene.lights[i];
4690 rtlight->corona_visibility = 0;
4691 rtlight->corona_queryindex_visiblepixels = 0;
4692 rtlight->corona_queryindex_allpixels = 0;
4693 if (!(rtlight->flags & flag))
4695 if (rtlight->corona <= 0)
4697 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4700 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4702 // now draw the coronas using the query data for intensity info
4703 for (lightindex = 0;lightindex < range;lightindex++)
4705 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4708 rtlight = &light->rtlight;
4709 if (rtlight->corona_visibility <= 0)
4711 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4713 for (i = 0;i < r_refdef.scene.numlights;i++)
4715 rtlight = r_refdef.scene.lights[i];
4716 if (rtlight->corona_visibility <= 0)
4718 if (gl_flashblend.integer)
4719 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4721 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4727 dlight_t *R_Shadow_NewWorldLight(void)
4729 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4732 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)
4735 // validate parameters
4736 if (style < 0 || style >= MAX_LIGHTSTYLES)
4738 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
4744 // copy to light properties
4745 VectorCopy(origin, light->origin);
4746 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4747 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4748 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4750 light->color[0] = max(color[0], 0);
4751 light->color[1] = max(color[1], 0);
4752 light->color[2] = max(color[2], 0);
4754 light->color[0] = color[0];
4755 light->color[1] = color[1];
4756 light->color[2] = color[2];
4757 light->radius = max(radius, 0);
4758 light->style = style;
4759 light->shadow = shadowenable;
4760 light->corona = corona;
4761 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4762 light->coronasizescale = coronasizescale;
4763 light->ambientscale = ambientscale;
4764 light->diffusescale = diffusescale;
4765 light->specularscale = specularscale;
4766 light->flags = flags;
4768 // update renderable light data
4769 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4770 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);
4773 void R_Shadow_FreeWorldLight(dlight_t *light)
4775 if (r_shadow_selectedlight == light)
4776 r_shadow_selectedlight = NULL;
4777 R_RTLight_Uncompile(&light->rtlight);
4778 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4781 void R_Shadow_ClearWorldLights(void)
4785 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4786 for (lightindex = 0;lightindex < range;lightindex++)
4788 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4790 R_Shadow_FreeWorldLight(light);
4792 r_shadow_selectedlight = NULL;
4795 void R_Shadow_SelectLight(dlight_t *light)
4797 if (r_shadow_selectedlight)
4798 r_shadow_selectedlight->selected = false;
4799 r_shadow_selectedlight = light;
4800 if (r_shadow_selectedlight)
4801 r_shadow_selectedlight->selected = true;
4804 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4806 // this is never batched (there can be only one)
4808 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
4809 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4810 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4813 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4818 skinframe_t *skinframe;
4821 // this is never batched (due to the ent parameter changing every time)
4822 // so numsurfaces == 1 and surfacelist[0] == lightnumber
4823 const dlight_t *light = (dlight_t *)ent;
4826 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
4829 VectorScale(light->color, intensity, spritecolor);
4830 if (VectorLength(spritecolor) < 0.1732f)
4831 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
4832 if (VectorLength(spritecolor) > 1.0f)
4833 VectorNormalize(spritecolor);
4835 // draw light sprite
4836 if (light->cubemapname[0] && !light->shadow)
4837 skinframe = r_editlights_sprcubemapnoshadowlight;
4838 else if (light->cubemapname[0])
4839 skinframe = r_editlights_sprcubemaplight;
4840 else if (!light->shadow)
4841 skinframe = r_editlights_sprnoshadowlight;
4843 skinframe = r_editlights_sprlight;
4845 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);
4846 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4848 // draw selection sprite if light is selected
4849 if (light->selected)
4851 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4852 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4853 // VorteX todo: add normalmode/realtime mode light overlay sprites?
4857 void R_Shadow_DrawLightSprites(void)
4861 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4862 for (lightindex = 0;lightindex < range;lightindex++)
4864 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4866 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
4868 if (!r_editlights_lockcursor)
4869 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
4872 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
4877 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
4878 if (lightindex >= range)
4880 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4883 rtlight = &light->rtlight;
4884 //if (!(rtlight->flags & flag))
4886 VectorCopy(rtlight->shadoworigin, origin);
4887 *radius = rtlight->radius;
4888 VectorCopy(rtlight->color, color);
4892 void R_Shadow_SelectLightInView(void)
4894 float bestrating, rating, temp[3];
4898 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4902 if (r_editlights_lockcursor)
4904 for (lightindex = 0;lightindex < range;lightindex++)
4906 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4909 VectorSubtract(light->origin, r_refdef.view.origin, temp);
4910 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
4913 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
4914 if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1.0f)
4916 bestrating = rating;
4921 R_Shadow_SelectLight(best);
4924 void R_Shadow_LoadWorldLights(void)
4926 int n, a, style, shadow, flags;
4927 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
4928 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
4929 if (cl.worldmodel == NULL)
4931 Con_Print("No map loaded.\n");
4934 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
4935 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4945 for (;COM_Parse(t, true) && strcmp(
4946 if (COM_Parse(t, true))
4948 if (com_token[0] == '!')
4951 origin[0] = atof(com_token+1);
4954 origin[0] = atof(com_token);
4959 while (*s && *s != '\n' && *s != '\r')
4965 // check for modifier flags
4972 #if _MSC_VER >= 1400
4973 #define sscanf sscanf_s
4975 cubemapname[sizeof(cubemapname)-1] = 0;
4976 #if MAX_QPATH != 128
4977 #error update this code if MAX_QPATH changes
4979 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
4980 #if _MSC_VER >= 1400
4981 , sizeof(cubemapname)
4983 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
4986 flags = LIGHTFLAG_REALTIMEMODE;
4994 coronasizescale = 0.25f;
4996 VectorClear(angles);
4999 if (a < 9 || !strcmp(cubemapname, "\"\""))
5001 // remove quotes on cubemapname
5002 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
5005 namelen = strlen(cubemapname) - 2;
5006 memmove(cubemapname, cubemapname + 1, namelen);
5007 cubemapname[namelen] = '\0';
5011 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);
5014 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5022 Con_Printf("invalid rtlights file \"%s\"\n", name);
5023 Mem_Free(lightsstring);
5027 void R_Shadow_SaveWorldLights(void)
5031 size_t bufchars, bufmaxchars;
5033 char name[MAX_QPATH];
5034 char line[MAX_INPUTLINE];
5035 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
5036 // I hate lines which are 3 times my screen size :( --blub
5039 if (cl.worldmodel == NULL)
5041 Con_Print("No map loaded.\n");
5044 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
5045 bufchars = bufmaxchars = 0;
5047 for (lightindex = 0;lightindex < range;lightindex++)
5049 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5052 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
5053 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);
5054 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
5055 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]);
5057 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);
5058 if (bufchars + strlen(line) > bufmaxchars)
5060 bufmaxchars = bufchars + strlen(line) + 2048;
5062 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
5066 memcpy(buf, oldbuf, bufchars);
5072 memcpy(buf + bufchars, line, strlen(line));
5073 bufchars += strlen(line);
5077 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
5082 void R_Shadow_LoadLightsFile(void)
5085 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
5086 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
5087 if (cl.worldmodel == NULL)
5089 Con_Print("No map loaded.\n");
5092 dpsnprintf(name, sizeof(name), "%s.lights", cl.worldnamenoextension);
5093 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5101 while (*s && *s != '\n' && *s != '\r')
5107 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);
5111 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);
5114 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
5115 radius = bound(15, radius, 4096);
5116 VectorScale(color, (2.0f / (8388608.0f)), color);
5117 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5125 Con_Printf("invalid lights file \"%s\"\n", name);
5126 Mem_Free(lightsstring);
5130 // tyrlite/hmap2 light types in the delay field
5131 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
5133 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
5145 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
5146 char key[256], value[MAX_INPUTLINE];
5148 if (cl.worldmodel == NULL)
5150 Con_Print("No map loaded.\n");
5153 // try to load a .ent file first
5154 dpsnprintf(key, sizeof(key), "%s.ent", cl.worldnamenoextension);
5155 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
5156 // and if that is not found, fall back to the bsp file entity string
5158 data = cl.worldmodel->brush.entities;
5161 for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
5163 type = LIGHTTYPE_MINUSX;
5164 origin[0] = origin[1] = origin[2] = 0;
5165 originhack[0] = originhack[1] = originhack[2] = 0;
5166 angles[0] = angles[1] = angles[2] = 0;
5167 color[0] = color[1] = color[2] = 1;
5168 light[0] = light[1] = light[2] = 1;light[3] = 300;
5169 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
5179 if (!COM_ParseToken_Simple(&data, false, false))
5181 if (com_token[0] == '}')
5182 break; // end of entity
5183 if (com_token[0] == '_')
5184 strlcpy(key, com_token + 1, sizeof(key));
5186 strlcpy(key, com_token, sizeof(key));
5187 while (key[strlen(key)-1] == ' ') // remove trailing spaces
5188 key[strlen(key)-1] = 0;
5189 if (!COM_ParseToken_Simple(&data, false, false))
5191 strlcpy(value, com_token, sizeof(value));
5193 // now that we have the key pair worked out...
5194 if (!strcmp("light", key))
5196 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5200 light[0] = vec[0] * (1.0f / 256.0f);
5201 light[1] = vec[0] * (1.0f / 256.0f);
5202 light[2] = vec[0] * (1.0f / 256.0f);
5208 light[0] = vec[0] * (1.0f / 255.0f);
5209 light[1] = vec[1] * (1.0f / 255.0f);
5210 light[2] = vec[2] * (1.0f / 255.0f);
5214 else if (!strcmp("delay", key))
5216 else if (!strcmp("origin", key))
5217 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5218 else if (!strcmp("angle", key))
5219 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5220 else if (!strcmp("angles", key))
5221 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5222 else if (!strcmp("color", key))
5223 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5224 else if (!strcmp("wait", key))
5225 fadescale = atof(value);
5226 else if (!strcmp("classname", key))
5228 if (!strncmp(value, "light", 5))
5231 if (!strcmp(value, "light_fluoro"))
5236 overridecolor[0] = 1;
5237 overridecolor[1] = 1;
5238 overridecolor[2] = 1;
5240 if (!strcmp(value, "light_fluorospark"))
5245 overridecolor[0] = 1;
5246 overridecolor[1] = 1;
5247 overridecolor[2] = 1;
5249 if (!strcmp(value, "light_globe"))
5254 overridecolor[0] = 1;
5255 overridecolor[1] = 0.8;
5256 overridecolor[2] = 0.4;
5258 if (!strcmp(value, "light_flame_large_yellow"))
5263 overridecolor[0] = 1;
5264 overridecolor[1] = 0.5;
5265 overridecolor[2] = 0.1;
5267 if (!strcmp(value, "light_flame_small_yellow"))
5272 overridecolor[0] = 1;
5273 overridecolor[1] = 0.5;
5274 overridecolor[2] = 0.1;
5276 if (!strcmp(value, "light_torch_small_white"))
5281 overridecolor[0] = 1;
5282 overridecolor[1] = 0.5;
5283 overridecolor[2] = 0.1;
5285 if (!strcmp(value, "light_torch_small_walltorch"))
5290 overridecolor[0] = 1;
5291 overridecolor[1] = 0.5;
5292 overridecolor[2] = 0.1;
5296 else if (!strcmp("style", key))
5297 style = atoi(value);
5298 else if (!strcmp("skin", key))
5299 skin = (int)atof(value);
5300 else if (!strcmp("pflags", key))
5301 pflags = (int)atof(value);
5302 //else if (!strcmp("effects", key))
5303 // effects = (int)atof(value);
5304 else if (cl.worldmodel->type == mod_brushq3)
5306 if (!strcmp("scale", key))
5307 lightscale = atof(value);
5308 if (!strcmp("fade", key))
5309 fadescale = atof(value);
5314 if (lightscale <= 0)
5318 if (color[0] == color[1] && color[0] == color[2])
5320 color[0] *= overridecolor[0];
5321 color[1] *= overridecolor[1];
5322 color[2] *= overridecolor[2];
5324 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5325 color[0] = color[0] * light[0];
5326 color[1] = color[1] * light[1];
5327 color[2] = color[2] * light[2];
5330 case LIGHTTYPE_MINUSX:
5332 case LIGHTTYPE_RECIPX:
5334 VectorScale(color, (1.0f / 16.0f), color);
5336 case LIGHTTYPE_RECIPXX:
5338 VectorScale(color, (1.0f / 16.0f), color);
5341 case LIGHTTYPE_NONE:
5345 case LIGHTTYPE_MINUSXX:
5348 VectorAdd(origin, originhack, origin);
5350 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);
5353 Mem_Free(entfiledata);
5357 void R_Shadow_SetCursorLocationForView(void)
5360 vec3_t dest, endpos;
5362 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5363 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
5364 if (trace.fraction < 1)
5366 dist = trace.fraction * r_editlights_cursordistance.value;
5367 push = r_editlights_cursorpushback.value;
5371 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5372 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5376 VectorClear( endpos );
5378 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5379 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5380 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5383 void R_Shadow_UpdateWorldLightSelection(void)
5385 if (r_editlights.integer)
5387 R_Shadow_SetCursorLocationForView();
5388 R_Shadow_SelectLightInView();
5391 R_Shadow_SelectLight(NULL);
5394 void R_Shadow_EditLights_Clear_f(void)
5396 R_Shadow_ClearWorldLights();
5399 void R_Shadow_EditLights_Reload_f(void)
5403 strlcpy(r_shadow_mapname, cl.worldname, sizeof(r_shadow_mapname));
5404 R_Shadow_ClearWorldLights();
5405 R_Shadow_LoadWorldLights();
5406 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5408 R_Shadow_LoadLightsFile();
5409 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5410 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5414 void R_Shadow_EditLights_Save_f(void)
5418 R_Shadow_SaveWorldLights();
5421 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
5423 R_Shadow_ClearWorldLights();
5424 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5427 void R_Shadow_EditLights_ImportLightsFile_f(void)
5429 R_Shadow_ClearWorldLights();
5430 R_Shadow_LoadLightsFile();
5433 void R_Shadow_EditLights_Spawn_f(void)
5436 if (!r_editlights.integer)
5438 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5441 if (Cmd_Argc() != 1)
5443 Con_Print("r_editlights_spawn does not take parameters\n");
5446 color[0] = color[1] = color[2] = 1;
5447 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5450 void R_Shadow_EditLights_Edit_f(void)
5452 vec3_t origin, angles, color;
5453 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5454 int style, shadows, flags, normalmode, realtimemode;
5455 char cubemapname[MAX_INPUTLINE];
5456 if (!r_editlights.integer)
5458 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5461 if (!r_shadow_selectedlight)
5463 Con_Print("No selected light.\n");
5466 VectorCopy(r_shadow_selectedlight->origin, origin);
5467 VectorCopy(r_shadow_selectedlight->angles, angles);
5468 VectorCopy(r_shadow_selectedlight->color, color);
5469 radius = r_shadow_selectedlight->radius;
5470 style = r_shadow_selectedlight->style;
5471 if (r_shadow_selectedlight->cubemapname)
5472 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5475 shadows = r_shadow_selectedlight->shadow;
5476 corona = r_shadow_selectedlight->corona;
5477 coronasizescale = r_shadow_selectedlight->coronasizescale;
5478 ambientscale = r_shadow_selectedlight->ambientscale;
5479 diffusescale = r_shadow_selectedlight->diffusescale;
5480 specularscale = r_shadow_selectedlight->specularscale;
5481 flags = r_shadow_selectedlight->flags;
5482 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5483 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5484 if (!strcmp(Cmd_Argv(1), "origin"))
5486 if (Cmd_Argc() != 5)
5488 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5491 origin[0] = atof(Cmd_Argv(2));
5492 origin[1] = atof(Cmd_Argv(3));
5493 origin[2] = atof(Cmd_Argv(4));
5495 else if (!strcmp(Cmd_Argv(1), "originx"))
5497 if (Cmd_Argc() != 3)
5499 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5502 origin[0] = atof(Cmd_Argv(2));
5504 else if (!strcmp(Cmd_Argv(1), "originy"))
5506 if (Cmd_Argc() != 3)
5508 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5511 origin[1] = atof(Cmd_Argv(2));
5513 else if (!strcmp(Cmd_Argv(1), "originz"))
5515 if (Cmd_Argc() != 3)
5517 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5520 origin[2] = atof(Cmd_Argv(2));
5522 else if (!strcmp(Cmd_Argv(1), "move"))
5524 if (Cmd_Argc() != 5)
5526 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5529 origin[0] += atof(Cmd_Argv(2));
5530 origin[1] += atof(Cmd_Argv(3));
5531 origin[2] += atof(Cmd_Argv(4));
5533 else if (!strcmp(Cmd_Argv(1), "movex"))
5535 if (Cmd_Argc() != 3)
5537 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5540 origin[0] += atof(Cmd_Argv(2));
5542 else if (!strcmp(Cmd_Argv(1), "movey"))
5544 if (Cmd_Argc() != 3)
5546 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5549 origin[1] += atof(Cmd_Argv(2));
5551 else if (!strcmp(Cmd_Argv(1), "movez"))
5553 if (Cmd_Argc() != 3)
5555 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5558 origin[2] += atof(Cmd_Argv(2));
5560 else if (!strcmp(Cmd_Argv(1), "angles"))
5562 if (Cmd_Argc() != 5)
5564 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5567 angles[0] = atof(Cmd_Argv(2));
5568 angles[1] = atof(Cmd_Argv(3));
5569 angles[2] = atof(Cmd_Argv(4));
5571 else if (!strcmp(Cmd_Argv(1), "anglesx"))
5573 if (Cmd_Argc() != 3)
5575 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5578 angles[0] = atof(Cmd_Argv(2));
5580 else if (!strcmp(Cmd_Argv(1), "anglesy"))
5582 if (Cmd_Argc() != 3)
5584 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5587 angles[1] = atof(Cmd_Argv(2));
5589 else if (!strcmp(Cmd_Argv(1), "anglesz"))
5591 if (Cmd_Argc() != 3)
5593 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5596 angles[2] = atof(Cmd_Argv(2));
5598 else if (!strcmp(Cmd_Argv(1), "color"))
5600 if (Cmd_Argc() != 5)
5602 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
5605 color[0] = atof(Cmd_Argv(2));
5606 color[1] = atof(Cmd_Argv(3));
5607 color[2] = atof(Cmd_Argv(4));
5609 else if (!strcmp(Cmd_Argv(1), "radius"))
5611 if (Cmd_Argc() != 3)
5613 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5616 radius = atof(Cmd_Argv(2));
5618 else if (!strcmp(Cmd_Argv(1), "colorscale"))
5620 if (Cmd_Argc() == 3)
5622 double scale = atof(Cmd_Argv(2));
5629 if (Cmd_Argc() != 5)
5631 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
5634 color[0] *= atof(Cmd_Argv(2));
5635 color[1] *= atof(Cmd_Argv(3));
5636 color[2] *= atof(Cmd_Argv(4));
5639 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
5641 if (Cmd_Argc() != 3)
5643 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5646 radius *= atof(Cmd_Argv(2));
5648 else if (!strcmp(Cmd_Argv(1), "style"))
5650 if (Cmd_Argc() != 3)
5652 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5655 style = atoi(Cmd_Argv(2));
5657 else if (!strcmp(Cmd_Argv(1), "cubemap"))
5661 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5664 if (Cmd_Argc() == 3)
5665 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
5669 else if (!strcmp(Cmd_Argv(1), "shadows"))
5671 if (Cmd_Argc() != 3)
5673 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5676 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5678 else if (!strcmp(Cmd_Argv(1), "corona"))
5680 if (Cmd_Argc() != 3)
5682 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5685 corona = atof(Cmd_Argv(2));
5687 else if (!strcmp(Cmd_Argv(1), "coronasize"))
5689 if (Cmd_Argc() != 3)
5691 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5694 coronasizescale = atof(Cmd_Argv(2));
5696 else if (!strcmp(Cmd_Argv(1), "ambient"))
5698 if (Cmd_Argc() != 3)
5700 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5703 ambientscale = atof(Cmd_Argv(2));
5705 else if (!strcmp(Cmd_Argv(1), "diffuse"))
5707 if (Cmd_Argc() != 3)
5709 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5712 diffusescale = atof(Cmd_Argv(2));
5714 else if (!strcmp(Cmd_Argv(1), "specular"))
5716 if (Cmd_Argc() != 3)
5718 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5721 specularscale = atof(Cmd_Argv(2));
5723 else if (!strcmp(Cmd_Argv(1), "normalmode"))
5725 if (Cmd_Argc() != 3)
5727 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5730 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5732 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
5734 if (Cmd_Argc() != 3)
5736 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5739 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5743 Con_Print("usage: r_editlights_edit [property] [value]\n");
5744 Con_Print("Selected light's properties:\n");
5745 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5746 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5747 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5748 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
5749 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
5750 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
5751 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5752 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
5753 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
5754 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
5755 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
5756 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
5757 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5758 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5761 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5762 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5765 void R_Shadow_EditLights_EditAll_f(void)
5768 dlight_t *light, *oldselected;
5771 if (!r_editlights.integer)
5773 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5777 oldselected = r_shadow_selectedlight;
5778 // EditLights doesn't seem to have a "remove" command or something so:
5779 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5780 for (lightindex = 0;lightindex < range;lightindex++)
5782 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5785 R_Shadow_SelectLight(light);
5786 R_Shadow_EditLights_Edit_f();
5788 // return to old selected (to not mess editing once selection is locked)
5789 R_Shadow_SelectLight(oldselected);
5792 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
5794 int lightnumber, lightcount;
5795 size_t lightindex, range;
5799 if (!r_editlights.integer)
5801 x = vid_conwidth.value - 240;
5803 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
5806 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5807 for (lightindex = 0;lightindex < range;lightindex++)
5809 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5812 if (light == r_shadow_selectedlight)
5813 lightnumber = lightindex;
5816 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;
5817 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;
5819 if (r_shadow_selectedlight == NULL)
5821 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;
5822 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;
5823 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;
5824 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;
5825 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;
5826 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;
5827 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;
5828 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;
5829 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;
5830 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;
5831 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;
5832 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;
5833 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;
5834 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;
5835 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;
5838 void R_Shadow_EditLights_ToggleShadow_f(void)
5840 if (!r_editlights.integer)
5842 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5845 if (!r_shadow_selectedlight)
5847 Con_Print("No selected light.\n");
5850 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);
5853 void R_Shadow_EditLights_ToggleCorona_f(void)
5855 if (!r_editlights.integer)
5857 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5860 if (!r_shadow_selectedlight)
5862 Con_Print("No selected light.\n");
5865 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);
5868 void R_Shadow_EditLights_Remove_f(void)
5870 if (!r_editlights.integer)
5872 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
5875 if (!r_shadow_selectedlight)
5877 Con_Print("No selected light.\n");
5880 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
5881 r_shadow_selectedlight = NULL;
5884 void R_Shadow_EditLights_Help_f(void)
5887 "Documentation on r_editlights system:\n"
5889 "r_editlights : enable/disable editing mode\n"
5890 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
5891 "r_editlights_cursorpushback : push back cursor this far from surface\n"
5892 "r_editlights_cursorpushoff : push cursor off surface this far\n"
5893 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
5894 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
5896 "r_editlights_help : this help\n"
5897 "r_editlights_clear : remove all lights\n"
5898 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
5899 "r_editlights_lock : lock selection to current light, if already locked - unlock\n"
5900 "r_editlights_save : save to .rtlights file\n"
5901 "r_editlights_spawn : create a light with default settings\n"
5902 "r_editlights_edit command : edit selected light - more documentation below\n"
5903 "r_editlights_remove : remove selected light\n"
5904 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
5905 "r_editlights_importlightentitiesfrommap : reload light entities\n"
5906 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
5908 "origin x y z : set light location\n"
5909 "originx x: set x component of light location\n"
5910 "originy y: set y component of light location\n"
5911 "originz z: set z component of light location\n"
5912 "move x y z : adjust light location\n"
5913 "movex x: adjust x component of light location\n"
5914 "movey y: adjust y component of light location\n"
5915 "movez z: adjust z component of light location\n"
5916 "angles x y z : set light angles\n"
5917 "anglesx x: set x component of light angles\n"
5918 "anglesy y: set y component of light angles\n"
5919 "anglesz z: set z component of light angles\n"
5920 "color r g b : set color of light (can be brighter than 1 1 1)\n"
5921 "radius radius : set radius (size) of light\n"
5922 "colorscale grey : multiply color of light (1 does nothing)\n"
5923 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
5924 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
5925 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
5926 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
5927 "cubemap basename : set filter cubemap of light (not yet supported)\n"
5928 "shadows 1/0 : turn on/off shadows\n"
5929 "corona n : set corona intensity\n"
5930 "coronasize n : set corona size (0-1)\n"
5931 "ambient n : set ambient intensity (0-1)\n"
5932 "diffuse n : set diffuse intensity (0-1)\n"
5933 "specular n : set specular intensity (0-1)\n"
5934 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
5935 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
5936 "<nothing> : print light properties to console\n"
5940 void R_Shadow_EditLights_CopyInfo_f(void)
5942 if (!r_editlights.integer)
5944 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
5947 if (!r_shadow_selectedlight)
5949 Con_Print("No selected light.\n");
5952 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
5953 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
5954 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
5955 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
5956 if (r_shadow_selectedlight->cubemapname)
5957 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
5959 r_shadow_bufferlight.cubemapname[0] = 0;
5960 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
5961 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
5962 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
5963 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
5964 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
5965 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
5966 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
5969 void R_Shadow_EditLights_PasteInfo_f(void)
5971 if (!r_editlights.integer)
5973 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
5976 if (!r_shadow_selectedlight)
5978 Con_Print("No selected light.\n");
5981 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);
5984 void R_Shadow_EditLights_Lock_f(void)
5986 if (!r_editlights.integer)
5988 Con_Print("Cannot lock on light when not in editing mode. Set r_editlights to 1.\n");
5991 if (r_editlights_lockcursor)
5993 r_editlights_lockcursor = false;
5996 if (!r_shadow_selectedlight)
5998 Con_Print("No selected light to lock on.\n");
6001 r_editlights_lockcursor = true;
6004 void R_Shadow_EditLights_Init(void)
6006 Cvar_RegisterVariable(&r_editlights);
6007 Cvar_RegisterVariable(&r_editlights_cursordistance);
6008 Cvar_RegisterVariable(&r_editlights_cursorpushback);
6009 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
6010 Cvar_RegisterVariable(&r_editlights_cursorgrid);
6011 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
6012 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
6013 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
6014 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)");
6015 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
6016 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
6017 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
6018 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)");
6019 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
6020 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
6021 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
6022 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
6023 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
6024 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
6025 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)");
6026 Cmd_AddCommand("r_editlights_lock", R_Shadow_EditLights_Lock_f, "lock selection to current light, if already locked - unlock");
6032 =============================================================================
6036 =============================================================================
6039 void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, const int flags)
6041 int i, numlights, flag;
6042 float f, relativepoint[3], dist, dist2, lightradius2;
6046 VectorClear(diffusecolor);
6047 VectorClear(diffusenormal);
6049 if (flags & LP_LIGHTMAP)
6051 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
6053 ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_refdef.scene.ambient;
6054 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
6057 VectorSet(ambientcolor, 1, 1, 1);
6059 if (flags & LP_RTWORLD)
6061 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
6062 numlights = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
6063 for (i = 0; i < numlights; i++)
6065 dlight = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, i);
6068 light = &dlight->rtlight;
6069 if (!(light->flags & flag))
6072 lightradius2 = light->radius * light->radius;
6073 VectorSubtract(light->shadoworigin, p, relativepoint);
6074 dist2 = VectorLength2(relativepoint);
6075 if (dist2 >= lightradius2)
6077 dist = sqrt(dist2) / light->radius;
6078 f = dist < 1 ? (r_shadow_lightintensityscale.value * ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist))) : 0;
6081 // todo: add to both ambient and diffuse
6082 if (!light->shadow || CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
6083 VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);
6086 if (flags & LP_DYNLIGHT)
6089 for (i = 0;i < r_refdef.scene.numlights;i++)
6091 light = r_refdef.scene.lights[i];
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->color, ambientcolor);