3 Terminology: Stencil Shadow Volume (sometimes called Stencil Shadows)
4 An extrusion of the lit faces, beginning at the original geometry and ending
5 further from the light source than the original geometry (presumably at least
6 as far as the light's radius, if the light has a radius at all), capped at
7 both front and back to avoid any problems (extrusion from dark faces also
8 works but has a different set of problems)
10 This is normally rendered using Carmack's Reverse technique, in which
11 backfaces behind zbuffer (zfail) increment the stencil, and frontfaces behind
12 zbuffer (zfail) decrement the stencil, the result is a stencil value of zero
13 where shadows did not intersect the visible geometry, suitable as a stencil
14 mask for rendering lighting everywhere but shadow.
16 In our case to hopefully avoid the Creative Labs patent, we draw the backfaces
17 as decrement and the frontfaces as increment, and we redefine the DepthFunc to
18 GL_LESS (the patent uses GL_GEQUAL) which causes zfail when behind surfaces
19 and zpass when infront (the patent draws where zpass with a GL_GEQUAL test),
20 additionally we clear stencil to 128 to avoid the need for the unclamped
21 incr/decr extension (not related to patent).
24 This algorithm may be covered by Creative's patent (US Patent #6384822),
25 however that patent is quite specific about increment on backfaces and
26 decrement on frontfaces where zpass with GL_GEQUAL depth test, which is
27 opposite this implementation and partially opposite Carmack's Reverse paper
28 (which uses GL_LESS, but increments on backfaces and decrements on frontfaces).
32 Terminology: Stencil Light Volume (sometimes called Light Volumes)
33 Similar to a Stencil Shadow Volume, but inverted; rather than containing the
34 areas in shadow it contains the areas in light, this can only be built
35 quickly for certain limited cases (such as portal visibility from a point),
36 but is quite useful for some effects (sunlight coming from sky polygons is
37 one possible example, translucent occluders is another example).
41 Terminology: Optimized Stencil Shadow Volume
42 A Stencil Shadow Volume that has been processed sufficiently to ensure it has
43 no duplicate coverage of areas (no need to shadow an area twice), often this
44 greatly improves performance but is an operation too costly to use on moving
45 lights (however completely optimal Stencil Light Volumes can be constructed
50 Terminology: Per Pixel Lighting (sometimes abbreviated PPL)
51 Per pixel evaluation of lighting equations, at a bare minimum this involves
52 DOT3 shading of diffuse lighting (per pixel dotproduct of negated incidence
53 vector and surface normal, using a texture of the surface bumps, called a
54 NormalMap) if supported by hardware; in our case there is support for cards
55 which are incapable of DOT3, the quality is quite poor however. Additionally
56 it is desirable to have specular evaluation per pixel, per vertex
57 normalization of specular halfangle vectors causes noticable distortion but
58 is unavoidable on hardware without GL_ARB_fragment_program or
59 GL_ARB_fragment_shader.
63 Terminology: Normalization CubeMap
64 A cubemap containing normalized dot3-encoded (vectors of length 1 or less
65 encoded as RGB colors) for any possible direction, this technique allows per
66 pixel calculation of incidence vector for per pixel lighting purposes, which
67 would not otherwise be possible per pixel without GL_ARB_fragment_program or
68 GL_ARB_fragment_shader.
72 Terminology: 2D+1D Attenuation Texturing
73 A very crude approximation of light attenuation with distance which results
74 in cylindrical light shapes which fade vertically as a streak (some games
75 such as Doom3 allow this to be rotated to be less noticable in specific
76 cases), the technique is simply modulating lighting by two 2D textures (which
77 can be the same) on different axes of projection (XY and Z, typically), this
78 is the second best technique available without 3D Attenuation Texturing,
79 GL_ARB_fragment_program or GL_ARB_fragment_shader technology.
83 Terminology: 2D+1D Inverse Attenuation Texturing
84 A clever method described in papers on the Abducted engine, this has a squared
85 distance texture (bright on the outside, black in the middle), which is used
86 twice using GL_ADD blending, the result of this is used in an inverse modulate
87 (GL_ONE_MINUS_DST_ALPHA, GL_ZERO) to implement the equation
88 lighting*=(1-((X*X+Y*Y)+(Z*Z))) which is spherical (unlike 2D+1D attenuation
93 Terminology: 3D Attenuation Texturing
94 A slightly crude approximation of light attenuation with distance, its flaws
95 are limited radius and resolution (performance tradeoffs).
99 Terminology: 3D Attenuation-Normalization Texturing
100 A 3D Attenuation Texture merged with a Normalization CubeMap, by making the
101 vectors shorter the lighting becomes darker, a very effective optimization of
102 diffuse lighting if 3D Attenuation Textures are already used.
106 Terminology: Light Cubemap Filtering
107 A technique for modeling non-uniform light distribution according to
108 direction, for example a lantern may use a cubemap to describe the light
109 emission pattern of the cage around the lantern (as well as soot buildup
110 discoloring the light in certain areas), often also used for softened grate
111 shadows and light shining through a stained glass window (done crudely by
112 texturing the lighting with a cubemap), another good example would be a disco
113 light. This technique is used heavily in many games (Doom3 does not support
118 Terminology: Light Projection Filtering
119 A technique for modeling shadowing of light passing through translucent
120 surfaces, allowing stained glass windows and other effects to be done more
121 elegantly than possible with Light Cubemap Filtering by applying an occluder
122 texture to the lighting combined with a stencil light volume to limit the lit
123 area, this technique is used by Doom3 for spotlights and flashlights, among
124 other things, this can also be used more generally to render light passing
125 through multiple translucent occluders in a scene (using a light volume to
126 describe the area beyond the occluder, and thus mask off rendering of all
131 Terminology: Doom3 Lighting
132 A combination of Stencil Shadow Volume, Per Pixel Lighting, Normalization
133 CubeMap, 2D+1D Attenuation Texturing, and Light Projection Filtering, as
134 demonstrated by the game Doom3.
137 #include "quakedef.h"
138 #include "r_shadow.h"
139 #include "cl_collision.h"
145 extern LPDIRECT3DDEVICE9 vid_d3d9dev;
148 extern void R_Shadow_EditLights_Init(void);
150 typedef enum r_shadow_rendermode_e
152 R_SHADOW_RENDERMODE_NONE,
153 R_SHADOW_RENDERMODE_ZPASS_STENCIL,
154 R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL,
155 R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE,
156 R_SHADOW_RENDERMODE_ZFAIL_STENCIL,
157 R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL,
158 R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE,
159 R_SHADOW_RENDERMODE_LIGHT_VERTEX,
160 R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN,
161 R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN,
162 R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN,
163 R_SHADOW_RENDERMODE_LIGHT_GLSL,
164 R_SHADOW_RENDERMODE_VISIBLEVOLUMES,
165 R_SHADOW_RENDERMODE_VISIBLELIGHTING,
166 R_SHADOW_RENDERMODE_SHADOWMAP2D
168 r_shadow_rendermode_t;
170 typedef enum r_shadow_shadowmode_e
172 R_SHADOW_SHADOWMODE_STENCIL,
173 R_SHADOW_SHADOWMODE_SHADOWMAP2D
175 r_shadow_shadowmode_t;
177 r_shadow_rendermode_t r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
178 r_shadow_rendermode_t r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_NONE;
179 r_shadow_rendermode_t r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_NONE;
180 r_shadow_rendermode_t r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_NONE;
181 qboolean r_shadow_usingshadowmap2d;
182 qboolean r_shadow_usingshadowmaportho;
183 int r_shadow_shadowmapside;
184 float r_shadow_shadowmap_texturescale[2];
185 float r_shadow_shadowmap_parameters[4];
187 int r_shadow_drawbuffer;
188 int r_shadow_readbuffer;
190 int r_shadow_cullface_front, r_shadow_cullface_back;
191 GLuint r_shadow_fbo2d;
192 r_shadow_shadowmode_t r_shadow_shadowmode;
193 int r_shadow_shadowmapfilterquality;
194 int r_shadow_shadowmapdepthbits;
195 int r_shadow_shadowmapmaxsize;
196 qboolean r_shadow_shadowmapvsdct;
197 qboolean r_shadow_shadowmapsampler;
198 int r_shadow_shadowmappcf;
199 int r_shadow_shadowmapborder;
200 matrix4x4_t r_shadow_shadowmapmatrix;
201 int r_shadow_lightscissor[4];
202 qboolean r_shadow_usingdeferredprepass;
204 int maxshadowtriangles;
207 int maxshadowvertices;
208 float *shadowvertex3f;
218 unsigned char *shadowsides;
219 int *shadowsideslist;
226 int r_shadow_buffer_numleafpvsbytes;
227 unsigned char *r_shadow_buffer_visitingleafpvs;
228 unsigned char *r_shadow_buffer_leafpvs;
229 int *r_shadow_buffer_leaflist;
231 int r_shadow_buffer_numsurfacepvsbytes;
232 unsigned char *r_shadow_buffer_surfacepvs;
233 int *r_shadow_buffer_surfacelist;
234 unsigned char *r_shadow_buffer_surfacesides;
236 int r_shadow_buffer_numshadowtrispvsbytes;
237 unsigned char *r_shadow_buffer_shadowtrispvs;
238 int r_shadow_buffer_numlighttrispvsbytes;
239 unsigned char *r_shadow_buffer_lighttrispvs;
241 rtexturepool_t *r_shadow_texturepool;
242 rtexture_t *r_shadow_attenuationgradienttexture;
243 rtexture_t *r_shadow_attenuation2dtexture;
244 rtexture_t *r_shadow_attenuation3dtexture;
245 skinframe_t *r_shadow_lightcorona;
246 rtexture_t *r_shadow_shadowmap2dtexture;
247 rtexture_t *r_shadow_shadowmap2dcolortexture;
248 rtexture_t *r_shadow_shadowmapvsdcttexture;
249 int r_shadow_shadowmapsize; // changes for each light based on distance
250 int r_shadow_shadowmaplod; // changes for each light based on distance
252 GLuint r_shadow_prepassgeometryfbo;
253 GLuint r_shadow_prepasslightingfbo;
254 int r_shadow_prepass_width;
255 int r_shadow_prepass_height;
256 rtexture_t *r_shadow_prepassgeometrydepthtexture;
257 rtexture_t *r_shadow_prepassgeometrydepthcolortexture;
258 rtexture_t *r_shadow_prepassgeometrynormalmaptexture;
259 rtexture_t *r_shadow_prepasslightingdiffusetexture;
260 rtexture_t *r_shadow_prepasslightingspeculartexture;
262 // lights are reloaded when this changes
263 char r_shadow_mapname[MAX_QPATH];
265 // used only for light filters (cubemaps)
266 rtexturepool_t *r_shadow_filters_texturepool;
268 static const GLenum r_shadow_prepasslightingdrawbuffers[2] = {GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT};
270 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"};
271 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"};
272 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
273 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"};
274 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)"};
275 //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"};
276 cvar_t r_shadow_usenormalmap = {CVAR_SAVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"};
277 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)"};
278 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"};
279 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
280 cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
281 cvar_t r_shadow_gloss2exponent = {0, "r_shadow_gloss2exponent", "32", "same as r_shadow_glossexponent but for forced gloss (gloss 2) surfaces"};
282 cvar_t r_shadow_glossexact = {0, "r_shadow_glossexact", "0", "use exact reflection math for gloss (slightly slower, but should look a tad better)"};
283 cvar_t r_shadow_lightattenuationdividebias = {0, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"};
284 cvar_t r_shadow_lightattenuationlinearscale = {0, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"};
285 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
286 cvar_t r_shadow_lightradiusscale = {0, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
287 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "0", "how far to cast shadows"};
288 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)"};
289 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
290 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
291 cvar_t r_shadow_realtime_dlight_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
292 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
293 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)"};
294 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"};
295 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
296 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
297 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"};
298 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)"};
299 cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "0", "enables portal-based culling optimization during compilation (overrides compilesvbsp)"};
300 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)"};
301 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"};
302 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)"};
303 cvar_t r_shadow_shadowmapping_depthbits = {CVAR_SAVE, "r_shadow_shadowmapping_depthbits", "24", "requested minimum shadowmap texture depth bits"};
304 cvar_t r_shadow_shadowmapping_vsdct = {CVAR_SAVE, "r_shadow_shadowmapping_vsdct", "1", "enables use of virtual shadow depth cube texture"};
305 cvar_t r_shadow_shadowmapping_minsize = {CVAR_SAVE, "r_shadow_shadowmapping_minsize", "32", "shadowmap size limit"};
306 cvar_t r_shadow_shadowmapping_maxsize = {CVAR_SAVE, "r_shadow_shadowmapping_maxsize", "512", "shadowmap size limit"};
307 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"};
308 //cvar_t r_shadow_shadowmapping_lod_bias = {CVAR_SAVE, "r_shadow_shadowmapping_lod_bias", "16", "shadowmap size bias"};
309 //cvar_t r_shadow_shadowmapping_lod_scale = {CVAR_SAVE, "r_shadow_shadowmapping_lod_scale", "128", "shadowmap size scaling parameter"};
310 cvar_t r_shadow_shadowmapping_bordersize = {CVAR_SAVE, "r_shadow_shadowmapping_bordersize", "4", "shadowmap size bias for filtering"};
311 cvar_t r_shadow_shadowmapping_nearclip = {CVAR_SAVE, "r_shadow_shadowmapping_nearclip", "1", "shadowmap nearclip in world units"};
312 cvar_t r_shadow_shadowmapping_bias = {CVAR_SAVE, "r_shadow_shadowmapping_bias", "0.03", "shadowmap bias parameter (this is multiplied by nearclip * 1024 / lodsize)"};
313 cvar_t r_shadow_shadowmapping_polygonfactor = {CVAR_SAVE, "r_shadow_shadowmapping_polygonfactor", "2", "slope-dependent shadowmapping bias"};
314 cvar_t r_shadow_shadowmapping_polygonoffset = {CVAR_SAVE, "r_shadow_shadowmapping_polygonoffset", "0", "constant shadowmapping bias"};
315 cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
316 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)"};
317 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)"};
318 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "1", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
319 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"};
320 cvar_t r_coronas_occlusionquery = {CVAR_SAVE, "r_coronas_occlusionquery", "1", "use GL_ARB_occlusion_query extension if supported (fades coronas according to visibility)"};
321 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
322 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
323 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
324 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
325 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
326 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
327 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
328 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
329 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
331 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
332 #define ATTENTABLESIZE 256
333 // 1D gradient, 2D circle and 3D sphere attenuation textures
334 #define ATTEN1DSIZE 32
335 #define ATTEN2DSIZE 64
336 #define ATTEN3DSIZE 32
338 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
339 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
340 static float r_shadow_attentable[ATTENTABLESIZE+1];
342 rtlight_t *r_shadow_compilingrtlight;
343 static memexpandablearray_t r_shadow_worldlightsarray;
344 dlight_t *r_shadow_selectedlight;
345 dlight_t r_shadow_bufferlight;
346 vec3_t r_editlights_cursorlocation;
347 qboolean r_editlights_lockcursor;
349 extern int con_vislines;
351 void R_Shadow_UncompileWorldLights(void);
352 void R_Shadow_ClearWorldLights(void);
353 void R_Shadow_SaveWorldLights(void);
354 void R_Shadow_LoadWorldLights(void);
355 void R_Shadow_LoadLightsFile(void);
356 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
357 void R_Shadow_EditLights_Reload_f(void);
358 void R_Shadow_ValidateCvars(void);
359 static void R_Shadow_MakeTextures(void);
361 #define EDLIGHTSPRSIZE 8
362 skinframe_t *r_editlights_sprcursor;
363 skinframe_t *r_editlights_sprlight;
364 skinframe_t *r_editlights_sprnoshadowlight;
365 skinframe_t *r_editlights_sprcubemaplight;
366 skinframe_t *r_editlights_sprcubemapnoshadowlight;
367 skinframe_t *r_editlights_sprselection;
369 void R_Shadow_SetShadowMode(void)
371 r_shadow_shadowmapmaxsize = bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4);
372 r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20;
373 r_shadow_shadowmapfilterquality = r_shadow_shadowmapping_filterquality.integer;
374 r_shadow_shadowmapdepthbits = r_shadow_shadowmapping_depthbits.integer;
375 r_shadow_shadowmapborder = bound(0, r_shadow_shadowmapping_bordersize.integer, 16);
376 r_shadow_shadowmaplod = -1;
377 r_shadow_shadowmapsize = 0;
378 r_shadow_shadowmapsampler = false;
379 r_shadow_shadowmappcf = 0;
380 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
381 if ((r_shadow_shadowmapping.integer || r_shadow_deferred.integer) && vid.support.ext_framebuffer_object)
383 switch(vid.renderpath)
385 case RENDERPATH_GL20:
386 if(r_shadow_shadowmapfilterquality < 0)
388 if(vid.support.amd_texture_texture4 || vid.support.arb_texture_gather)
389 r_shadow_shadowmappcf = 1;
390 else if(strstr(gl_vendor, "NVIDIA") || strstr(gl_renderer, "Radeon HD"))
392 r_shadow_shadowmapsampler = vid.support.arb_shadow;
393 r_shadow_shadowmappcf = 1;
395 else if(strstr(gl_vendor, "ATI"))
396 r_shadow_shadowmappcf = 1;
398 r_shadow_shadowmapsampler = vid.support.arb_shadow;
402 switch (r_shadow_shadowmapfilterquality)
405 r_shadow_shadowmapsampler = vid.support.arb_shadow;
408 r_shadow_shadowmapsampler = vid.support.arb_shadow;
409 r_shadow_shadowmappcf = 1;
412 r_shadow_shadowmappcf = 1;
415 r_shadow_shadowmappcf = 2;
419 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
420 // Cg has very little choice in depth texture sampling
422 r_shadow_shadowmapsampler = false;
424 case RENDERPATH_CGGL:
425 case RENDERPATH_D3D9:
426 case RENDERPATH_D3D10:
427 case RENDERPATH_D3D11:
428 r_shadow_shadowmapsampler = false;
429 r_shadow_shadowmappcf = 1;
430 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
432 case RENDERPATH_GL13:
434 case RENDERPATH_GL11:
440 qboolean R_Shadow_ShadowMappingEnabled(void)
442 switch (r_shadow_shadowmode)
444 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
451 void R_Shadow_FreeShadowMaps(void)
453 R_Shadow_SetShadowMode();
455 R_Mesh_DestroyFramebufferObject(r_shadow_fbo2d);
459 if (r_shadow_shadowmap2dtexture)
460 R_FreeTexture(r_shadow_shadowmap2dtexture);
461 r_shadow_shadowmap2dtexture = NULL;
463 if (r_shadow_shadowmap2dcolortexture)
464 R_FreeTexture(r_shadow_shadowmap2dcolortexture);
465 r_shadow_shadowmap2dcolortexture = NULL;
467 if (r_shadow_shadowmapvsdcttexture)
468 R_FreeTexture(r_shadow_shadowmapvsdcttexture);
469 r_shadow_shadowmapvsdcttexture = NULL;
472 void r_shadow_start(void)
474 // allocate vertex processing arrays
475 r_shadow_attenuationgradienttexture = NULL;
476 r_shadow_attenuation2dtexture = NULL;
477 r_shadow_attenuation3dtexture = NULL;
478 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
479 r_shadow_shadowmap2dtexture = NULL;
480 r_shadow_shadowmap2dcolortexture = NULL;
481 r_shadow_shadowmapvsdcttexture = NULL;
482 r_shadow_shadowmapmaxsize = 0;
483 r_shadow_shadowmapsize = 0;
484 r_shadow_shadowmaplod = 0;
485 r_shadow_shadowmapfilterquality = -1;
486 r_shadow_shadowmapdepthbits = 0;
487 r_shadow_shadowmapvsdct = false;
488 r_shadow_shadowmapsampler = false;
489 r_shadow_shadowmappcf = 0;
492 R_Shadow_FreeShadowMaps();
494 r_shadow_texturepool = NULL;
495 r_shadow_filters_texturepool = NULL;
496 R_Shadow_ValidateCvars();
497 R_Shadow_MakeTextures();
498 maxshadowtriangles = 0;
499 shadowelements = NULL;
500 maxshadowvertices = 0;
501 shadowvertex3f = NULL;
509 shadowmarklist = NULL;
514 shadowsideslist = NULL;
515 r_shadow_buffer_numleafpvsbytes = 0;
516 r_shadow_buffer_visitingleafpvs = NULL;
517 r_shadow_buffer_leafpvs = NULL;
518 r_shadow_buffer_leaflist = NULL;
519 r_shadow_buffer_numsurfacepvsbytes = 0;
520 r_shadow_buffer_surfacepvs = NULL;
521 r_shadow_buffer_surfacelist = NULL;
522 r_shadow_buffer_surfacesides = NULL;
523 r_shadow_buffer_numshadowtrispvsbytes = 0;
524 r_shadow_buffer_shadowtrispvs = NULL;
525 r_shadow_buffer_numlighttrispvsbytes = 0;
526 r_shadow_buffer_lighttrispvs = NULL;
528 r_shadow_usingdeferredprepass = false;
529 r_shadow_prepass_width = r_shadow_prepass_height = 0;
532 static void R_Shadow_FreeDeferred(void);
533 void r_shadow_shutdown(void)
536 R_Shadow_UncompileWorldLights();
538 R_Shadow_FreeShadowMaps();
540 r_shadow_usingdeferredprepass = false;
541 if (r_shadow_prepass_width)
542 R_Shadow_FreeDeferred();
543 r_shadow_prepass_width = r_shadow_prepass_height = 0;
546 r_shadow_attenuationgradienttexture = NULL;
547 r_shadow_attenuation2dtexture = NULL;
548 r_shadow_attenuation3dtexture = NULL;
549 R_FreeTexturePool(&r_shadow_texturepool);
550 R_FreeTexturePool(&r_shadow_filters_texturepool);
551 maxshadowtriangles = 0;
553 Mem_Free(shadowelements);
554 shadowelements = NULL;
556 Mem_Free(shadowvertex3f);
557 shadowvertex3f = NULL;
560 Mem_Free(vertexupdate);
563 Mem_Free(vertexremap);
569 Mem_Free(shadowmark);
572 Mem_Free(shadowmarklist);
573 shadowmarklist = NULL;
578 Mem_Free(shadowsides);
581 Mem_Free(shadowsideslist);
582 shadowsideslist = NULL;
583 r_shadow_buffer_numleafpvsbytes = 0;
584 if (r_shadow_buffer_visitingleafpvs)
585 Mem_Free(r_shadow_buffer_visitingleafpvs);
586 r_shadow_buffer_visitingleafpvs = NULL;
587 if (r_shadow_buffer_leafpvs)
588 Mem_Free(r_shadow_buffer_leafpvs);
589 r_shadow_buffer_leafpvs = NULL;
590 if (r_shadow_buffer_leaflist)
591 Mem_Free(r_shadow_buffer_leaflist);
592 r_shadow_buffer_leaflist = NULL;
593 r_shadow_buffer_numsurfacepvsbytes = 0;
594 if (r_shadow_buffer_surfacepvs)
595 Mem_Free(r_shadow_buffer_surfacepvs);
596 r_shadow_buffer_surfacepvs = NULL;
597 if (r_shadow_buffer_surfacelist)
598 Mem_Free(r_shadow_buffer_surfacelist);
599 r_shadow_buffer_surfacelist = NULL;
600 if (r_shadow_buffer_surfacesides)
601 Mem_Free(r_shadow_buffer_surfacesides);
602 r_shadow_buffer_surfacesides = NULL;
603 r_shadow_buffer_numshadowtrispvsbytes = 0;
604 if (r_shadow_buffer_shadowtrispvs)
605 Mem_Free(r_shadow_buffer_shadowtrispvs);
606 r_shadow_buffer_numlighttrispvsbytes = 0;
607 if (r_shadow_buffer_lighttrispvs)
608 Mem_Free(r_shadow_buffer_lighttrispvs);
611 void r_shadow_newmap(void)
613 if (r_shadow_lightcorona) R_SkinFrame_MarkUsed(r_shadow_lightcorona);
614 if (r_editlights_sprcursor) R_SkinFrame_MarkUsed(r_editlights_sprcursor);
615 if (r_editlights_sprlight) R_SkinFrame_MarkUsed(r_editlights_sprlight);
616 if (r_editlights_sprnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprnoshadowlight);
617 if (r_editlights_sprcubemaplight) R_SkinFrame_MarkUsed(r_editlights_sprcubemaplight);
618 if (r_editlights_sprcubemapnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprcubemapnoshadowlight);
619 if (r_editlights_sprselection) R_SkinFrame_MarkUsed(r_editlights_sprselection);
620 if (strncmp(cl.worldname, r_shadow_mapname, sizeof(r_shadow_mapname)))
621 R_Shadow_EditLights_Reload_f();
624 void R_Shadow_Init(void)
626 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
627 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
628 Cvar_RegisterVariable(&r_shadow_usenormalmap);
629 Cvar_RegisterVariable(&r_shadow_debuglight);
630 Cvar_RegisterVariable(&r_shadow_deferred);
631 Cvar_RegisterVariable(&r_shadow_deferred_8bitrange);
632 // Cvar_RegisterVariable(&r_shadow_deferred_fp);
633 Cvar_RegisterVariable(&r_shadow_gloss);
634 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
635 Cvar_RegisterVariable(&r_shadow_glossintensity);
636 Cvar_RegisterVariable(&r_shadow_glossexponent);
637 Cvar_RegisterVariable(&r_shadow_gloss2exponent);
638 Cvar_RegisterVariable(&r_shadow_glossexact);
639 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
640 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
641 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
642 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
643 Cvar_RegisterVariable(&r_shadow_projectdistance);
644 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
645 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
646 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
647 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
648 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
649 Cvar_RegisterVariable(&r_shadow_realtime_world);
650 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
651 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
652 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
653 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
654 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
655 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
656 Cvar_RegisterVariable(&r_shadow_scissor);
657 Cvar_RegisterVariable(&r_shadow_shadowmapping);
658 Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
659 Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
660 Cvar_RegisterVariable(&r_shadow_shadowmapping_depthbits);
661 Cvar_RegisterVariable(&r_shadow_shadowmapping_precision);
662 Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
663 Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
664 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
665 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
666 Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
667 Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
668 Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
669 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonfactor);
670 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonoffset);
671 Cvar_RegisterVariable(&r_shadow_polygonfactor);
672 Cvar_RegisterVariable(&r_shadow_polygonoffset);
673 Cvar_RegisterVariable(&r_shadow_texture3d);
674 Cvar_RegisterVariable(&r_coronas);
675 Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
676 Cvar_RegisterVariable(&r_coronas_occlusionquery);
677 Cvar_RegisterVariable(&gl_flashblend);
678 Cvar_RegisterVariable(&gl_ext_separatestencil);
679 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
680 if (gamemode == GAME_TENEBRAE)
682 Cvar_SetValue("r_shadow_gloss", 2);
683 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
685 R_Shadow_EditLights_Init();
686 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
687 maxshadowtriangles = 0;
688 shadowelements = NULL;
689 maxshadowvertices = 0;
690 shadowvertex3f = NULL;
698 shadowmarklist = NULL;
703 shadowsideslist = NULL;
704 r_shadow_buffer_numleafpvsbytes = 0;
705 r_shadow_buffer_visitingleafpvs = NULL;
706 r_shadow_buffer_leafpvs = NULL;
707 r_shadow_buffer_leaflist = NULL;
708 r_shadow_buffer_numsurfacepvsbytes = 0;
709 r_shadow_buffer_surfacepvs = NULL;
710 r_shadow_buffer_surfacelist = NULL;
711 r_shadow_buffer_surfacesides = NULL;
712 r_shadow_buffer_shadowtrispvs = NULL;
713 r_shadow_buffer_lighttrispvs = NULL;
714 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap, NULL, NULL);
717 matrix4x4_t matrix_attenuationxyz =
720 {0.5, 0.0, 0.0, 0.5},
721 {0.0, 0.5, 0.0, 0.5},
722 {0.0, 0.0, 0.5, 0.5},
727 matrix4x4_t matrix_attenuationz =
730 {0.0, 0.0, 0.5, 0.5},
731 {0.0, 0.0, 0.0, 0.5},
732 {0.0, 0.0, 0.0, 0.5},
737 void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles, int vertscale, int triscale)
739 numvertices = ((numvertices + 255) & ~255) * vertscale;
740 numtriangles = ((numtriangles + 255) & ~255) * triscale;
741 // make sure shadowelements is big enough for this volume
742 if (maxshadowtriangles < numtriangles)
744 maxshadowtriangles = numtriangles;
746 Mem_Free(shadowelements);
747 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[3]));
749 // make sure shadowvertex3f is big enough for this volume
750 if (maxshadowvertices < numvertices)
752 maxshadowvertices = numvertices;
754 Mem_Free(shadowvertex3f);
755 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[3]));
759 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
761 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
762 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
763 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
764 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
765 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
767 if (r_shadow_buffer_visitingleafpvs)
768 Mem_Free(r_shadow_buffer_visitingleafpvs);
769 if (r_shadow_buffer_leafpvs)
770 Mem_Free(r_shadow_buffer_leafpvs);
771 if (r_shadow_buffer_leaflist)
772 Mem_Free(r_shadow_buffer_leaflist);
773 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
774 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
775 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
776 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
778 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
780 if (r_shadow_buffer_surfacepvs)
781 Mem_Free(r_shadow_buffer_surfacepvs);
782 if (r_shadow_buffer_surfacelist)
783 Mem_Free(r_shadow_buffer_surfacelist);
784 if (r_shadow_buffer_surfacesides)
785 Mem_Free(r_shadow_buffer_surfacesides);
786 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
787 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
788 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
789 r_shadow_buffer_surfacesides = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
791 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
793 if (r_shadow_buffer_shadowtrispvs)
794 Mem_Free(r_shadow_buffer_shadowtrispvs);
795 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
796 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
798 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
800 if (r_shadow_buffer_lighttrispvs)
801 Mem_Free(r_shadow_buffer_lighttrispvs);
802 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
803 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
807 void R_Shadow_PrepareShadowMark(int numtris)
809 // make sure shadowmark is big enough for this volume
810 if (maxshadowmark < numtris)
812 maxshadowmark = numtris;
814 Mem_Free(shadowmark);
816 Mem_Free(shadowmarklist);
817 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
818 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
822 // if shadowmarkcount wrapped we clear the array and adjust accordingly
823 if (shadowmarkcount == 0)
826 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
831 void R_Shadow_PrepareShadowSides(int numtris)
833 if (maxshadowsides < numtris)
835 maxshadowsides = numtris;
837 Mem_Free(shadowsides);
839 Mem_Free(shadowsideslist);
840 shadowsides = (unsigned char *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsides));
841 shadowsideslist = (int *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsideslist));
846 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)
849 int outtriangles = 0, outvertices = 0;
852 float ratio, direction[3], projectvector[3];
854 if (projectdirection)
855 VectorScale(projectdirection, projectdistance, projectvector);
857 VectorClear(projectvector);
859 // create the vertices
860 if (projectdirection)
862 for (i = 0;i < numshadowmarktris;i++)
864 element = inelement3i + shadowmarktris[i] * 3;
865 for (j = 0;j < 3;j++)
867 if (vertexupdate[element[j]] != vertexupdatenum)
869 vertexupdate[element[j]] = vertexupdatenum;
870 vertexremap[element[j]] = outvertices;
871 vertex = invertex3f + element[j] * 3;
872 // project one copy of the vertex according to projectvector
873 VectorCopy(vertex, outvertex3f);
874 VectorAdd(vertex, projectvector, (outvertex3f + 3));
883 for (i = 0;i < numshadowmarktris;i++)
885 element = inelement3i + shadowmarktris[i] * 3;
886 for (j = 0;j < 3;j++)
888 if (vertexupdate[element[j]] != vertexupdatenum)
890 vertexupdate[element[j]] = vertexupdatenum;
891 vertexremap[element[j]] = outvertices;
892 vertex = invertex3f + element[j] * 3;
893 // project one copy of the vertex to the sphere radius of the light
894 // (FIXME: would projecting it to the light box be better?)
895 VectorSubtract(vertex, projectorigin, direction);
896 ratio = projectdistance / VectorLength(direction);
897 VectorCopy(vertex, outvertex3f);
898 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
906 if (r_shadow_frontsidecasting.integer)
908 for (i = 0;i < numshadowmarktris;i++)
910 int remappedelement[3];
912 const int *neighbortriangle;
914 markindex = shadowmarktris[i] * 3;
915 element = inelement3i + markindex;
916 neighbortriangle = inneighbor3i + markindex;
917 // output the front and back triangles
918 outelement3i[0] = vertexremap[element[0]];
919 outelement3i[1] = vertexremap[element[1]];
920 outelement3i[2] = vertexremap[element[2]];
921 outelement3i[3] = vertexremap[element[2]] + 1;
922 outelement3i[4] = vertexremap[element[1]] + 1;
923 outelement3i[5] = vertexremap[element[0]] + 1;
927 // output the sides (facing outward from this triangle)
928 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
930 remappedelement[0] = vertexremap[element[0]];
931 remappedelement[1] = vertexremap[element[1]];
932 outelement3i[0] = remappedelement[1];
933 outelement3i[1] = remappedelement[0];
934 outelement3i[2] = remappedelement[0] + 1;
935 outelement3i[3] = remappedelement[1];
936 outelement3i[4] = remappedelement[0] + 1;
937 outelement3i[5] = remappedelement[1] + 1;
942 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
944 remappedelement[1] = vertexremap[element[1]];
945 remappedelement[2] = vertexremap[element[2]];
946 outelement3i[0] = remappedelement[2];
947 outelement3i[1] = remappedelement[1];
948 outelement3i[2] = remappedelement[1] + 1;
949 outelement3i[3] = remappedelement[2];
950 outelement3i[4] = remappedelement[1] + 1;
951 outelement3i[5] = remappedelement[2] + 1;
956 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
958 remappedelement[0] = vertexremap[element[0]];
959 remappedelement[2] = vertexremap[element[2]];
960 outelement3i[0] = remappedelement[0];
961 outelement3i[1] = remappedelement[2];
962 outelement3i[2] = remappedelement[2] + 1;
963 outelement3i[3] = remappedelement[0];
964 outelement3i[4] = remappedelement[2] + 1;
965 outelement3i[5] = remappedelement[0] + 1;
974 for (i = 0;i < numshadowmarktris;i++)
976 int remappedelement[3];
978 const int *neighbortriangle;
980 markindex = shadowmarktris[i] * 3;
981 element = inelement3i + markindex;
982 neighbortriangle = inneighbor3i + markindex;
983 // output the front and back triangles
984 outelement3i[0] = vertexremap[element[2]];
985 outelement3i[1] = vertexremap[element[1]];
986 outelement3i[2] = vertexremap[element[0]];
987 outelement3i[3] = vertexremap[element[0]] + 1;
988 outelement3i[4] = vertexremap[element[1]] + 1;
989 outelement3i[5] = vertexremap[element[2]] + 1;
993 // output the sides (facing outward from this triangle)
994 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
996 remappedelement[0] = vertexremap[element[0]];
997 remappedelement[1] = vertexremap[element[1]];
998 outelement3i[0] = remappedelement[0];
999 outelement3i[1] = remappedelement[1];
1000 outelement3i[2] = remappedelement[1] + 1;
1001 outelement3i[3] = remappedelement[0];
1002 outelement3i[4] = remappedelement[1] + 1;
1003 outelement3i[5] = remappedelement[0] + 1;
1008 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1010 remappedelement[1] = vertexremap[element[1]];
1011 remappedelement[2] = vertexremap[element[2]];
1012 outelement3i[0] = remappedelement[1];
1013 outelement3i[1] = remappedelement[2];
1014 outelement3i[2] = remappedelement[2] + 1;
1015 outelement3i[3] = remappedelement[1];
1016 outelement3i[4] = remappedelement[2] + 1;
1017 outelement3i[5] = remappedelement[1] + 1;
1022 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1024 remappedelement[0] = vertexremap[element[0]];
1025 remappedelement[2] = vertexremap[element[2]];
1026 outelement3i[0] = remappedelement[2];
1027 outelement3i[1] = remappedelement[0];
1028 outelement3i[2] = remappedelement[0] + 1;
1029 outelement3i[3] = remappedelement[2];
1030 outelement3i[4] = remappedelement[0] + 1;
1031 outelement3i[5] = remappedelement[2] + 1;
1039 *outnumvertices = outvertices;
1040 return outtriangles;
1043 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)
1046 int outtriangles = 0, outvertices = 0;
1048 const float *vertex;
1049 float ratio, direction[3], projectvector[3];
1052 if (projectdirection)
1053 VectorScale(projectdirection, projectdistance, projectvector);
1055 VectorClear(projectvector);
1057 for (i = 0;i < numshadowmarktris;i++)
1059 int remappedelement[3];
1061 const int *neighbortriangle;
1063 markindex = shadowmarktris[i] * 3;
1064 neighbortriangle = inneighbor3i + markindex;
1065 side[0] = shadowmark[neighbortriangle[0]] == shadowmarkcount;
1066 side[1] = shadowmark[neighbortriangle[1]] == shadowmarkcount;
1067 side[2] = shadowmark[neighbortriangle[2]] == shadowmarkcount;
1068 if (side[0] + side[1] + side[2] == 0)
1072 element = inelement3i + markindex;
1074 // create the vertices
1075 for (j = 0;j < 3;j++)
1077 if (side[j] + side[j+1] == 0)
1080 if (vertexupdate[k] != vertexupdatenum)
1082 vertexupdate[k] = vertexupdatenum;
1083 vertexremap[k] = outvertices;
1084 vertex = invertex3f + k * 3;
1085 VectorCopy(vertex, outvertex3f);
1086 if (projectdirection)
1088 // project one copy of the vertex according to projectvector
1089 VectorAdd(vertex, projectvector, (outvertex3f + 3));
1093 // project one copy of the vertex to the sphere radius of the light
1094 // (FIXME: would projecting it to the light box be better?)
1095 VectorSubtract(vertex, projectorigin, direction);
1096 ratio = projectdistance / VectorLength(direction);
1097 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1104 // output the sides (facing outward from this triangle)
1107 remappedelement[0] = vertexremap[element[0]];
1108 remappedelement[1] = vertexremap[element[1]];
1109 outelement3i[0] = remappedelement[1];
1110 outelement3i[1] = remappedelement[0];
1111 outelement3i[2] = remappedelement[0] + 1;
1112 outelement3i[3] = remappedelement[1];
1113 outelement3i[4] = remappedelement[0] + 1;
1114 outelement3i[5] = remappedelement[1] + 1;
1121 remappedelement[1] = vertexremap[element[1]];
1122 remappedelement[2] = vertexremap[element[2]];
1123 outelement3i[0] = remappedelement[2];
1124 outelement3i[1] = remappedelement[1];
1125 outelement3i[2] = remappedelement[1] + 1;
1126 outelement3i[3] = remappedelement[2];
1127 outelement3i[4] = remappedelement[1] + 1;
1128 outelement3i[5] = remappedelement[2] + 1;
1135 remappedelement[0] = vertexremap[element[0]];
1136 remappedelement[2] = vertexremap[element[2]];
1137 outelement3i[0] = remappedelement[0];
1138 outelement3i[1] = remappedelement[2];
1139 outelement3i[2] = remappedelement[2] + 1;
1140 outelement3i[3] = remappedelement[0];
1141 outelement3i[4] = remappedelement[2] + 1;
1142 outelement3i[5] = remappedelement[0] + 1;
1149 *outnumvertices = outvertices;
1150 return outtriangles;
1153 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)
1159 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1161 tend = firsttriangle + numtris;
1162 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1164 // surface box entirely inside light box, no box cull
1165 if (projectdirection)
1167 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1169 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
1170 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1171 shadowmarklist[numshadowmark++] = t;
1176 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1177 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
1178 shadowmarklist[numshadowmark++] = t;
1183 // surface box not entirely inside light box, cull each triangle
1184 if (projectdirection)
1186 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1188 v[0] = invertex3f + e[0] * 3;
1189 v[1] = invertex3f + e[1] * 3;
1190 v[2] = invertex3f + e[2] * 3;
1191 TriangleNormal(v[0], v[1], v[2], normal);
1192 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1193 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1194 shadowmarklist[numshadowmark++] = t;
1199 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1201 v[0] = invertex3f + e[0] * 3;
1202 v[1] = invertex3f + e[1] * 3;
1203 v[2] = invertex3f + e[2] * 3;
1204 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1205 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1206 shadowmarklist[numshadowmark++] = t;
1212 qboolean R_Shadow_UseZPass(vec3_t mins, vec3_t maxs)
1217 if (r_shadow_compilingrtlight || !r_shadow_frontsidecasting.integer || !r_shadow_usezpassifpossible.integer)
1219 // check if the shadow volume intersects the near plane
1221 // a ray between the eye and light origin may intersect the caster,
1222 // indicating that the shadow may touch the eye location, however we must
1223 // test the near plane (a polygon), not merely the eye location, so it is
1224 // easiest to enlarge the caster bounding shape slightly for this.
1230 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)
1232 int i, tris, outverts;
1233 if (projectdistance < 0.1)
1235 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
1238 if (!numverts || !nummarktris)
1240 // make sure shadowelements is big enough for this volume
1241 if (maxshadowtriangles < nummarktris*8 || maxshadowvertices < numverts*2)
1242 R_Shadow_ResizeShadowArrays(numverts, nummarktris, 2, 8);
1244 if (maxvertexupdate < numverts)
1246 maxvertexupdate = numverts;
1248 Mem_Free(vertexupdate);
1250 Mem_Free(vertexremap);
1251 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1252 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1253 vertexupdatenum = 0;
1256 if (vertexupdatenum == 0)
1258 vertexupdatenum = 1;
1259 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
1260 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
1263 for (i = 0;i < nummarktris;i++)
1264 shadowmark[marktris[i]] = shadowmarkcount;
1266 if (r_shadow_compilingrtlight)
1268 // if we're compiling an rtlight, capture the mesh
1269 //tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1270 //Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zpass, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1271 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1272 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zfail, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1274 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
1276 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1277 R_Mesh_PrepareVertices_Position_Arrays(outverts, shadowvertex3f);
1278 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1282 // decide which type of shadow to generate and set stencil mode
1283 R_Shadow_RenderMode_StencilShadowVolumes(R_Shadow_UseZPass(trismins, trismaxs));
1284 // generate the sides or a solid volume, depending on type
1285 if (r_shadow_rendermode >= R_SHADOW_RENDERMODE_ZPASS_STENCIL && r_shadow_rendermode <= R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE)
1286 tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1288 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1289 r_refdef.stats.lights_dynamicshadowtriangles += tris;
1290 r_refdef.stats.lights_shadowtriangles += tris;
1291 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
1293 // increment stencil if frontface is infront of depthbuffer
1294 GL_CullFace(r_refdef.view.cullface_front);
1295 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
1296 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1297 // decrement stencil if backface is infront of depthbuffer
1298 GL_CullFace(r_refdef.view.cullface_back);
1299 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
1301 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
1303 // decrement stencil if backface is behind depthbuffer
1304 GL_CullFace(r_refdef.view.cullface_front);
1305 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
1306 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1307 // increment stencil if frontface is behind depthbuffer
1308 GL_CullFace(r_refdef.view.cullface_back);
1309 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
1311 R_Mesh_PrepareVertices_Position_Arrays(outverts, shadowvertex3f);
1312 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1316 int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias)
1318 // p1, p2, p3 are in the cubemap's local coordinate system
1319 // bias = border/(size - border)
1322 float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1323 dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2),
1324 dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3);
1325 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1327 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1328 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1329 | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1330 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1332 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1333 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1334 | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1336 dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1337 dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2),
1338 dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3);
1339 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1341 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1342 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1343 | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1344 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1346 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1347 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1348 | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1350 dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1351 dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2),
1352 dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3);
1353 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1355 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1356 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1357 | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1358 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1360 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1361 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1362 | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1367 int R_Shadow_CalcBBoxSideMask(const vec3_t mins, const vec3_t maxs, const matrix4x4_t *worldtolight, const matrix4x4_t *radiustolight, float bias)
1369 vec3_t center, radius, lightcenter, lightradius, pmin, pmax;
1370 float dp1, dn1, ap1, an1, dp2, dn2, ap2, an2;
1373 VectorSubtract(maxs, mins, radius);
1374 VectorScale(radius, 0.5f, radius);
1375 VectorAdd(mins, radius, center);
1376 Matrix4x4_Transform(worldtolight, center, lightcenter);
1377 Matrix4x4_Transform3x3(radiustolight, radius, lightradius);
1378 VectorSubtract(lightcenter, lightradius, pmin);
1379 VectorAdd(lightcenter, lightradius, pmax);
1381 dp1 = pmax[0] + pmax[1], dn1 = pmax[0] - pmin[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1382 dp2 = pmin[0] + pmin[1], dn2 = pmin[0] - pmax[1], ap2 = fabs(dp2), an2 = fabs(dn2);
1383 if(ap1 > bias*an1 && ap2 > bias*an2)
1385 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1386 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1387 if(an1 > bias*ap1 && an2 > bias*ap2)
1389 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1390 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1392 dp1 = pmax[1] + pmax[2], dn1 = pmax[1] - pmin[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1393 dp2 = pmin[1] + pmin[2], dn2 = pmin[1] - pmax[2], ap2 = fabs(dp2), an2 = fabs(dn2);
1394 if(ap1 > bias*an1 && ap2 > bias*an2)
1396 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1397 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1398 if(an1 > bias*ap1 && an2 > bias*ap2)
1400 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1401 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1403 dp1 = pmax[2] + pmax[0], dn1 = pmax[2] - pmin[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1404 dp2 = pmin[2] + pmin[0], dn2 = pmin[2] - pmax[0], ap2 = fabs(dp2), an2 = fabs(dn2);
1405 if(ap1 > bias*an1 && ap2 > bias*an2)
1407 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1408 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1409 if(an1 > bias*ap1 && an2 > bias*ap2)
1411 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1412 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1417 #define R_Shadow_CalcEntitySideMask(ent, worldtolight, radiustolight, bias) R_Shadow_CalcBBoxSideMask((ent)->mins, (ent)->maxs, worldtolight, radiustolight, bias)
1419 int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
1421 // p is in the cubemap's local coordinate system
1422 // bias = border/(size - border)
1423 float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn);
1424 float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn);
1425 float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn);
1427 if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
1428 if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
1429 if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
1430 if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
1431 if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
1432 if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
1436 int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
1440 int sides = 0x3F, masks[6] = { 3<<4, 3<<4, 3<<0, 3<<0, 3<<2, 3<<2 };
1441 float scale = (size - 2*border)/size, len;
1442 float bias = border / (float)(size - border), dp, dn, ap, an;
1443 // check if cone enclosing side would cross frustum plane
1444 scale = 2 / (scale*scale + 2);
1445 for (i = 0;i < 5;i++)
1447 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) > -0.03125)
1449 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[i].normal, n);
1450 len = scale*VectorLength2(n);
1451 if(n[0]*n[0] > len) sides &= n[0] < 0 ? ~(1<<0) : ~(2 << 0);
1452 if(n[1]*n[1] > len) sides &= n[1] < 0 ? ~(1<<2) : ~(2 << 2);
1453 if(n[2]*n[2] > len) sides &= n[2] < 0 ? ~(1<<4) : ~(2 << 4);
1455 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[4]) >= r_refdef.farclip - r_refdef.nearclip + 0.03125)
1457 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[4].normal, n);
1458 len = scale*VectorLength(n);
1459 if(n[0]*n[0] > len) sides &= n[0] >= 0 ? ~(1<<0) : ~(2 << 0);
1460 if(n[1]*n[1] > len) sides &= n[1] >= 0 ? ~(1<<2) : ~(2 << 2);
1461 if(n[2]*n[2] > len) sides &= n[2] >= 0 ? ~(1<<4) : ~(2 << 4);
1463 // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results
1464 // check if frustum corners/origin cross plane sides
1466 // infinite version, assumes frustum corners merely give direction and extend to infinite distance
1467 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.origin, p);
1468 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1469 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1470 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1471 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1472 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1473 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1474 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1475 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1476 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1477 for (i = 0;i < 4;i++)
1479 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.frustumcorner[i], n);
1480 VectorSubtract(n, p, n);
1481 dp = n[0] + n[1], dn = n[0] - n[1], ap = fabs(dp), an = fabs(dn);
1482 if(ap > 0) masks[0] |= dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2);
1483 if(an > 0) masks[1] |= dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2);
1484 dp = n[1] + n[2], dn = n[1] - n[2], ap = fabs(dp), an = fabs(dn);
1485 if(ap > 0) masks[2] |= dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4);
1486 if(an > 0) masks[3] |= dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4);
1487 dp = n[2] + n[0], dn = n[2] - n[0], ap = fabs(dp), an = fabs(dn);
1488 if(ap > 0) masks[4] |= dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0);
1489 if(an > 0) masks[5] |= dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0);
1492 // finite version, assumes corners are a finite distance from origin dependent on far plane
1493 for (i = 0;i < 5;i++)
1495 Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p);
1496 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1497 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1498 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1499 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1500 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1501 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1502 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1503 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1504 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1507 return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5];
1510 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)
1518 int mask, surfacemask = 0;
1519 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1521 bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
1522 tend = firsttriangle + numtris;
1523 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1525 // surface box entirely inside light box, no box cull
1526 if (projectdirection)
1528 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1530 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1531 TriangleNormal(v[0], v[1], v[2], normal);
1532 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1534 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1535 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1536 surfacemask |= mask;
1539 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;
1540 shadowsides[numshadowsides] = mask;
1541 shadowsideslist[numshadowsides++] = t;
1548 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1550 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1551 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]))
1553 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1554 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1555 surfacemask |= mask;
1558 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;
1559 shadowsides[numshadowsides] = mask;
1560 shadowsideslist[numshadowsides++] = t;
1568 // surface box not entirely inside light box, cull each triangle
1569 if (projectdirection)
1571 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1573 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1574 TriangleNormal(v[0], v[1], v[2], normal);
1575 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1576 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1578 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1579 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1580 surfacemask |= mask;
1583 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;
1584 shadowsides[numshadowsides] = mask;
1585 shadowsideslist[numshadowsides++] = t;
1592 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1594 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1595 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1596 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1598 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1599 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1600 surfacemask |= mask;
1603 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;
1604 shadowsides[numshadowsides] = mask;
1605 shadowsideslist[numshadowsides++] = t;
1614 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)
1616 int i, j, outtriangles = 0;
1617 int *outelement3i[6];
1618 if (!numverts || !numsidetris || !r_shadow_compilingrtlight)
1620 outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5];
1621 // make sure shadowelements is big enough for this mesh
1622 if (maxshadowtriangles < outtriangles)
1623 R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1);
1625 // compute the offset and size of the separate index lists for each cubemap side
1627 for (i = 0;i < 6;i++)
1629 outelement3i[i] = shadowelements + outtriangles * 3;
1630 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles;
1631 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i];
1632 outtriangles += sidetotals[i];
1635 // gather up the (sparse) triangles into separate index lists for each cubemap side
1636 for (i = 0;i < numsidetris;i++)
1638 const int *element = elements + sidetris[i] * 3;
1639 for (j = 0;j < 6;j++)
1641 if (sides[i] & (1 << j))
1643 outelement3i[j][0] = element[0];
1644 outelement3i[j][1] = element[1];
1645 outelement3i[j][2] = element[2];
1646 outelement3i[j] += 3;
1651 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, outtriangles, shadowelements);
1654 static void R_Shadow_MakeTextures_MakeCorona(void)
1658 unsigned char pixels[32][32][4];
1659 for (y = 0;y < 32;y++)
1661 dy = (y - 15.5f) * (1.0f / 16.0f);
1662 for (x = 0;x < 32;x++)
1664 dx = (x - 15.5f) * (1.0f / 16.0f);
1665 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1666 a = bound(0, a, 255);
1667 pixels[y][x][0] = a;
1668 pixels[y][x][1] = a;
1669 pixels[y][x][2] = a;
1670 pixels[y][x][3] = 255;
1673 r_shadow_lightcorona = R_SkinFrame_LoadInternalBGRA("lightcorona", TEXF_FORCELINEAR, &pixels[0][0][0], 32, 32);
1676 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1678 float dist = sqrt(x*x+y*y+z*z);
1679 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1680 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1681 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1684 static void R_Shadow_MakeTextures(void)
1687 float intensity, dist;
1689 R_Shadow_FreeShadowMaps();
1690 R_FreeTexturePool(&r_shadow_texturepool);
1691 r_shadow_texturepool = R_AllocTexturePool();
1692 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1693 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1694 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1695 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1696 for (x = 0;x <= ATTENTABLESIZE;x++)
1698 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1699 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1700 r_shadow_attentable[x] = bound(0, intensity, 1);
1702 // 1D gradient texture
1703 for (x = 0;x < ATTEN1DSIZE;x++)
1704 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1705 r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1706 // 2D circle texture
1707 for (y = 0;y < ATTEN2DSIZE;y++)
1708 for (x = 0;x < ATTEN2DSIZE;x++)
1709 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);
1710 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1711 // 3D sphere texture
1712 if (r_shadow_texture3d.integer && vid.support.ext_texture_3d)
1714 for (z = 0;z < ATTEN3DSIZE;z++)
1715 for (y = 0;y < ATTEN3DSIZE;y++)
1716 for (x = 0;x < ATTEN3DSIZE;x++)
1717 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));
1718 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);
1721 r_shadow_attenuation3dtexture = NULL;
1724 R_Shadow_MakeTextures_MakeCorona();
1726 // Editor light sprites
1727 r_editlights_sprcursor = R_SkinFrame_LoadInternal8bit("gfx/editlights/cursor", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1744 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1745 r_editlights_sprlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/light", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1762 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1763 r_editlights_sprnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/noshadow", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1780 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1781 r_editlights_sprcubemaplight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemaplight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1798 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1799 r_editlights_sprcubemapnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemapnoshadowlight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1816 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1817 r_editlights_sprselection = R_SkinFrame_LoadInternal8bit("gfx/editlights/selection", TEXF_ALPHA | TEXF_CLAMP, (unsigned char *)
1834 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1837 void R_Shadow_ValidateCvars(void)
1839 if (r_shadow_texture3d.integer && !vid.support.ext_texture_3d)
1840 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1841 if (gl_ext_separatestencil.integer && !vid.support.ati_separate_stencil)
1842 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
1843 if (gl_ext_stenciltwoside.integer && !vid.support.ext_stencil_two_side)
1844 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1847 //static const r_vertexposition_t resetvertexposition[3] = {{0, 0, 0}};
1849 void R_Shadow_RenderMode_Begin(void)
1855 R_Shadow_ValidateCvars();
1857 if (!r_shadow_attenuation2dtexture
1858 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1859 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1860 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1861 R_Shadow_MakeTextures();
1864 R_Mesh_ResetTextureState();
1865 // R_Mesh_PrepareVertices_Position(0, resetvertexposition, NULL);
1866 GL_BlendFunc(GL_ONE, GL_ZERO);
1867 GL_DepthRange(0, 1);
1868 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1870 GL_DepthMask(false);
1871 GL_Color(0, 0, 0, 1);
1872 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1874 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1876 if (gl_ext_separatestencil.integer && vid.support.ati_separate_stencil)
1878 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
1879 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
1881 else if (gl_ext_stenciltwoside.integer && vid.support.ext_stencil_two_side)
1883 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
1884 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
1888 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
1889 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
1892 switch(vid.renderpath)
1894 case RENDERPATH_GL20:
1895 case RENDERPATH_CGGL:
1896 case RENDERPATH_D3D9:
1897 case RENDERPATH_D3D10:
1898 case RENDERPATH_D3D11:
1899 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1901 case RENDERPATH_GL13:
1902 case RENDERPATH_GL11:
1903 if (r_textureunits.integer >= 2 && vid.texunits >= 2 && r_shadow_texture3d.integer && r_shadow_attenuation3dtexture)
1904 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN;
1905 else if (r_textureunits.integer >= 3 && vid.texunits >= 3)
1906 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN;
1907 else if (r_textureunits.integer >= 2 && vid.texunits >= 2)
1908 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN;
1910 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1916 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
1917 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
1918 r_shadow_drawbuffer = drawbuffer;
1919 r_shadow_readbuffer = readbuffer;
1921 r_shadow_cullface_front = r_refdef.view.cullface_front;
1922 r_shadow_cullface_back = r_refdef.view.cullface_back;
1925 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
1927 rsurface.rtlight = rtlight;
1930 void R_Shadow_RenderMode_Reset(void)
1932 R_Mesh_ResetRenderTargets();
1933 R_SetViewport(&r_refdef.view.viewport);
1934 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
1935 R_Mesh_ResetTextureState();
1936 // R_Mesh_PrepareVertices_Position(0, resetvertexposition, NULL);
1937 GL_DepthRange(0, 1);
1939 GL_DepthMask(false);
1940 GL_DepthFunc(GL_LEQUAL);
1941 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1942 r_refdef.view.cullface_front = r_shadow_cullface_front;
1943 r_refdef.view.cullface_back = r_shadow_cullface_back;
1944 GL_CullFace(r_refdef.view.cullface_back);
1945 GL_Color(1, 1, 1, 1);
1946 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
1947 GL_BlendFunc(GL_ONE, GL_ZERO);
1948 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
1949 r_shadow_usingshadowmap2d = false;
1950 r_shadow_usingshadowmaportho = false;
1951 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
1954 void R_Shadow_ClearStencil(void)
1956 GL_Clear(GL_STENCIL_BUFFER_BIT, NULL, 1.0f, 128);
1957 r_refdef.stats.lights_clears++;
1960 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
1962 r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
1963 if (r_shadow_rendermode == mode)
1965 R_Shadow_RenderMode_Reset();
1966 GL_DepthFunc(GL_LESS);
1967 GL_ColorMask(0, 0, 0, 0);
1968 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1969 GL_CullFace(GL_NONE);
1970 R_SetupShader_DepthOrShadow();
1971 r_shadow_rendermode = mode;
1976 case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
1977 case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
1978 R_SetStencilSeparate(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, GL_ALWAYS, 128, 255);
1980 case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
1981 case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
1982 R_SetStencilSeparate(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, GL_ALWAYS, 128, 255);
1987 static void R_Shadow_MakeVSDCT(void)
1989 // maps to a 2x3 texture rectangle with normalized coordinates
1994 // stores abs(dir.xy), offset.xy/2.5
1995 unsigned char data[4*6] =
1997 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
1998 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
1999 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
2000 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
2001 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
2002 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
2004 r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
2007 static void R_Shadow_MakeShadowMap(int side, int size)
2009 switch (r_shadow_shadowmode)
2011 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2012 if (r_shadow_shadowmap2dtexture) return;
2013 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);
2014 r_shadow_shadowmap2dcolortexture = NULL;
2015 switch(vid.renderpath)
2018 case RENDERPATH_D3D9:
2019 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);
2020 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
2024 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2dtexture, NULL, NULL, NULL, NULL);
2032 // render depth into the fbo, do not render color at all
2033 // validate the fbo now
2037 qglDrawBuffer(GL_NONE);CHECKGLERROR
2038 qglReadBuffer(GL_NONE);CHECKGLERROR
2039 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2040 if (status != GL_FRAMEBUFFER_COMPLETE_EXT && (r_shadow_shadowmapping.integer || r_shadow_deferred.integer))
2042 Con_Printf("R_Shadow_MakeShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2043 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2044 Cvar_SetValueQuick(&r_shadow_deferred, 0);
2049 static float testcolor[4] = {0,1,0,1};
2050 void R_Shadow_RenderMode_ShadowMap(int side, int clear, int size)
2052 float nearclip, farclip, bias;
2053 r_viewport_t viewport;
2056 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
2058 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
2059 r_shadow_shadowmap_parameters[1] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
2060 r_shadow_shadowmap_parameters[3] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
2061 r_shadow_shadowmapside = side;
2062 r_shadow_shadowmapsize = size;
2064 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2065 r_shadow_shadowmap_parameters[2] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2066 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
2067 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D) goto init_done;
2069 // complex unrolled cube approach (more flexible)
2070 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2071 R_Shadow_MakeVSDCT();
2072 if (!r_shadow_shadowmap2dtexture)
2073 R_Shadow_MakeShadowMap(side, r_shadow_shadowmapmaxsize);
2074 if (r_shadow_shadowmap2dtexture) fbo = r_shadow_fbo2d;
2075 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
2076 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
2077 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
2079 R_Mesh_ResetTextureState();
2080 R_Mesh_ResetRenderTargets();
2081 R_Shadow_RenderMode_Reset();
2084 R_Mesh_SetRenderTargets(fbo, r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
2085 R_SetupShader_DepthOrShadow();
2088 R_SetupShader_ShowDepth();
2089 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
2094 R_SetViewport(&viewport);
2095 flipped = (side & 1) ^ (side >> 2);
2096 r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
2097 r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
2098 switch(vid.renderpath)
2100 case RENDERPATH_GL11:
2101 case RENDERPATH_GL13:
2102 case RENDERPATH_GL20:
2103 case RENDERPATH_CGGL:
2104 GL_CullFace(r_refdef.view.cullface_back);
2105 // OpenGL lets us scissor larger than the viewport, so go ahead and clear all views at once
2106 if ((clear & ((2 << side) - 1)) == (1 << side)) // only clear if the side is the first in the mask
2108 // get tightest scissor rectangle that encloses all viewports in the clear mask
2109 int x1 = clear & 0x15 ? 0 : size;
2110 int x2 = clear & 0x2A ? 2 * size : size;
2111 int y1 = clear & 0x03 ? 0 : (clear & 0xC ? size : 2 * size);
2112 int y2 = clear & 0x30 ? 3 * size : (clear & 0xC ? 2 * size : size);
2113 GL_Scissor(x1, y1, x2 - x1, y2 - y1);
2114 GL_Clear(GL_DEPTH_BUFFER_BIT, NULL, 1.0f, 0);
2116 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2118 case RENDERPATH_D3D9:
2119 // completely different meaning than in OpenGL path
2120 r_shadow_shadowmap_parameters[1] = 0;
2121 r_shadow_shadowmap_parameters[3] = -bias;
2122 // we invert the cull mode because we flip the projection matrix
2123 // NOTE: this actually does nothing because the DrawShadowMap code sets it to doublesided...
2124 GL_CullFace(r_refdef.view.cullface_front);
2125 // D3D considers it an error to use a scissor larger than the viewport... clear just this view
2126 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2127 if (r_shadow_shadowmapsampler)
2129 GL_ColorMask(0,0,0,0);
2131 GL_Clear(GL_DEPTH_BUFFER_BIT, testcolor, 1.0f, 0);
2135 GL_ColorMask(1,1,1,1);
2137 GL_Clear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT, testcolor, 1.0f, 0);
2140 case RENDERPATH_D3D10:
2141 case RENDERPATH_D3D11:
2142 // D3D considers it an error to use a scissor larger than the viewport... clear just this view
2143 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2144 GL_ColorMask(0,0,0,0);
2146 GL_Clear(GL_DEPTH_BUFFER_BIT, NULL, 1.0f, 0);
2151 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
2153 R_Mesh_ResetTextureState();
2154 R_Mesh_ResetRenderTargets();
2157 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2158 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2159 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2160 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2162 R_Shadow_RenderMode_Reset();
2163 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2165 GL_DepthFunc(GL_EQUAL);
2166 // do global setup needed for the chosen lighting mode
2167 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2168 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2169 r_shadow_usingshadowmap2d = shadowmapping;
2170 r_shadow_rendermode = r_shadow_lightingrendermode;
2171 // only draw light where this geometry was already rendered AND the
2172 // stencil is 128 (values other than this mean shadow)
2174 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2176 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
2179 static const unsigned short bboxelements[36] =
2189 static const float bboxpoints[8][3] =
2201 void R_Shadow_RenderMode_DrawDeferredLight(qboolean stenciltest, qboolean shadowmapping)
2204 float vertex3f[8*3];
2205 const matrix4x4_t *matrix = &rsurface.rtlight->matrix_lighttoworld;
2206 // do global setup needed for the chosen lighting mode
2207 R_Shadow_RenderMode_Reset();
2208 r_shadow_rendermode = r_shadow_lightingrendermode;
2209 R_EntityMatrix(&identitymatrix);
2210 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2211 // only draw light where this geometry was already rendered AND the
2212 // stencil is 128 (values other than this mean shadow)
2213 R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2214 R_Mesh_SetRenderTargets(r_shadow_prepasslightingfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
2216 r_shadow_usingshadowmap2d = shadowmapping;
2218 // render the lighting
2219 R_SetupShader_DeferredLight(rsurface.rtlight);
2220 for (i = 0;i < 8;i++)
2221 Matrix4x4_Transform(matrix, bboxpoints[i], vertex3f + i*3);
2222 GL_ColorMask(1,1,1,1);
2223 GL_DepthMask(false);
2224 GL_DepthRange(0, 1);
2225 GL_PolygonOffset(0, 0);
2227 GL_DepthFunc(GL_GREATER);
2228 GL_CullFace(r_refdef.view.cullface_back);
2229 R_Mesh_PrepareVertices_Position_Arrays(8, vertex3f);
2230 R_Mesh_Draw(0, 8, 0, 12, NULL, NULL, 0, bboxelements, NULL, 0);
2233 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
2235 R_Shadow_RenderMode_Reset();
2236 GL_BlendFunc(GL_ONE, GL_ONE);
2237 GL_DepthRange(0, 1);
2238 GL_DepthTest(r_showshadowvolumes.integer < 2);
2239 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
2240 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2241 GL_CullFace(GL_NONE);
2242 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
2245 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
2247 R_Shadow_RenderMode_Reset();
2248 GL_BlendFunc(GL_ONE, GL_ONE);
2249 GL_DepthRange(0, 1);
2250 GL_DepthTest(r_showlighting.integer < 2);
2251 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2253 GL_DepthFunc(GL_EQUAL);
2254 R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2255 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2258 void R_Shadow_RenderMode_End(void)
2260 R_Shadow_RenderMode_Reset();
2261 R_Shadow_RenderMode_ActiveLight(NULL);
2263 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2264 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2267 int bboxedges[12][2] =
2286 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2288 int i, ix1, iy1, ix2, iy2;
2289 float x1, y1, x2, y2;
2291 float vertex[20][3];
2300 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2301 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2302 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2303 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2305 if (!r_shadow_scissor.integer)
2308 // if view is inside the light box, just say yes it's visible
2309 if (BoxesOverlap(r_refdef.view.origin, r_refdef.view.origin, mins, maxs))
2312 x1 = y1 = x2 = y2 = 0;
2314 // transform all corners that are infront of the nearclip plane
2315 VectorNegate(r_refdef.view.frustum[4].normal, plane4f);
2316 plane4f[3] = r_refdef.view.frustum[4].dist;
2318 for (i = 0;i < 8;i++)
2320 Vector4Set(corner[i], (i & 1) ? maxs[0] : mins[0], (i & 2) ? maxs[1] : mins[1], (i & 4) ? maxs[2] : mins[2], 1);
2321 dist[i] = DotProduct4(corner[i], plane4f);
2322 sign[i] = dist[i] > 0;
2325 VectorCopy(corner[i], vertex[numvertices]);
2329 // if some points are behind the nearclip, add clipped edge points to make
2330 // sure that the scissor boundary is complete
2331 if (numvertices > 0 && numvertices < 8)
2333 // add clipped edge points
2334 for (i = 0;i < 12;i++)
2336 j = bboxedges[i][0];
2337 k = bboxedges[i][1];
2338 if (sign[j] != sign[k])
2340 f = dist[j] / (dist[j] - dist[k]);
2341 VectorLerp(corner[j], f, corner[k], vertex[numvertices]);
2347 // if we have no points to check, the light is behind the view plane
2351 // if we have some points to transform, check what screen area is covered
2352 x1 = y1 = x2 = y2 = 0;
2354 //Con_Printf("%i vertices to transform...\n", numvertices);
2355 for (i = 0;i < numvertices;i++)
2357 VectorCopy(vertex[i], v);
2358 R_Viewport_TransformToScreen(&r_refdef.view.viewport, v, v2);
2359 //Con_Printf("%.3f %.3f %.3f %.3f transformed to %.3f %.3f %.3f %.3f\n", v[0], v[1], v[2], v[3], v2[0], v2[1], v2[2], v2[3]);
2362 if (x1 > v2[0]) x1 = v2[0];
2363 if (x2 < v2[0]) x2 = v2[0];
2364 if (y1 > v2[1]) y1 = v2[1];
2365 if (y2 < v2[1]) y2 = v2[1];
2374 // now convert the scissor rectangle to integer screen coordinates
2375 ix1 = (int)(x1 - 1.0f);
2376 iy1 = vid.height - (int)(y2 - 1.0f);
2377 ix2 = (int)(x2 + 1.0f);
2378 iy2 = vid.height - (int)(y1 + 1.0f);
2379 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
2381 // clamp it to the screen
2382 if (ix1 < r_refdef.view.viewport.x) ix1 = r_refdef.view.viewport.x;
2383 if (iy1 < r_refdef.view.viewport.y) iy1 = r_refdef.view.viewport.y;
2384 if (ix2 > r_refdef.view.viewport.x + r_refdef.view.viewport.width) ix2 = r_refdef.view.viewport.x + r_refdef.view.viewport.width;
2385 if (iy2 > r_refdef.view.viewport.y + r_refdef.view.viewport.height) iy2 = r_refdef.view.viewport.y + r_refdef.view.viewport.height;
2387 // if it is inside out, it's not visible
2388 if (ix2 <= ix1 || iy2 <= iy1)
2391 // the light area is visible, set up the scissor rectangle
2392 r_shadow_lightscissor[0] = ix1;
2393 r_shadow_lightscissor[1] = iy1;
2394 r_shadow_lightscissor[2] = ix2 - ix1;
2395 r_shadow_lightscissor[3] = iy2 - iy1;
2397 // D3D Y coordinate is top to bottom, OpenGL is bottom to top, fix the D3D one
2398 switch(vid.renderpath)
2400 case RENDERPATH_D3D9:
2401 case RENDERPATH_D3D10:
2402 case RENDERPATH_D3D11:
2403 r_shadow_lightscissor[1] = vid.height - r_shadow_lightscissor[1] - r_shadow_lightscissor[3];
2405 case RENDERPATH_GL11:
2406 case RENDERPATH_GL13:
2407 case RENDERPATH_GL20:
2408 case RENDERPATH_CGGL:
2412 r_refdef.stats.lights_scissored++;
2416 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, const float *diffusecolor, const float *ambientcolor)
2419 const float *vertex3f;
2420 const float *normal3f;
2422 float dist, dot, distintensity, shadeintensity, v[3], n[3];
2423 switch (r_shadow_rendermode)
2425 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2426 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2427 if (VectorLength2(diffusecolor) > 0)
2429 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, normal3f = rsurface.batchnormal3f + 3*firstvertex, color4f = rsurface.array_passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, normal3f += 3, color4f += 4)
2431 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2432 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2433 if ((dot = DotProduct(n, v)) < 0)
2435 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2436 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
2439 VectorCopy(ambientcolor, color4f);
2440 if (r_refdef.fogenabled)
2443 f = RSurf_FogVertex(vertex3f);
2444 VectorScale(color4f, f, color4f);
2451 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.array_passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
2453 VectorCopy(ambientcolor, color4f);
2454 if (r_refdef.fogenabled)
2457 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2458 f = RSurf_FogVertex(vertex3f);
2459 VectorScale(color4f + 4*i, f, color4f);
2465 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2466 if (VectorLength2(diffusecolor) > 0)
2468 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, normal3f = rsurface.batchnormal3f + 3*firstvertex, color4f = rsurface.array_passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, normal3f += 3, color4f += 4)
2470 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2471 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2473 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2474 if ((dot = DotProduct(n, v)) < 0)
2476 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2477 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2478 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2479 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2483 color4f[0] = ambientcolor[0] * distintensity;
2484 color4f[1] = ambientcolor[1] * distintensity;
2485 color4f[2] = ambientcolor[2] * distintensity;
2487 if (r_refdef.fogenabled)
2490 f = RSurf_FogVertex(vertex3f);
2491 VectorScale(color4f, f, color4f);
2495 VectorClear(color4f);
2501 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.array_passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
2503 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2504 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2506 color4f[0] = ambientcolor[0] * distintensity;
2507 color4f[1] = ambientcolor[1] * distintensity;
2508 color4f[2] = ambientcolor[2] * distintensity;
2509 if (r_refdef.fogenabled)
2512 f = RSurf_FogVertex(vertex3f);
2513 VectorScale(color4f, f, color4f);
2517 VectorClear(color4f);
2522 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2523 if (VectorLength2(diffusecolor) > 0)
2525 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, normal3f = rsurface.batchnormal3f + 3*firstvertex, color4f = rsurface.array_passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, normal3f += 3, color4f += 4)
2527 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2528 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2530 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2531 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2532 if ((dot = DotProduct(n, v)) < 0)
2534 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2535 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2536 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2537 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2541 color4f[0] = ambientcolor[0] * distintensity;
2542 color4f[1] = ambientcolor[1] * distintensity;
2543 color4f[2] = ambientcolor[2] * distintensity;
2545 if (r_refdef.fogenabled)
2548 f = RSurf_FogVertex(vertex3f);
2549 VectorScale(color4f, f, color4f);
2553 VectorClear(color4f);
2559 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.array_passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
2561 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2562 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2564 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2565 color4f[0] = ambientcolor[0] * distintensity;
2566 color4f[1] = ambientcolor[1] * distintensity;
2567 color4f[2] = ambientcolor[2] * distintensity;
2568 if (r_refdef.fogenabled)
2571 f = RSurf_FogVertex(vertex3f);
2572 VectorScale(color4f, f, color4f);
2576 VectorClear(color4f);
2586 static void R_Shadow_RenderLighting_VisibleLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
2588 // used to display how many times a surface is lit for level design purposes
2589 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
2590 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
2594 static void R_Shadow_RenderLighting_Light_GLSL(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale, float specularscale)
2596 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2597 R_SetupShader_Surface(lightcolor, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT, texturenumsurfaces, texturesurfacelist, NULL);
2598 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2599 GL_DepthFunc(GL_EQUAL);
2601 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2602 GL_DepthFunc(GL_LEQUAL);
2605 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
2612 int newnumtriangles;
2616 int maxtriangles = 4096;
2617 static int newelements[4096*3];
2618 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, diffusecolor2, ambientcolor2);
2619 for (renders = 0;renders < 4;renders++)
2624 newnumtriangles = 0;
2626 // due to low fillrate on the cards this vertex lighting path is
2627 // designed for, we manually cull all triangles that do not
2628 // contain a lit vertex
2629 // this builds batches of triangles from multiple surfaces and
2630 // renders them at once
2631 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
2633 if (VectorLength2(rsurface.array_passcolor4f + e[0] * 4) + VectorLength2(rsurface.array_passcolor4f + e[1] * 4) + VectorLength2(rsurface.array_passcolor4f + e[2] * 4) >= 0.01)
2635 if (newnumtriangles)
2637 newfirstvertex = min(newfirstvertex, e[0]);
2638 newlastvertex = max(newlastvertex, e[0]);
2642 newfirstvertex = e[0];
2643 newlastvertex = e[0];
2645 newfirstvertex = min(newfirstvertex, e[1]);
2646 newlastvertex = max(newlastvertex, e[1]);
2647 newfirstvertex = min(newfirstvertex, e[2]);
2648 newlastvertex = max(newlastvertex, e[2]);
2654 if (newnumtriangles >= maxtriangles)
2656 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
2657 newnumtriangles = 0;
2663 if (newnumtriangles >= 1)
2665 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
2668 // if we couldn't find any lit triangles, exit early
2671 // now reduce the intensity for the next overbright pass
2672 // we have to clamp to 0 here incase the drivers have improper
2673 // handling of negative colors
2674 // (some old drivers even have improper handling of >1 color)
2676 for (i = 0, c = rsurface.array_passcolor4f + 4 * firstvertex;i < numvertices;i++, c += 4)
2678 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
2680 c[0] = max(0, c[0] - 1);
2681 c[1] = max(0, c[1] - 1);
2682 c[2] = max(0, c[2] - 1);
2694 static void R_Shadow_RenderLighting_Light_Vertex(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale)
2696 // OpenGL 1.1 path (anything)
2697 float ambientcolorbase[3], diffusecolorbase[3];
2698 float ambientcolorpants[3], diffusecolorpants[3];
2699 float ambientcolorshirt[3], diffusecolorshirt[3];
2700 const float *surfacecolor = rsurface.texture->dlightcolor;
2701 const float *surfacepants = rsurface.colormap_pantscolor;
2702 const float *surfaceshirt = rsurface.colormap_shirtcolor;
2703 rtexture_t *basetexture = rsurface.texture->basetexture;
2704 rtexture_t *pantstexture = rsurface.texture->pantstexture;
2705 rtexture_t *shirttexture = rsurface.texture->shirttexture;
2706 qboolean dopants = pantstexture && VectorLength2(surfacepants) >= (1.0f / 1048576.0f);
2707 qboolean doshirt = shirttexture && VectorLength2(surfaceshirt) >= (1.0f / 1048576.0f);
2708 ambientscale *= 2 * r_refdef.view.colorscale;
2709 diffusescale *= 2 * r_refdef.view.colorscale;
2710 ambientcolorbase[0] = lightcolor[0] * ambientscale * surfacecolor[0];ambientcolorbase[1] = lightcolor[1] * ambientscale * surfacecolor[1];ambientcolorbase[2] = lightcolor[2] * ambientscale * surfacecolor[2];
2711 diffusecolorbase[0] = lightcolor[0] * diffusescale * surfacecolor[0];diffusecolorbase[1] = lightcolor[1] * diffusescale * surfacecolor[1];diffusecolorbase[2] = lightcolor[2] * diffusescale * surfacecolor[2];
2712 ambientcolorpants[0] = ambientcolorbase[0] * surfacepants[0];ambientcolorpants[1] = ambientcolorbase[1] * surfacepants[1];ambientcolorpants[2] = ambientcolorbase[2] * surfacepants[2];
2713 diffusecolorpants[0] = diffusecolorbase[0] * surfacepants[0];diffusecolorpants[1] = diffusecolorbase[1] * surfacepants[1];diffusecolorpants[2] = diffusecolorbase[2] * surfacepants[2];
2714 ambientcolorshirt[0] = ambientcolorbase[0] * surfaceshirt[0];ambientcolorshirt[1] = ambientcolorbase[1] * surfaceshirt[1];ambientcolorshirt[2] = ambientcolorbase[2] * surfaceshirt[2];
2715 diffusecolorshirt[0] = diffusecolorbase[0] * surfaceshirt[0];diffusecolorshirt[1] = diffusecolorbase[1] * surfaceshirt[1];diffusecolorshirt[2] = diffusecolorbase[2] * surfaceshirt[2];
2716 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | (diffusescale > 0 ? BATCHNEED_ARRAY_NORMAL : 0) | BATCHNEED_ARRAY_TEXCOORD, texturenumsurfaces, texturesurfacelist);
2717 R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
2718 R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.array_passcolor4f, 0, 0);
2719 R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
2720 R_Mesh_TexBind(0, basetexture);
2721 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
2722 R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
2723 switch(r_shadow_rendermode)
2725 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2726 R_Mesh_TexBind(1, r_shadow_attenuation3dtexture);
2727 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
2728 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
2729 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
2731 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2732 R_Mesh_TexBind(2, r_shadow_attenuation2dtexture);
2733 R_Mesh_TexMatrix(2, &rsurface.entitytoattenuationz);
2734 R_Mesh_TexCombine(2, GL_MODULATE, GL_MODULATE, 1, 1);
2735 R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
2737 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2738 R_Mesh_TexBind(1, r_shadow_attenuation2dtexture);
2739 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
2740 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
2741 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
2743 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2748 //R_Mesh_TexBind(0, basetexture);
2749 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorbase, ambientcolorbase);
2752 R_Mesh_TexBind(0, pantstexture);
2753 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorpants, ambientcolorpants);
2757 R_Mesh_TexBind(0, shirttexture);
2758 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorshirt, ambientcolorshirt);
2762 extern cvar_t gl_lightmaps;
2763 void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
2765 float ambientscale, diffusescale, specularscale;
2767 float lightcolor[3];
2768 VectorCopy(rsurface.rtlight->currentcolor, lightcolor);
2769 ambientscale = rsurface.rtlight->ambientscale;
2770 diffusescale = rsurface.rtlight->diffusescale;
2771 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
2772 if (!r_shadow_usenormalmap.integer)
2774 ambientscale += 1.0f * diffusescale;
2778 if ((ambientscale + diffusescale) * VectorLength2(lightcolor) + specularscale * VectorLength2(lightcolor) < (1.0f / 1048576.0f))
2780 negated = (lightcolor[0] + lightcolor[1] + lightcolor[2] < 0) && vid.support.ext_blend_subtract;
2783 VectorNegate(lightcolor, lightcolor);
2784 switch(vid.renderpath)
2786 case RENDERPATH_GL11:
2787 case RENDERPATH_GL13:
2788 case RENDERPATH_GL20:
2789 case RENDERPATH_CGGL:
2790 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
2792 case RENDERPATH_D3D9:
2794 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_SUBTRACT);
2797 case RENDERPATH_D3D10:
2798 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2800 case RENDERPATH_D3D11:
2801 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2805 RSurf_SetupDepthAndCulling();
2806 switch (r_shadow_rendermode)
2808 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2809 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2810 R_Shadow_RenderLighting_VisibleLighting(texturenumsurfaces, texturesurfacelist);
2812 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2813 R_Shadow_RenderLighting_Light_GLSL(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale, specularscale);
2815 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2816 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2817 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2818 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2819 R_Shadow_RenderLighting_Light_Vertex(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale);
2822 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2827 switch(vid.renderpath)
2829 case RENDERPATH_GL11:
2830 case RENDERPATH_GL13:
2831 case RENDERPATH_GL20:
2832 case RENDERPATH_CGGL:
2833 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
2835 case RENDERPATH_D3D9:
2837 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_ADD);
2840 case RENDERPATH_D3D10:
2841 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2843 case RENDERPATH_D3D11:
2844 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2850 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)
2852 matrix4x4_t tempmatrix = *matrix;
2853 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
2855 // if this light has been compiled before, free the associated data
2856 R_RTLight_Uncompile(rtlight);
2858 // clear it completely to avoid any lingering data
2859 memset(rtlight, 0, sizeof(*rtlight));
2861 // copy the properties
2862 rtlight->matrix_lighttoworld = tempmatrix;
2863 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
2864 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
2865 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
2866 VectorCopy(color, rtlight->color);
2867 rtlight->cubemapname[0] = 0;
2868 if (cubemapname && cubemapname[0])
2869 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
2870 rtlight->shadow = shadow;
2871 rtlight->corona = corona;
2872 rtlight->style = style;
2873 rtlight->isstatic = isstatic;
2874 rtlight->coronasizescale = coronasizescale;
2875 rtlight->ambientscale = ambientscale;
2876 rtlight->diffusescale = diffusescale;
2877 rtlight->specularscale = specularscale;
2878 rtlight->flags = flags;
2880 // compute derived data
2881 //rtlight->cullradius = rtlight->radius;
2882 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2883 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2884 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2885 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2886 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2887 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2888 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2891 // compiles rtlight geometry
2892 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2893 void R_RTLight_Compile(rtlight_t *rtlight)
2896 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
2897 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
2898 entity_render_t *ent = r_refdef.scene.worldentity;
2899 dp_model_t *model = r_refdef.scene.worldmodel;
2900 unsigned char *data;
2903 // compile the light
2904 rtlight->compiled = true;
2905 rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
2906 rtlight->static_numleafs = 0;
2907 rtlight->static_numleafpvsbytes = 0;
2908 rtlight->static_leaflist = NULL;
2909 rtlight->static_leafpvs = NULL;
2910 rtlight->static_numsurfaces = 0;
2911 rtlight->static_surfacelist = NULL;
2912 rtlight->static_shadowmap_receivers = 0x3F;
2913 rtlight->static_shadowmap_casters = 0x3F;
2914 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2915 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2916 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2917 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2918 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2919 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2921 if (model && model->GetLightInfo)
2923 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
2924 r_shadow_compilingrtlight = rtlight;
2925 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);
2926 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2927 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
2928 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
2929 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
2930 rtlight->static_numsurfaces = numsurfaces;
2931 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
2932 rtlight->static_numleafs = numleafs;
2933 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
2934 rtlight->static_numleafpvsbytes = numleafpvsbytes;
2935 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
2936 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
2937 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
2938 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
2939 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
2940 if (rtlight->static_numsurfaces)
2941 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
2942 if (rtlight->static_numleafs)
2943 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
2944 if (rtlight->static_numleafpvsbytes)
2945 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
2946 if (rtlight->static_numshadowtrispvsbytes)
2947 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
2948 if (rtlight->static_numlighttrispvsbytes)
2949 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
2950 switch (rtlight->shadowmode)
2952 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2953 if (model->CompileShadowMap && rtlight->shadow)
2954 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2957 if (model->CompileShadowVolume && rtlight->shadow)
2958 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2961 // now we're done compiling the rtlight
2962 r_shadow_compilingrtlight = NULL;
2966 // use smallest available cullradius - box radius or light radius
2967 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2968 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2970 shadowzpasstris = 0;
2971 if (rtlight->static_meshchain_shadow_zpass)
2972 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
2973 shadowzpasstris += mesh->numtriangles;
2975 shadowzfailtris = 0;
2976 if (rtlight->static_meshchain_shadow_zfail)
2977 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
2978 shadowzfailtris += mesh->numtriangles;
2981 if (rtlight->static_numlighttrispvsbytes)
2982 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
2983 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
2987 if (rtlight->static_numlighttrispvsbytes)
2988 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
2989 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
2992 if (developer_extra.integer)
2993 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);
2996 void R_RTLight_Uncompile(rtlight_t *rtlight)
2998 if (rtlight->compiled)
3000 if (rtlight->static_meshchain_shadow_zpass)
3001 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
3002 rtlight->static_meshchain_shadow_zpass = NULL;
3003 if (rtlight->static_meshchain_shadow_zfail)
3004 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
3005 rtlight->static_meshchain_shadow_zfail = NULL;
3006 if (rtlight->static_meshchain_shadow_shadowmap)
3007 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
3008 rtlight->static_meshchain_shadow_shadowmap = NULL;
3009 // these allocations are grouped
3010 if (rtlight->static_surfacelist)
3011 Mem_Free(rtlight->static_surfacelist);
3012 rtlight->static_numleafs = 0;
3013 rtlight->static_numleafpvsbytes = 0;
3014 rtlight->static_leaflist = NULL;
3015 rtlight->static_leafpvs = NULL;
3016 rtlight->static_numsurfaces = 0;
3017 rtlight->static_surfacelist = NULL;
3018 rtlight->static_numshadowtrispvsbytes = 0;
3019 rtlight->static_shadowtrispvs = NULL;
3020 rtlight->static_numlighttrispvsbytes = 0;
3021 rtlight->static_lighttrispvs = NULL;
3022 rtlight->compiled = false;
3026 void R_Shadow_UncompileWorldLights(void)
3030 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3031 for (lightindex = 0;lightindex < range;lightindex++)
3033 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3036 R_RTLight_Uncompile(&light->rtlight);
3040 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3044 // reset the count of frustum planes
3045 // see rtlight->cached_frustumplanes definition for how much this array
3047 rtlight->cached_numfrustumplanes = 0;
3049 // haven't implemented a culling path for ortho rendering
3050 if (!r_refdef.view.useperspective)
3052 // check if the light is on screen and copy the 4 planes if it is
3053 for (i = 0;i < 4;i++)
3054 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3057 for (i = 0;i < 4;i++)
3058 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3063 // generate a deformed frustum that includes the light origin, this is
3064 // used to cull shadow casting surfaces that can not possibly cast a
3065 // shadow onto the visible light-receiving surfaces, which can be a
3068 // if the light origin is onscreen the result will be 4 planes exactly
3069 // if the light origin is offscreen on only one axis the result will
3070 // be exactly 5 planes (split-side case)
3071 // if the light origin is offscreen on two axes the result will be
3072 // exactly 4 planes (stretched corner case)
3073 for (i = 0;i < 4;i++)
3075 // quickly reject standard frustum planes that put the light
3076 // origin outside the frustum
3077 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3080 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3082 // if all the standard frustum planes were accepted, the light is onscreen
3083 // otherwise we need to generate some more planes below...
3084 if (rtlight->cached_numfrustumplanes < 4)
3086 // at least one of the stock frustum planes failed, so we need to
3087 // create one or two custom planes to enclose the light origin
3088 for (i = 0;i < 4;i++)
3090 // create a plane using the view origin and light origin, and a
3091 // single point from the frustum corner set
3092 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3093 VectorNormalize(plane.normal);
3094 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3095 // see if this plane is backwards and flip it if so
3096 for (j = 0;j < 4;j++)
3097 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3101 VectorNegate(plane.normal, plane.normal);
3103 // flipped plane, test again to see if it is now valid
3104 for (j = 0;j < 4;j++)
3105 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3107 // if the plane is still not valid, then it is dividing the
3108 // frustum and has to be rejected
3112 // we have created a valid plane, compute extra info
3113 PlaneClassify(&plane);
3115 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3117 // if we've found 5 frustum planes then we have constructed a
3118 // proper split-side case and do not need to keep searching for
3119 // planes to enclose the light origin
3120 if (rtlight->cached_numfrustumplanes == 5)
3128 for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
3130 plane = rtlight->cached_frustumplanes[i];
3131 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));
3136 // now add the light-space box planes if the light box is rotated, as any
3137 // caster outside the oriented light box is irrelevant (even if it passed
3138 // the worldspace light box, which is axial)
3139 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3141 for (i = 0;i < 6;i++)
3145 v[i >> 1] = (i & 1) ? -1 : 1;
3146 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3147 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3148 plane.dist = VectorNormalizeLength(plane.normal);
3149 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3150 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3156 // add the world-space reduced box planes
3157 for (i = 0;i < 6;i++)
3159 VectorClear(plane.normal);
3160 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3161 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
3162 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3171 // reduce all plane distances to tightly fit the rtlight cull box, which
3173 VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3174 VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3175 VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3176 VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3177 VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3178 VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3179 VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3180 VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3181 oldnum = rtlight->cached_numfrustumplanes;
3182 rtlight->cached_numfrustumplanes = 0;
3183 for (j = 0;j < oldnum;j++)
3185 // find the nearest point on the box to this plane
3186 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
3187 for (i = 1;i < 8;i++)
3189 dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
3190 if (bestdist > dist)
3193 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);
3194 // if the nearest point is near or behind the plane, we want this
3195 // plane, otherwise the plane is useless as it won't cull anything
3196 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
3198 PlaneClassify(&rtlight->cached_frustumplanes[j]);
3199 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
3206 void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
3210 RSurf_ActiveWorldEntity();
3212 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3215 GL_CullFace(GL_NONE);
3216 mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3217 for (;mesh;mesh = mesh->next)
3219 if (!mesh->sidetotals[r_shadow_shadowmapside])
3221 r_refdef.stats.lights_shadowtriangles += mesh->sidetotals[r_shadow_shadowmapside];
3222 R_Mesh_PrepareVertices_Position(mesh->numverts, mesh->vertexposition, mesh->vertexpositionbuffer);
3223 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);
3227 else if (r_refdef.scene.worldentity->model)
3228 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);
3230 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3233 void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3235 qboolean zpass = false;
3238 int surfacelistindex;
3239 msurface_t *surface;
3241 RSurf_ActiveWorldEntity();
3243 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3246 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
3248 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
3249 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
3251 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
3252 for (;mesh;mesh = mesh->next)
3254 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
3255 R_Mesh_PrepareVertices_Position(mesh->numverts, mesh->vertexposition, mesh->vertexpositionbuffer);
3256 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
3258 // increment stencil if frontface is infront of depthbuffer
3259 GL_CullFace(r_refdef.view.cullface_back);
3260 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
3261 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);
3262 // decrement stencil if backface is infront of depthbuffer
3263 GL_CullFace(r_refdef.view.cullface_front);
3264 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
3266 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
3268 // decrement stencil if backface is behind depthbuffer
3269 GL_CullFace(r_refdef.view.cullface_front);
3270 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
3271 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);
3272 // increment stencil if frontface is behind depthbuffer
3273 GL_CullFace(r_refdef.view.cullface_back);
3274 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
3276 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);
3280 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh)
3282 // use the shadow trispvs calculated earlier by GetLightInfo to cull world triangles on this dynamic light
3283 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
3284 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
3286 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
3287 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
3288 if (CHECKPVSBIT(trispvs, t))
3289 shadowmarklist[numshadowmark++] = t;
3291 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);
3293 else if (numsurfaces)
3294 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);
3296 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3299 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3301 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3302 vec_t relativeshadowradius;
3303 RSurf_ActiveModelEntity(ent, false, false, false);
3304 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3305 // we need to re-init the shader for each entity because the matrix changed
3306 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3307 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3308 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3309 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3310 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3311 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3312 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3313 switch (r_shadow_rendermode)
3315 case R_SHADOW_RENDERMODE_SHADOWMAP2D:
3316 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
3319 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3322 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3325 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3327 // set up properties for rendering light onto this entity
3328 RSurf_ActiveModelEntity(ent, true, true, false);
3329 GL_AlphaTest(false);
3330 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3331 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3332 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3333 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3336 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
3338 if (!r_refdef.scene.worldmodel->DrawLight)
3341 // set up properties for rendering light onto this entity
3342 RSurf_ActiveWorldEntity();
3343 GL_AlphaTest(false);
3344 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3345 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3346 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3347 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3349 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
3351 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3354 void R_Shadow_DrawEntityLight(entity_render_t *ent)
3356 dp_model_t *model = ent->model;
3357 if (!model->DrawLight)
3360 R_Shadow_SetupEntityLight(ent);
3362 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3364 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3367 void R_Shadow_PrepareLight(rtlight_t *rtlight)
3371 int numleafs, numsurfaces;
3372 int *leaflist, *surfacelist;
3373 unsigned char *leafpvs;
3374 unsigned char *shadowtrispvs;
3375 unsigned char *lighttrispvs;
3376 //unsigned char *surfacesides;
3377 int numlightentities;
3378 int numlightentities_noselfshadow;
3379 int numshadowentities;
3380 int numshadowentities_noselfshadow;
3381 static entity_render_t *lightentities[MAX_EDICTS];
3382 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3383 static entity_render_t *shadowentities[MAX_EDICTS];
3384 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3387 rtlight->draw = false;
3389 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3390 // skip lights that are basically invisible (color 0 0 0)
3391 nolight = VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f);
3393 // loading is done before visibility checks because loading should happen
3394 // all at once at the start of a level, not when it stalls gameplay.
3395 // (especially important to benchmarks)
3397 if (rtlight->isstatic && !nolight && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
3399 if (rtlight->compiled)
3400 R_RTLight_Uncompile(rtlight);
3401 R_RTLight_Compile(rtlight);
3405 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
3407 // look up the light style value at this time
3408 f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3409 VectorScale(rtlight->color, f, rtlight->currentcolor);
3411 if (rtlight->selected)
3413 f = 2 + sin(realtime * M_PI * 4.0);
3414 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3418 // if lightstyle is currently off, don't draw the light
3419 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3422 // skip processing on corona-only lights
3426 // if the light box is offscreen, skip it
3427 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3430 VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
3431 VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
3433 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3435 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3437 // compiled light, world available and can receive realtime lighting
3438 // retrieve leaf information
3439 numleafs = rtlight->static_numleafs;
3440 leaflist = rtlight->static_leaflist;
3441 leafpvs = rtlight->static_leafpvs;
3442 numsurfaces = rtlight->static_numsurfaces;
3443 surfacelist = rtlight->static_surfacelist;
3444 //surfacesides = NULL;
3445 shadowtrispvs = rtlight->static_shadowtrispvs;
3446 lighttrispvs = rtlight->static_lighttrispvs;
3448 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3450 // dynamic light, world available and can receive realtime lighting
3451 // calculate lit surfaces and leafs
3452 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);
3453 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3454 leaflist = r_shadow_buffer_leaflist;
3455 leafpvs = r_shadow_buffer_leafpvs;
3456 surfacelist = r_shadow_buffer_surfacelist;
3457 //surfacesides = r_shadow_buffer_surfacesides;
3458 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3459 lighttrispvs = r_shadow_buffer_lighttrispvs;
3460 // if the reduced leaf bounds are offscreen, skip it
3461 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3472 //surfacesides = NULL;
3473 shadowtrispvs = NULL;
3474 lighttrispvs = NULL;
3476 // check if light is illuminating any visible leafs
3479 for (i = 0;i < numleafs;i++)
3480 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3486 // make a list of lit entities and shadow casting entities
3487 numlightentities = 0;
3488 numlightentities_noselfshadow = 0;
3489 numshadowentities = 0;
3490 numshadowentities_noselfshadow = 0;
3492 // add dynamic entities that are lit by the light
3493 for (i = 0;i < r_refdef.scene.numentities;i++)
3496 entity_render_t *ent = r_refdef.scene.entities[i];
3498 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3500 // skip the object entirely if it is not within the valid
3501 // shadow-casting region (which includes the lit region)
3502 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
3504 if (!(model = ent->model))
3506 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
3508 // this entity wants to receive light, is visible, and is
3509 // inside the light box
3510 // TODO: check if the surfaces in the model can receive light
3511 // so now check if it's in a leaf seen by the light
3512 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))
3514 if (ent->flags & RENDER_NOSELFSHADOW)
3515 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
3517 lightentities[numlightentities++] = ent;
3518 // since it is lit, it probably also casts a shadow...
3519 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3520 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3521 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3523 // note: exterior models without the RENDER_NOSELFSHADOW
3524 // flag still create a RENDER_NOSELFSHADOW shadow but
3525 // are lit normally, this means that they are
3526 // self-shadowing but do not shadow other
3527 // RENDER_NOSELFSHADOW entities such as the gun
3528 // (very weird, but keeps the player shadow off the gun)
3529 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3530 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3532 shadowentities[numshadowentities++] = ent;
3535 else if (ent->flags & RENDER_SHADOW)
3537 // this entity is not receiving light, but may still need to
3539 // TODO: check if the surfaces in the model can cast shadow
3540 // now check if it is in a leaf seen by the light
3541 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))
3543 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3544 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3545 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3547 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3548 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3550 shadowentities[numshadowentities++] = ent;
3555 // return if there's nothing at all to light
3556 if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
3559 // count this light in the r_speeds
3560 r_refdef.stats.lights++;
3562 // flag it as worth drawing later
3563 rtlight->draw = true;
3565 // cache all the animated entities that cast a shadow but are not visible
3566 for (i = 0;i < numshadowentities;i++)
3567 if (!shadowentities[i]->animcache_vertex3f)
3568 R_AnimCache_GetEntity(shadowentities[i], false, false);
3569 for (i = 0;i < numshadowentities_noselfshadow;i++)
3570 if (!shadowentities_noselfshadow[i]->animcache_vertex3f)
3571 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
3573 // allocate some temporary memory for rendering this light later in the frame
3574 // reusable buffers need to be copied, static data can be used as-is
3575 rtlight->cached_numlightentities = numlightentities;
3576 rtlight->cached_numlightentities_noselfshadow = numlightentities_noselfshadow;
3577 rtlight->cached_numshadowentities = numshadowentities;
3578 rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
3579 rtlight->cached_numsurfaces = numsurfaces;
3580 rtlight->cached_lightentities = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
3581 rtlight->cached_lightentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
3582 rtlight->cached_shadowentities = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
3583 rtlight->cached_shadowentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
3584 if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
3586 int numshadowtrispvsbytes = (((r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles) + 7) >> 3);
3587 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
3588 rtlight->cached_shadowtrispvs = (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
3589 rtlight->cached_lighttrispvs = (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
3590 rtlight->cached_surfacelist = (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
3594 // compiled light data
3595 rtlight->cached_shadowtrispvs = shadowtrispvs;
3596 rtlight->cached_lighttrispvs = lighttrispvs;
3597 rtlight->cached_surfacelist = surfacelist;
3601 void R_Shadow_DrawLight(rtlight_t *rtlight)
3605 unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
3606 int numlightentities;
3607 int numlightentities_noselfshadow;
3608 int numshadowentities;
3609 int numshadowentities_noselfshadow;
3610 entity_render_t **lightentities;
3611 entity_render_t **lightentities_noselfshadow;
3612 entity_render_t **shadowentities;
3613 entity_render_t **shadowentities_noselfshadow;
3615 static unsigned char entitysides[MAX_EDICTS];
3616 static unsigned char entitysides_noselfshadow[MAX_EDICTS];
3617 vec3_t nearestpoint;
3619 qboolean castshadows;
3622 // check if we cached this light this frame (meaning it is worth drawing)
3626 // if R_FrameData_Store ran out of space we skip anything dependent on it
3627 if (r_framedata_failed)
3630 numlightentities = rtlight->cached_numlightentities;
3631 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
3632 numshadowentities = rtlight->cached_numshadowentities;
3633 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
3634 numsurfaces = rtlight->cached_numsurfaces;
3635 lightentities = rtlight->cached_lightentities;
3636 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
3637 shadowentities = rtlight->cached_shadowentities;
3638 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
3639 shadowtrispvs = rtlight->cached_shadowtrispvs;
3640 lighttrispvs = rtlight->cached_lighttrispvs;
3641 surfacelist = rtlight->cached_surfacelist;
3643 // set up a scissor rectangle for this light
3644 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3647 // don't let sound skip if going slow
3648 if (r_refdef.scene.extraupdate)
3651 // make this the active rtlight for rendering purposes
3652 R_Shadow_RenderMode_ActiveLight(rtlight);
3654 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
3656 // optionally draw visible shape of the shadow volumes
3657 // for performance analysis by level designers
3658 R_Shadow_RenderMode_VisibleShadowVolumes();
3660 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
3661 for (i = 0;i < numshadowentities;i++)
3662 R_Shadow_DrawEntityShadow(shadowentities[i]);
3663 for (i = 0;i < numshadowentities_noselfshadow;i++)
3664 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3665 R_Shadow_RenderMode_VisibleLighting(false, false);
3668 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
3670 // optionally draw the illuminated areas
3671 // for performance analysis by level designers
3672 R_Shadow_RenderMode_VisibleLighting(false, false);
3674 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3675 for (i = 0;i < numlightentities;i++)
3676 R_Shadow_DrawEntityLight(lightentities[i]);
3677 for (i = 0;i < numlightentities_noselfshadow;i++)
3678 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3681 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
3683 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
3684 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
3685 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
3686 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
3688 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance/rtlight->radius));
3689 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
3690 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
3692 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
3698 int receivermask = 0;
3699 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
3700 Matrix4x4_Abs(&radiustolight);
3702 r_shadow_shadowmaplod = 0;
3703 for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
3704 if ((r_shadow_shadowmapmaxsize >> i) > lodlinear)
3705 r_shadow_shadowmaplod = i;
3707 size = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
3709 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
3711 surfacesides = NULL;
3714 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3716 castermask = rtlight->static_shadowmap_casters;
3717 receivermask = rtlight->static_shadowmap_receivers;
3721 surfacesides = r_shadow_buffer_surfacesides;
3722 for(i = 0;i < numsurfaces;i++)
3724 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
3725 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3726 castermask |= surfacesides[i];
3727 receivermask |= surfacesides[i];
3731 if (receivermask < 0x3F)
3733 for (i = 0;i < numlightentities;i++)
3734 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3735 if (receivermask < 0x3F)
3736 for(i = 0; i < numlightentities_noselfshadow;i++)
3737 receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3740 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
3744 for (i = 0;i < numshadowentities;i++)
3745 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3746 for (i = 0;i < numshadowentities_noselfshadow;i++)
3747 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3750 //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
3752 // render shadow casters into 6 sided depth texture
3753 for (side = 0;side < 6;side++) if (receivermask & (1 << side))
3755 R_Shadow_RenderMode_ShadowMap(side, receivermask, size);
3756 if (! (castermask & (1 << side))) continue;
3758 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
3759 for (i = 0;i < numshadowentities;i++) if (entitysides[i] & (1 << side))
3760 R_Shadow_DrawEntityShadow(shadowentities[i]);
3763 if (numlightentities_noselfshadow)
3765 // render lighting using the depth texture as shadowmap
3766 // draw lighting in the unmasked areas
3767 R_Shadow_RenderMode_Lighting(false, false, true);
3768 for (i = 0;i < numlightentities_noselfshadow;i++)
3769 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3772 // render shadow casters into 6 sided depth texture
3773 if (numshadowentities_noselfshadow)
3775 for (side = 0;side < 6;side++) if ((receivermask & castermask) & (1 << side))
3777 R_Shadow_RenderMode_ShadowMap(side, 0, size);
3778 for (i = 0;i < numshadowentities_noselfshadow;i++) if (entitysides_noselfshadow[i] & (1 << side))
3779 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3783 // render lighting using the depth texture as shadowmap
3784 // draw lighting in the unmasked areas
3785 R_Shadow_RenderMode_Lighting(false, false, true);
3786 // draw lighting in the unmasked areas
3788 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3789 for (i = 0;i < numlightentities;i++)
3790 R_Shadow_DrawEntityLight(lightentities[i]);
3792 else if (castshadows && vid.stencil)
3794 // draw stencil shadow volumes to mask off pixels that are in shadow
3795 // so that they won't receive lighting
3796 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
3797 R_Shadow_ClearStencil();
3800 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
3801 for (i = 0;i < numshadowentities;i++)
3802 R_Shadow_DrawEntityShadow(shadowentities[i]);
3804 // draw lighting in the unmasked areas
3805 R_Shadow_RenderMode_Lighting(true, false, false);
3806 for (i = 0;i < numlightentities_noselfshadow;i++)
3807 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3809 for (i = 0;i < numshadowentities_noselfshadow;i++)
3810 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3812 // draw lighting in the unmasked areas
3813 R_Shadow_RenderMode_Lighting(true, false, false);
3815 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3816 for (i = 0;i < numlightentities;i++)
3817 R_Shadow_DrawEntityLight(lightentities[i]);
3821 // draw lighting in the unmasked areas
3822 R_Shadow_RenderMode_Lighting(false, false, false);
3824 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3825 for (i = 0;i < numlightentities;i++)
3826 R_Shadow_DrawEntityLight(lightentities[i]);
3827 for (i = 0;i < numlightentities_noselfshadow;i++)
3828 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3831 if (r_shadow_usingdeferredprepass)
3833 // when rendering deferred lighting, we simply rasterize the box
3834 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
3835 R_Shadow_RenderMode_DrawDeferredLight(false, true);
3836 else if (castshadows && vid.stencil)
3837 R_Shadow_RenderMode_DrawDeferredLight(true, false);
3839 R_Shadow_RenderMode_DrawDeferredLight(false, false);
3843 static void R_Shadow_FreeDeferred(void)
3845 R_Mesh_DestroyFramebufferObject(r_shadow_prepassgeometryfbo);
3846 r_shadow_prepassgeometryfbo = 0;
3848 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingfbo);
3849 r_shadow_prepasslightingfbo = 0;
3851 if (r_shadow_prepassgeometrydepthtexture)
3852 R_FreeTexture(r_shadow_prepassgeometrydepthtexture);
3853 r_shadow_prepassgeometrydepthtexture = NULL;
3855 if (r_shadow_prepassgeometrydepthcolortexture)
3856 R_FreeTexture(r_shadow_prepassgeometrydepthcolortexture);
3857 r_shadow_prepassgeometrydepthcolortexture = NULL;
3859 if (r_shadow_prepassgeometrynormalmaptexture)
3860 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
3861 r_shadow_prepassgeometrynormalmaptexture = NULL;
3863 if (r_shadow_prepasslightingdiffusetexture)
3864 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
3865 r_shadow_prepasslightingdiffusetexture = NULL;
3867 if (r_shadow_prepasslightingspeculartexture)
3868 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
3869 r_shadow_prepasslightingspeculartexture = NULL;
3872 void R_Shadow_DrawPrepass(void)
3880 entity_render_t *ent;
3881 float clearcolor[4];
3883 GL_AlphaTest(false);
3884 R_Mesh_ResetTextureState();
3886 GL_ColorMask(1,1,1,1);
3887 GL_BlendFunc(GL_ONE, GL_ZERO);
3890 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, r_shadow_prepassgeometrydepthcolortexture, NULL, NULL);
3891 Vector4Set(clearcolor, 0.5f,0.5f,0.5f,1.0f);
3892 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
3893 if (r_timereport_active)
3894 R_TimeReport("prepasscleargeom");
3896 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
3897 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
3898 if (r_timereport_active)
3899 R_TimeReport("prepassworld");
3901 for (i = 0;i < r_refdef.scene.numentities;i++)
3903 if (!r_refdef.viewcache.entityvisible[i])
3905 ent = r_refdef.scene.entities[i];
3906 if (ent->model && ent->model->DrawPrepass != NULL)
3907 ent->model->DrawPrepass(ent);
3910 if (r_timereport_active)
3911 R_TimeReport("prepassmodels");
3913 GL_DepthMask(false);
3914 GL_ColorMask(1,1,1,1);
3917 R_Mesh_SetRenderTargets(r_shadow_prepasslightingfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
3918 Vector4Set(clearcolor, 0, 0, 0, 0);
3919 GL_Clear(GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
3920 if (r_timereport_active)
3921 R_TimeReport("prepassclearlit");
3923 R_Shadow_RenderMode_Begin();
3925 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3926 if (r_shadow_debuglight.integer >= 0)
3928 lightindex = r_shadow_debuglight.integer;
3929 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3930 if (light && (light->flags & flag))
3931 R_Shadow_DrawLight(&light->rtlight);
3935 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3936 for (lightindex = 0;lightindex < range;lightindex++)
3938 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3939 if (light && (light->flags & flag))
3940 R_Shadow_DrawLight(&light->rtlight);
3943 if (r_refdef.scene.rtdlight)
3944 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
3945 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
3947 R_Mesh_ResetRenderTargets();
3949 R_Shadow_RenderMode_End();
3951 if (r_timereport_active)
3952 R_TimeReport("prepasslights");
3955 void R_Shadow_DrawLightSprites(void);
3956 void R_Shadow_PrepareLights(void)
3966 if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4) ||
3967 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
3968 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20) ||
3969 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
3970 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
3971 r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
3972 R_Shadow_FreeShadowMaps();
3974 r_shadow_usingshadowmaportho = false;
3976 switch (vid.renderpath)
3978 case RENDERPATH_GL20:
3979 case RENDERPATH_CGGL:
3980 case RENDERPATH_D3D9:
3981 case RENDERPATH_D3D10:
3982 case RENDERPATH_D3D11:
3983 if (!r_shadow_deferred.integer || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_STENCIL || !vid.support.ext_framebuffer_object || vid.maxdrawbuffers < 2)
3985 r_shadow_usingdeferredprepass = false;
3986 if (r_shadow_prepass_width)
3987 R_Shadow_FreeDeferred();
3988 r_shadow_prepass_width = r_shadow_prepass_height = 0;
3992 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
3994 R_Shadow_FreeDeferred();
3996 r_shadow_usingdeferredprepass = true;
3997 r_shadow_prepass_width = vid.width;
3998 r_shadow_prepass_height = vid.height;
3999 r_shadow_prepassgeometrydepthtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "prepassgeometrydepthmap", vid.width, vid.height, 24, false);
4000 switch (vid.renderpath)
4002 case RENDERPATH_D3D9:
4003 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);
4008 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);
4009 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);
4010 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);
4012 // set up the geometry pass fbo (depth + normalmap)
4013 r_shadow_prepassgeometryfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4014 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, r_shadow_prepassgeometrydepthcolortexture, NULL, NULL);
4015 // render depth into one texture and normalmap into the other
4016 if (qglDrawBuffersARB)
4018 qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);CHECKGLERROR
4019 qglReadBuffer(GL_NONE);CHECKGLERROR
4020 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4021 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4023 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4024 Cvar_SetValueQuick(&r_shadow_deferred, 0);
4025 r_shadow_usingdeferredprepass = false;
4029 // set up the lighting pass fbo (diffuse + specular)
4030 r_shadow_prepasslightingfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4031 R_Mesh_SetRenderTargets(r_shadow_prepasslightingfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4032 // render diffuse into one texture and specular into another,
4033 // with depth and normalmap bound as textures,
4034 // with depth bound as attachment as well
4035 if (qglDrawBuffersARB)
4037 qglDrawBuffersARB(2, r_shadow_prepasslightingdrawbuffers);CHECKGLERROR
4038 qglReadBuffer(GL_NONE);CHECKGLERROR
4039 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4040 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4042 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4043 Cvar_SetValueQuick(&r_shadow_deferred, 0);
4044 r_shadow_usingdeferredprepass = false;
4049 case RENDERPATH_GL13:
4050 case RENDERPATH_GL11:
4051 r_shadow_usingdeferredprepass = false;
4055 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);
4057 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4058 if (r_shadow_debuglight.integer >= 0)
4060 lightindex = r_shadow_debuglight.integer;
4061 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4062 if (light && (light->flags & flag))
4063 R_Shadow_PrepareLight(&light->rtlight);
4067 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4068 for (lightindex = 0;lightindex < range;lightindex++)
4070 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4071 if (light && (light->flags & flag))
4072 R_Shadow_PrepareLight(&light->rtlight);
4075 if (r_refdef.scene.rtdlight)
4077 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4078 R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
4080 else if(gl_flashblend.integer)
4082 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4084 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
4085 f = (rtlight->style >= 0 ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4086 VectorScale(rtlight->color, f, rtlight->currentcolor);
4090 if (r_editlights.integer)
4091 R_Shadow_DrawLightSprites();
4094 void R_Shadow_DrawLights(void)
4102 R_Shadow_RenderMode_Begin();
4104 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4105 if (r_shadow_debuglight.integer >= 0)
4107 lightindex = r_shadow_debuglight.integer;
4108 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4109 if (light && (light->flags & flag))
4110 R_Shadow_DrawLight(&light->rtlight);
4114 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4115 for (lightindex = 0;lightindex < range;lightindex++)
4117 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4118 if (light && (light->flags & flag))
4119 R_Shadow_DrawLight(&light->rtlight);
4122 if (r_refdef.scene.rtdlight)
4123 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4124 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4126 R_Shadow_RenderMode_End();
4129 extern const float r_screenvertex3f[12];
4130 extern void R_SetupView(qboolean allowwaterclippingplane);
4131 extern void R_ResetViewRendering3D(void);
4132 extern void R_ResetViewRendering2D(void);
4133 extern cvar_t r_shadows;
4134 extern cvar_t r_shadows_darken;
4135 extern cvar_t r_shadows_drawafterrtlighting;
4136 extern cvar_t r_shadows_castfrombmodels;
4137 extern cvar_t r_shadows_throwdistance;
4138 extern cvar_t r_shadows_throwdirection;
4139 extern cvar_t r_shadows_focus;
4140 extern cvar_t r_shadows_shadowmapscale;
4142 void R_Shadow_PrepareModelShadows(void)
4145 float scale, size, radius, dot1, dot2;
4146 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
4147 entity_render_t *ent;
4149 if (!r_refdef.scene.numentities)
4152 switch (r_shadow_shadowmode)
4154 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4155 if (r_shadows.integer >= 2)
4158 case R_SHADOW_SHADOWMODE_STENCIL:
4159 for (i = 0;i < r_refdef.scene.numentities;i++)
4161 ent = r_refdef.scene.entities[i];
4162 if (!ent->animcache_vertex3f && ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4163 R_AnimCache_GetEntity(ent, false, false);
4170 size = 2*r_shadow_shadowmapmaxsize;
4171 scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
4172 radius = 0.5f * size / scale;
4174 Math_atov(r_shadows_throwdirection.string, shadowdir);
4175 VectorNormalize(shadowdir);
4176 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4177 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4178 if (fabs(dot1) <= fabs(dot2))
4179 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4181 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4182 VectorNormalize(shadowforward);
4183 CrossProduct(shadowdir, shadowforward, shadowright);
4184 Math_atov(r_shadows_focus.string, shadowfocus);
4185 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4186 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4187 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4188 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4189 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4191 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4193 shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4194 shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4195 shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4196 shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4197 shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4198 shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4200 for (i = 0;i < r_refdef.scene.numentities;i++)
4202 ent = r_refdef.scene.entities[i];
4203 if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
4205 // cast shadows from anything of the map (submodels are optional)
4206 if (!ent->animcache_vertex3f && ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4207 R_AnimCache_GetEntity(ent, false, false);
4211 void R_DrawModelShadowMaps(void)
4214 float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
4215 entity_render_t *ent;
4216 vec3_t relativelightorigin;
4217 vec3_t relativelightdirection, relativeforward, relativeright;
4218 vec3_t relativeshadowmins, relativeshadowmaxs;
4219 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
4221 matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
4222 r_viewport_t viewport;
4224 float clearcolor[4];
4226 if (!r_refdef.scene.numentities)
4229 switch (r_shadow_shadowmode)
4231 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4237 R_ResetViewRendering3D();
4238 R_Shadow_RenderMode_Begin();
4239 R_Shadow_RenderMode_ActiveLight(NULL);
4241 switch (r_shadow_shadowmode)
4243 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4244 if (!r_shadow_shadowmap2dtexture)
4245 R_Shadow_MakeShadowMap(0, r_shadow_shadowmapmaxsize);
4246 fbo = r_shadow_fbo2d;
4247 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
4248 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
4249 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
4255 size = 2*r_shadow_shadowmapmaxsize;
4256 scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
4257 radius = 0.5f / scale;
4258 nearclip = -r_shadows_throwdistance.value;
4259 farclip = r_shadows_throwdistance.value;
4260 bias = r_shadow_shadowmapping_bias.value * r_shadow_shadowmapping_nearclip.value / (2 * r_shadows_throwdistance.value) * (1024.0f / size);
4262 r_shadow_shadowmap_parameters[0] = size;
4263 r_shadow_shadowmap_parameters[1] = size;
4264 r_shadow_shadowmap_parameters[2] = 1.0;
4265 r_shadow_shadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
4267 Math_atov(r_shadows_throwdirection.string, shadowdir);
4268 VectorNormalize(shadowdir);
4269 Math_atov(r_shadows_focus.string, shadowfocus);
4270 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4271 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4272 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4273 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4274 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4275 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4276 if (fabs(dot1) <= fabs(dot2))
4277 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4279 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4280 VectorNormalize(shadowforward);
4281 VectorM(scale, shadowforward, &m[0]);
4282 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4284 m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
4285 CrossProduct(shadowdir, shadowforward, shadowright);
4286 VectorM(scale, shadowright, &m[4]);
4287 m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
4288 VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
4289 m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
4290 Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
4291 Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
4292 R_Viewport_InitOrtho(&viewport, &cameramatrix, 0, 0, size, size, 0, 0, 1, 1, 0, -1, NULL);
4294 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4296 R_Mesh_SetRenderTargets(fbo, r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
4297 R_SetupShader_DepthOrShadow();
4298 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
4301 R_SetViewport(&viewport);
4302 GL_Scissor(viewport.x, viewport.y, min(viewport.width + r_shadow_shadowmapborder, 2*r_shadow_shadowmapmaxsize), viewport.height + r_shadow_shadowmapborder);
4303 Vector4Set(clearcolor, 1,1,1,1);
4304 // in D3D9 we have to render to a color texture shadowmap
4305 // in GL we render directly to a depth texture only
4306 if (r_shadow_shadowmap2dtexture)
4307 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4309 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4310 // render into a slightly restricted region so that the borders of the
4311 // shadowmap area fade away, rather than streaking across everything
4312 // outside the usable area
4313 GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
4317 R_Mesh_ResetRenderTargets();
4318 R_SetupShader_ShowDepth();
4319 GL_ColorMask(1,1,1,1);
4320 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4323 for (i = 0;i < r_refdef.scene.numentities;i++)
4325 ent = r_refdef.scene.entities[i];
4327 // cast shadows from anything of the map (submodels are optional)
4328 if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4330 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4331 Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
4332 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4333 Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
4334 Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
4335 relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4336 relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4337 relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4338 relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4339 relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4340 relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4341 RSurf_ActiveModelEntity(ent, false, false, false);
4342 ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
4343 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4350 unsigned char *rawpixels = Z_Malloc(viewport.width*viewport.height*4);
4352 qglReadPixels(viewport.x, viewport.y, viewport.width, viewport.height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, rawpixels);
4354 Image_WriteTGABGRA("r_shadows_2.tga", viewport.width, viewport.height, rawpixels);
4355 Cvar_SetValueQuick(&r_test, 0);
4360 R_Shadow_RenderMode_End();
4362 Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
4363 Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
4364 Matrix4x4_CreateScale3(&scalematrix, size, -size, 1);
4365 Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
4366 Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
4367 Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
4369 r_shadow_usingshadowmaportho = true;
4370 switch (r_shadow_shadowmode)
4372 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4373 r_shadow_usingshadowmap2d = true;
4380 void R_DrawModelShadows(void)
4383 float relativethrowdistance;
4384 entity_render_t *ent;
4385 vec3_t relativelightorigin;
4386 vec3_t relativelightdirection;
4387 vec3_t relativeshadowmins, relativeshadowmaxs;
4388 vec3_t tmp, shadowdir;
4390 if (!r_refdef.scene.numentities || !vid.stencil || (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL && r_shadows.integer != 1))
4393 R_ResetViewRendering3D();
4394 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4395 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4396 R_Shadow_RenderMode_Begin();
4397 R_Shadow_RenderMode_ActiveLight(NULL);
4398 r_shadow_lightscissor[0] = r_refdef.view.x;
4399 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
4400 r_shadow_lightscissor[2] = r_refdef.view.width;
4401 r_shadow_lightscissor[3] = r_refdef.view.height;
4402 R_Shadow_RenderMode_StencilShadowVolumes(false);
4405 if (r_shadows.integer == 2)
4407 Math_atov(r_shadows_throwdirection.string, shadowdir);
4408 VectorNormalize(shadowdir);
4411 R_Shadow_ClearStencil();
4413 for (i = 0;i < r_refdef.scene.numentities;i++)
4415 ent = r_refdef.scene.entities[i];
4417 // cast shadows from anything of the map (submodels are optional)
4418 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4420 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4421 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
4422 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
4423 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
4424 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4427 if(ent->entitynumber != 0)
4429 if(ent->entitynumber >= MAX_EDICTS) // csqc entity
4431 // FIXME handle this
4432 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4436 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
4437 int entnum, entnum2, recursion;
4438 entnum = entnum2 = ent->entitynumber;
4439 for(recursion = 32; recursion > 0; --recursion)
4441 entnum2 = cl.entities[entnum].state_current.tagentity;
4442 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
4447 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
4449 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
4450 // transform into modelspace of OUR entity
4451 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
4452 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
4455 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4459 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4462 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
4463 RSurf_ActiveModelEntity(ent, false, false, false);
4464 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4465 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4469 // not really the right mode, but this will disable any silly stencil features
4470 R_Shadow_RenderMode_End();
4472 // set up ortho view for rendering this pass
4473 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4474 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4475 //GL_ScissorTest(true);
4476 //R_EntityMatrix(&identitymatrix);
4477 //R_Mesh_ResetTextureState();
4478 R_ResetViewRendering2D();
4480 // set up a darkening blend on shadowed areas
4481 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4482 //GL_DepthRange(0, 1);
4483 //GL_DepthTest(false);
4484 //GL_DepthMask(false);
4485 //GL_PolygonOffset(0, 0);CHECKGLERROR
4486 GL_Color(0, 0, 0, r_shadows_darken.value);
4487 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4488 //GL_DepthFunc(GL_ALWAYS);
4489 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_NOTEQUAL, 128, 255);
4491 // apply the blend to the shadowed areas
4492 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, NULL);
4493 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
4494 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4496 // restore the viewport
4497 R_SetViewport(&r_refdef.view.viewport);
4499 // restore other state to normal
4500 //R_Shadow_RenderMode_End();
4503 void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4506 vec3_t centerorigin;
4508 // if it's too close, skip it
4509 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
4511 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4514 if (usequery && r_numqueries + 2 <= r_maxqueries)
4516 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4517 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4518 // 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
4519 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4521 switch(vid.renderpath)
4523 case RENDERPATH_GL20:
4524 case RENDERPATH_GL13:
4525 case RENDERPATH_GL11:
4526 case RENDERPATH_CGGL:
4528 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use GL_DepthFunc instead
4529 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
4530 GL_DepthFunc(GL_ALWAYS);
4531 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4532 R_Mesh_PrepareVertices_Position_Arrays(4, vertex3f);
4533 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4534 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4535 GL_DepthFunc(GL_LEQUAL);
4536 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
4537 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4538 R_Mesh_PrepareVertices_Position_Arrays(4, vertex3f);
4539 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4540 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4543 case RENDERPATH_D3D9:
4544 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4546 case RENDERPATH_D3D10:
4547 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4549 case RENDERPATH_D3D11:
4550 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4554 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4557 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
4559 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4562 GLint allpixels = 0, visiblepixels = 0;
4563 // now we have to check the query result
4564 if (rtlight->corona_queryindex_visiblepixels)
4566 switch(vid.renderpath)
4568 case RENDERPATH_GL20:
4569 case RENDERPATH_GL13:
4570 case RENDERPATH_GL11:
4571 case RENDERPATH_CGGL:
4573 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
4574 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
4577 case RENDERPATH_D3D9:
4578 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4580 case RENDERPATH_D3D10:
4581 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4583 case RENDERPATH_D3D11:
4584 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4587 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
4588 if (visiblepixels < 1 || allpixels < 1)
4590 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
4591 cscale *= rtlight->corona_visibility;
4595 // FIXME: these traces should scan all render entities instead of cl.world
4596 if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
4599 VectorScale(rtlight->currentcolor, cscale, color);
4600 if (VectorLength(color) > (1.0f / 256.0f))
4603 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
4606 VectorNegate(color, color);
4607 switch(vid.renderpath)
4609 case RENDERPATH_GL11:
4610 case RENDERPATH_GL13:
4611 case RENDERPATH_GL20:
4612 case RENDERPATH_CGGL:
4613 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
4615 case RENDERPATH_D3D9:
4617 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_SUBTRACT);
4620 case RENDERPATH_D3D10:
4621 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4623 case RENDERPATH_D3D11:
4624 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4628 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4629 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);
4630 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4633 switch(vid.renderpath)
4635 case RENDERPATH_GL11:
4636 case RENDERPATH_GL13:
4637 case RENDERPATH_GL20:
4638 case RENDERPATH_CGGL:
4639 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
4641 case RENDERPATH_D3D9:
4643 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_ADD);
4646 case RENDERPATH_D3D10:
4647 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4649 case RENDERPATH_D3D11:
4650 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4657 void R_Shadow_DrawCoronas(void)
4660 qboolean usequery = false;
4665 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4667 if (r_waterstate.renderingscene)
4669 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4670 R_EntityMatrix(&identitymatrix);
4672 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4674 // check occlusion of coronas
4675 // use GL_ARB_occlusion_query if available
4676 // otherwise use raytraces
4678 switch (vid.renderpath)
4680 case RENDERPATH_GL11:
4681 case RENDERPATH_GL13:
4682 case RENDERPATH_GL20:
4683 case RENDERPATH_CGGL:
4684 usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
4687 GL_ColorMask(0,0,0,0);
4688 if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
4689 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
4692 r_maxqueries = (range + r_refdef.scene.numlights) * 4;
4693 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
4695 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
4698 RSurf_ActiveWorldEntity();
4699 GL_BlendFunc(GL_ONE, GL_ZERO);
4700 GL_CullFace(GL_NONE);
4701 GL_DepthMask(false);
4702 GL_DepthRange(0, 1);
4703 GL_PolygonOffset(0, 0);
4705 R_Mesh_ResetTextureState();
4706 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
4709 case RENDERPATH_D3D9:
4711 //Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4713 case RENDERPATH_D3D10:
4714 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4716 case RENDERPATH_D3D11:
4717 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4720 for (lightindex = 0;lightindex < range;lightindex++)
4722 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4725 rtlight = &light->rtlight;
4726 rtlight->corona_visibility = 0;
4727 rtlight->corona_queryindex_visiblepixels = 0;
4728 rtlight->corona_queryindex_allpixels = 0;
4729 if (!(rtlight->flags & flag))
4731 if (rtlight->corona <= 0)
4733 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4735 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4737 for (i = 0;i < r_refdef.scene.numlights;i++)
4739 rtlight = r_refdef.scene.lights[i];
4740 rtlight->corona_visibility = 0;
4741 rtlight->corona_queryindex_visiblepixels = 0;
4742 rtlight->corona_queryindex_allpixels = 0;
4743 if (!(rtlight->flags & flag))
4745 if (rtlight->corona <= 0)
4747 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4750 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4752 // now draw the coronas using the query data for intensity info
4753 for (lightindex = 0;lightindex < range;lightindex++)
4755 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4758 rtlight = &light->rtlight;
4759 if (rtlight->corona_visibility <= 0)
4761 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4763 for (i = 0;i < r_refdef.scene.numlights;i++)
4765 rtlight = r_refdef.scene.lights[i];
4766 if (rtlight->corona_visibility <= 0)
4768 if (gl_flashblend.integer)
4769 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4771 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4777 dlight_t *R_Shadow_NewWorldLight(void)
4779 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4782 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)
4785 // validate parameters
4786 if (style < 0 || style >= MAX_LIGHTSTYLES)
4788 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
4794 // copy to light properties
4795 VectorCopy(origin, light->origin);
4796 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4797 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4798 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4800 light->color[0] = max(color[0], 0);
4801 light->color[1] = max(color[1], 0);
4802 light->color[2] = max(color[2], 0);
4804 light->color[0] = color[0];
4805 light->color[1] = color[1];
4806 light->color[2] = color[2];
4807 light->radius = max(radius, 0);
4808 light->style = style;
4809 light->shadow = shadowenable;
4810 light->corona = corona;
4811 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4812 light->coronasizescale = coronasizescale;
4813 light->ambientscale = ambientscale;
4814 light->diffusescale = diffusescale;
4815 light->specularscale = specularscale;
4816 light->flags = flags;
4818 // update renderable light data
4819 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4820 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);
4823 void R_Shadow_FreeWorldLight(dlight_t *light)
4825 if (r_shadow_selectedlight == light)
4826 r_shadow_selectedlight = NULL;
4827 R_RTLight_Uncompile(&light->rtlight);
4828 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4831 void R_Shadow_ClearWorldLights(void)
4835 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4836 for (lightindex = 0;lightindex < range;lightindex++)
4838 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4840 R_Shadow_FreeWorldLight(light);
4842 r_shadow_selectedlight = NULL;
4845 void R_Shadow_SelectLight(dlight_t *light)
4847 if (r_shadow_selectedlight)
4848 r_shadow_selectedlight->selected = false;
4849 r_shadow_selectedlight = light;
4850 if (r_shadow_selectedlight)
4851 r_shadow_selectedlight->selected = true;
4854 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4856 // this is never batched (there can be only one)
4858 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
4859 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4860 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4863 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4868 skinframe_t *skinframe;
4871 // this is never batched (due to the ent parameter changing every time)
4872 // so numsurfaces == 1 and surfacelist[0] == lightnumber
4873 const dlight_t *light = (dlight_t *)ent;
4876 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
4879 VectorScale(light->color, intensity, spritecolor);
4880 if (VectorLength(spritecolor) < 0.1732f)
4881 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
4882 if (VectorLength(spritecolor) > 1.0f)
4883 VectorNormalize(spritecolor);
4885 // draw light sprite
4886 if (light->cubemapname[0] && !light->shadow)
4887 skinframe = r_editlights_sprcubemapnoshadowlight;
4888 else if (light->cubemapname[0])
4889 skinframe = r_editlights_sprcubemaplight;
4890 else if (!light->shadow)
4891 skinframe = r_editlights_sprnoshadowlight;
4893 skinframe = r_editlights_sprlight;
4895 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);
4896 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4898 // draw selection sprite if light is selected
4899 if (light->selected)
4901 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4902 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4903 // VorteX todo: add normalmode/realtime mode light overlay sprites?
4907 void R_Shadow_DrawLightSprites(void)
4911 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4912 for (lightindex = 0;lightindex < range;lightindex++)
4914 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4916 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
4918 if (!r_editlights_lockcursor)
4919 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
4922 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
4927 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
4928 if (lightindex >= range)
4930 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4933 rtlight = &light->rtlight;
4934 //if (!(rtlight->flags & flag))
4936 VectorCopy(rtlight->shadoworigin, origin);
4937 *radius = rtlight->radius;
4938 VectorCopy(rtlight->color, color);
4942 void R_Shadow_SelectLightInView(void)
4944 float bestrating, rating, temp[3];
4948 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4952 if (r_editlights_lockcursor)
4954 for (lightindex = 0;lightindex < range;lightindex++)
4956 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4959 VectorSubtract(light->origin, r_refdef.view.origin, temp);
4960 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
4963 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
4964 if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1.0f)
4966 bestrating = rating;
4971 R_Shadow_SelectLight(best);
4974 void R_Shadow_LoadWorldLights(void)
4976 int n, a, style, shadow, flags;
4977 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
4978 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
4979 if (cl.worldmodel == NULL)
4981 Con_Print("No map loaded.\n");
4984 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
4985 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4995 for (;COM_Parse(t, true) && strcmp(
4996 if (COM_Parse(t, true))
4998 if (com_token[0] == '!')
5001 origin[0] = atof(com_token+1);
5004 origin[0] = atof(com_token);
5009 while (*s && *s != '\n' && *s != '\r')
5015 // check for modifier flags
5022 #if _MSC_VER >= 1400
5023 #define sscanf sscanf_s
5025 cubemapname[sizeof(cubemapname)-1] = 0;
5026 #if MAX_QPATH != 128
5027 #error update this code if MAX_QPATH changes
5029 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
5030 #if _MSC_VER >= 1400
5031 , sizeof(cubemapname)
5033 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
5036 flags = LIGHTFLAG_REALTIMEMODE;
5044 coronasizescale = 0.25f;
5046 VectorClear(angles);
5049 if (a < 9 || !strcmp(cubemapname, "\"\""))
5051 // remove quotes on cubemapname
5052 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
5055 namelen = strlen(cubemapname) - 2;
5056 memmove(cubemapname, cubemapname + 1, namelen);
5057 cubemapname[namelen] = '\0';
5061 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);
5064 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5072 Con_Printf("invalid rtlights file \"%s\"\n", name);
5073 Mem_Free(lightsstring);
5077 void R_Shadow_SaveWorldLights(void)
5081 size_t bufchars, bufmaxchars;
5083 char name[MAX_QPATH];
5084 char line[MAX_INPUTLINE];
5085 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
5086 // I hate lines which are 3 times my screen size :( --blub
5089 if (cl.worldmodel == NULL)
5091 Con_Print("No map loaded.\n");
5094 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
5095 bufchars = bufmaxchars = 0;
5097 for (lightindex = 0;lightindex < range;lightindex++)
5099 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5102 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
5103 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);
5104 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
5105 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]);
5107 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);
5108 if (bufchars + strlen(line) > bufmaxchars)
5110 bufmaxchars = bufchars + strlen(line) + 2048;
5112 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
5116 memcpy(buf, oldbuf, bufchars);
5122 memcpy(buf + bufchars, line, strlen(line));
5123 bufchars += strlen(line);
5127 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
5132 void R_Shadow_LoadLightsFile(void)
5135 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
5136 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
5137 if (cl.worldmodel == NULL)
5139 Con_Print("No map loaded.\n");
5142 dpsnprintf(name, sizeof(name), "%s.lights", cl.worldnamenoextension);
5143 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5151 while (*s && *s != '\n' && *s != '\r')
5157 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);
5161 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);
5164 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
5165 radius = bound(15, radius, 4096);
5166 VectorScale(color, (2.0f / (8388608.0f)), color);
5167 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5175 Con_Printf("invalid lights file \"%s\"\n", name);
5176 Mem_Free(lightsstring);
5180 // tyrlite/hmap2 light types in the delay field
5181 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
5183 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
5195 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
5196 char key[256], value[MAX_INPUTLINE];
5198 if (cl.worldmodel == NULL)
5200 Con_Print("No map loaded.\n");
5203 // try to load a .ent file first
5204 dpsnprintf(key, sizeof(key), "%s.ent", cl.worldnamenoextension);
5205 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
5206 // and if that is not found, fall back to the bsp file entity string
5208 data = cl.worldmodel->brush.entities;
5211 for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
5213 type = LIGHTTYPE_MINUSX;
5214 origin[0] = origin[1] = origin[2] = 0;
5215 originhack[0] = originhack[1] = originhack[2] = 0;
5216 angles[0] = angles[1] = angles[2] = 0;
5217 color[0] = color[1] = color[2] = 1;
5218 light[0] = light[1] = light[2] = 1;light[3] = 300;
5219 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
5229 if (!COM_ParseToken_Simple(&data, false, false))
5231 if (com_token[0] == '}')
5232 break; // end of entity
5233 if (com_token[0] == '_')
5234 strlcpy(key, com_token + 1, sizeof(key));
5236 strlcpy(key, com_token, sizeof(key));
5237 while (key[strlen(key)-1] == ' ') // remove trailing spaces
5238 key[strlen(key)-1] = 0;
5239 if (!COM_ParseToken_Simple(&data, false, false))
5241 strlcpy(value, com_token, sizeof(value));
5243 // now that we have the key pair worked out...
5244 if (!strcmp("light", key))
5246 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5250 light[0] = vec[0] * (1.0f / 256.0f);
5251 light[1] = vec[0] * (1.0f / 256.0f);
5252 light[2] = vec[0] * (1.0f / 256.0f);
5258 light[0] = vec[0] * (1.0f / 255.0f);
5259 light[1] = vec[1] * (1.0f / 255.0f);
5260 light[2] = vec[2] * (1.0f / 255.0f);
5264 else if (!strcmp("delay", key))
5266 else if (!strcmp("origin", key))
5267 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5268 else if (!strcmp("angle", key))
5269 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5270 else if (!strcmp("angles", key))
5271 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5272 else if (!strcmp("color", key))
5273 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5274 else if (!strcmp("wait", key))
5275 fadescale = atof(value);
5276 else if (!strcmp("classname", key))
5278 if (!strncmp(value, "light", 5))
5281 if (!strcmp(value, "light_fluoro"))
5286 overridecolor[0] = 1;
5287 overridecolor[1] = 1;
5288 overridecolor[2] = 1;
5290 if (!strcmp(value, "light_fluorospark"))
5295 overridecolor[0] = 1;
5296 overridecolor[1] = 1;
5297 overridecolor[2] = 1;
5299 if (!strcmp(value, "light_globe"))
5304 overridecolor[0] = 1;
5305 overridecolor[1] = 0.8;
5306 overridecolor[2] = 0.4;
5308 if (!strcmp(value, "light_flame_large_yellow"))
5313 overridecolor[0] = 1;
5314 overridecolor[1] = 0.5;
5315 overridecolor[2] = 0.1;
5317 if (!strcmp(value, "light_flame_small_yellow"))
5322 overridecolor[0] = 1;
5323 overridecolor[1] = 0.5;
5324 overridecolor[2] = 0.1;
5326 if (!strcmp(value, "light_torch_small_white"))
5331 overridecolor[0] = 1;
5332 overridecolor[1] = 0.5;
5333 overridecolor[2] = 0.1;
5335 if (!strcmp(value, "light_torch_small_walltorch"))
5340 overridecolor[0] = 1;
5341 overridecolor[1] = 0.5;
5342 overridecolor[2] = 0.1;
5346 else if (!strcmp("style", key))
5347 style = atoi(value);
5348 else if (!strcmp("skin", key))
5349 skin = (int)atof(value);
5350 else if (!strcmp("pflags", key))
5351 pflags = (int)atof(value);
5352 //else if (!strcmp("effects", key))
5353 // effects = (int)atof(value);
5354 else if (cl.worldmodel->type == mod_brushq3)
5356 if (!strcmp("scale", key))
5357 lightscale = atof(value);
5358 if (!strcmp("fade", key))
5359 fadescale = atof(value);
5364 if (lightscale <= 0)
5368 if (color[0] == color[1] && color[0] == color[2])
5370 color[0] *= overridecolor[0];
5371 color[1] *= overridecolor[1];
5372 color[2] *= overridecolor[2];
5374 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5375 color[0] = color[0] * light[0];
5376 color[1] = color[1] * light[1];
5377 color[2] = color[2] * light[2];
5380 case LIGHTTYPE_MINUSX:
5382 case LIGHTTYPE_RECIPX:
5384 VectorScale(color, (1.0f / 16.0f), color);
5386 case LIGHTTYPE_RECIPXX:
5388 VectorScale(color, (1.0f / 16.0f), color);
5391 case LIGHTTYPE_NONE:
5395 case LIGHTTYPE_MINUSXX:
5398 VectorAdd(origin, originhack, origin);
5400 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);
5403 Mem_Free(entfiledata);
5407 void R_Shadow_SetCursorLocationForView(void)
5410 vec3_t dest, endpos;
5412 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5413 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
5414 if (trace.fraction < 1)
5416 dist = trace.fraction * r_editlights_cursordistance.value;
5417 push = r_editlights_cursorpushback.value;
5421 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5422 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5426 VectorClear( endpos );
5428 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5429 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5430 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5433 void R_Shadow_UpdateWorldLightSelection(void)
5435 if (r_editlights.integer)
5437 R_Shadow_SetCursorLocationForView();
5438 R_Shadow_SelectLightInView();
5441 R_Shadow_SelectLight(NULL);
5444 void R_Shadow_EditLights_Clear_f(void)
5446 R_Shadow_ClearWorldLights();
5449 void R_Shadow_EditLights_Reload_f(void)
5453 strlcpy(r_shadow_mapname, cl.worldname, sizeof(r_shadow_mapname));
5454 R_Shadow_ClearWorldLights();
5455 R_Shadow_LoadWorldLights();
5456 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5458 R_Shadow_LoadLightsFile();
5459 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5460 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5464 void R_Shadow_EditLights_Save_f(void)
5468 R_Shadow_SaveWorldLights();
5471 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
5473 R_Shadow_ClearWorldLights();
5474 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5477 void R_Shadow_EditLights_ImportLightsFile_f(void)
5479 R_Shadow_ClearWorldLights();
5480 R_Shadow_LoadLightsFile();
5483 void R_Shadow_EditLights_Spawn_f(void)
5486 if (!r_editlights.integer)
5488 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5491 if (Cmd_Argc() != 1)
5493 Con_Print("r_editlights_spawn does not take parameters\n");
5496 color[0] = color[1] = color[2] = 1;
5497 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5500 void R_Shadow_EditLights_Edit_f(void)
5502 vec3_t origin, angles, color;
5503 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5504 int style, shadows, flags, normalmode, realtimemode;
5505 char cubemapname[MAX_INPUTLINE];
5506 if (!r_editlights.integer)
5508 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5511 if (!r_shadow_selectedlight)
5513 Con_Print("No selected light.\n");
5516 VectorCopy(r_shadow_selectedlight->origin, origin);
5517 VectorCopy(r_shadow_selectedlight->angles, angles);
5518 VectorCopy(r_shadow_selectedlight->color, color);
5519 radius = r_shadow_selectedlight->radius;
5520 style = r_shadow_selectedlight->style;
5521 if (r_shadow_selectedlight->cubemapname)
5522 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5525 shadows = r_shadow_selectedlight->shadow;
5526 corona = r_shadow_selectedlight->corona;
5527 coronasizescale = r_shadow_selectedlight->coronasizescale;
5528 ambientscale = r_shadow_selectedlight->ambientscale;
5529 diffusescale = r_shadow_selectedlight->diffusescale;
5530 specularscale = r_shadow_selectedlight->specularscale;
5531 flags = r_shadow_selectedlight->flags;
5532 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5533 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5534 if (!strcmp(Cmd_Argv(1), "origin"))
5536 if (Cmd_Argc() != 5)
5538 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5541 origin[0] = atof(Cmd_Argv(2));
5542 origin[1] = atof(Cmd_Argv(3));
5543 origin[2] = atof(Cmd_Argv(4));
5545 else if (!strcmp(Cmd_Argv(1), "originx"))
5547 if (Cmd_Argc() != 3)
5549 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5552 origin[0] = atof(Cmd_Argv(2));
5554 else if (!strcmp(Cmd_Argv(1), "originy"))
5556 if (Cmd_Argc() != 3)
5558 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5561 origin[1] = atof(Cmd_Argv(2));
5563 else if (!strcmp(Cmd_Argv(1), "originz"))
5565 if (Cmd_Argc() != 3)
5567 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5570 origin[2] = atof(Cmd_Argv(2));
5572 else if (!strcmp(Cmd_Argv(1), "move"))
5574 if (Cmd_Argc() != 5)
5576 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5579 origin[0] += atof(Cmd_Argv(2));
5580 origin[1] += atof(Cmd_Argv(3));
5581 origin[2] += atof(Cmd_Argv(4));
5583 else if (!strcmp(Cmd_Argv(1), "movex"))
5585 if (Cmd_Argc() != 3)
5587 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5590 origin[0] += atof(Cmd_Argv(2));
5592 else if (!strcmp(Cmd_Argv(1), "movey"))
5594 if (Cmd_Argc() != 3)
5596 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5599 origin[1] += atof(Cmd_Argv(2));
5601 else if (!strcmp(Cmd_Argv(1), "movez"))
5603 if (Cmd_Argc() != 3)
5605 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5608 origin[2] += atof(Cmd_Argv(2));
5610 else if (!strcmp(Cmd_Argv(1), "angles"))
5612 if (Cmd_Argc() != 5)
5614 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5617 angles[0] = atof(Cmd_Argv(2));
5618 angles[1] = atof(Cmd_Argv(3));
5619 angles[2] = atof(Cmd_Argv(4));
5621 else if (!strcmp(Cmd_Argv(1), "anglesx"))
5623 if (Cmd_Argc() != 3)
5625 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5628 angles[0] = atof(Cmd_Argv(2));
5630 else if (!strcmp(Cmd_Argv(1), "anglesy"))
5632 if (Cmd_Argc() != 3)
5634 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5637 angles[1] = atof(Cmd_Argv(2));
5639 else if (!strcmp(Cmd_Argv(1), "anglesz"))
5641 if (Cmd_Argc() != 3)
5643 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5646 angles[2] = atof(Cmd_Argv(2));
5648 else if (!strcmp(Cmd_Argv(1), "color"))
5650 if (Cmd_Argc() != 5)
5652 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
5655 color[0] = atof(Cmd_Argv(2));
5656 color[1] = atof(Cmd_Argv(3));
5657 color[2] = atof(Cmd_Argv(4));
5659 else if (!strcmp(Cmd_Argv(1), "radius"))
5661 if (Cmd_Argc() != 3)
5663 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5666 radius = atof(Cmd_Argv(2));
5668 else if (!strcmp(Cmd_Argv(1), "colorscale"))
5670 if (Cmd_Argc() == 3)
5672 double scale = atof(Cmd_Argv(2));
5679 if (Cmd_Argc() != 5)
5681 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
5684 color[0] *= atof(Cmd_Argv(2));
5685 color[1] *= atof(Cmd_Argv(3));
5686 color[2] *= atof(Cmd_Argv(4));
5689 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
5691 if (Cmd_Argc() != 3)
5693 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5696 radius *= atof(Cmd_Argv(2));
5698 else if (!strcmp(Cmd_Argv(1), "style"))
5700 if (Cmd_Argc() != 3)
5702 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5705 style = atoi(Cmd_Argv(2));
5707 else if (!strcmp(Cmd_Argv(1), "cubemap"))
5711 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5714 if (Cmd_Argc() == 3)
5715 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
5719 else if (!strcmp(Cmd_Argv(1), "shadows"))
5721 if (Cmd_Argc() != 3)
5723 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5726 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5728 else if (!strcmp(Cmd_Argv(1), "corona"))
5730 if (Cmd_Argc() != 3)
5732 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5735 corona = atof(Cmd_Argv(2));
5737 else if (!strcmp(Cmd_Argv(1), "coronasize"))
5739 if (Cmd_Argc() != 3)
5741 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5744 coronasizescale = atof(Cmd_Argv(2));
5746 else if (!strcmp(Cmd_Argv(1), "ambient"))
5748 if (Cmd_Argc() != 3)
5750 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5753 ambientscale = atof(Cmd_Argv(2));
5755 else if (!strcmp(Cmd_Argv(1), "diffuse"))
5757 if (Cmd_Argc() != 3)
5759 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5762 diffusescale = atof(Cmd_Argv(2));
5764 else if (!strcmp(Cmd_Argv(1), "specular"))
5766 if (Cmd_Argc() != 3)
5768 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5771 specularscale = atof(Cmd_Argv(2));
5773 else if (!strcmp(Cmd_Argv(1), "normalmode"))
5775 if (Cmd_Argc() != 3)
5777 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5780 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5782 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
5784 if (Cmd_Argc() != 3)
5786 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5789 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5793 Con_Print("usage: r_editlights_edit [property] [value]\n");
5794 Con_Print("Selected light's properties:\n");
5795 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5796 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5797 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5798 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
5799 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
5800 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
5801 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5802 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
5803 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
5804 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
5805 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
5806 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
5807 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5808 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5811 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5812 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5815 void R_Shadow_EditLights_EditAll_f(void)
5818 dlight_t *light, *oldselected;
5821 if (!r_editlights.integer)
5823 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5827 oldselected = r_shadow_selectedlight;
5828 // EditLights doesn't seem to have a "remove" command or something so:
5829 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5830 for (lightindex = 0;lightindex < range;lightindex++)
5832 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5835 R_Shadow_SelectLight(light);
5836 R_Shadow_EditLights_Edit_f();
5838 // return to old selected (to not mess editing once selection is locked)
5839 R_Shadow_SelectLight(oldselected);
5842 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
5844 int lightnumber, lightcount;
5845 size_t lightindex, range;
5849 if (!r_editlights.integer)
5851 x = vid_conwidth.value - 240;
5853 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
5856 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5857 for (lightindex = 0;lightindex < range;lightindex++)
5859 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5862 if (light == r_shadow_selectedlight)
5863 lightnumber = lightindex;
5866 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;
5867 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;
5869 if (r_shadow_selectedlight == NULL)
5871 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;
5872 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;
5873 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;
5874 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;
5875 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;
5876 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;
5877 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;
5878 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;
5879 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;
5880 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;
5881 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;
5882 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;
5883 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;
5884 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;
5885 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;
5888 void R_Shadow_EditLights_ToggleShadow_f(void)
5890 if (!r_editlights.integer)
5892 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5895 if (!r_shadow_selectedlight)
5897 Con_Print("No selected light.\n");
5900 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);
5903 void R_Shadow_EditLights_ToggleCorona_f(void)
5905 if (!r_editlights.integer)
5907 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5910 if (!r_shadow_selectedlight)
5912 Con_Print("No selected light.\n");
5915 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);
5918 void R_Shadow_EditLights_Remove_f(void)
5920 if (!r_editlights.integer)
5922 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
5925 if (!r_shadow_selectedlight)
5927 Con_Print("No selected light.\n");
5930 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
5931 r_shadow_selectedlight = NULL;
5934 void R_Shadow_EditLights_Help_f(void)
5937 "Documentation on r_editlights system:\n"
5939 "r_editlights : enable/disable editing mode\n"
5940 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
5941 "r_editlights_cursorpushback : push back cursor this far from surface\n"
5942 "r_editlights_cursorpushoff : push cursor off surface this far\n"
5943 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
5944 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
5946 "r_editlights_help : this help\n"
5947 "r_editlights_clear : remove all lights\n"
5948 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
5949 "r_editlights_lock : lock selection to current light, if already locked - unlock\n"
5950 "r_editlights_save : save to .rtlights file\n"
5951 "r_editlights_spawn : create a light with default settings\n"
5952 "r_editlights_edit command : edit selected light - more documentation below\n"
5953 "r_editlights_remove : remove selected light\n"
5954 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
5955 "r_editlights_importlightentitiesfrommap : reload light entities\n"
5956 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
5958 "origin x y z : set light location\n"
5959 "originx x: set x component of light location\n"
5960 "originy y: set y component of light location\n"
5961 "originz z: set z component of light location\n"
5962 "move x y z : adjust light location\n"
5963 "movex x: adjust x component of light location\n"
5964 "movey y: adjust y component of light location\n"
5965 "movez z: adjust z component of light location\n"
5966 "angles x y z : set light angles\n"
5967 "anglesx x: set x component of light angles\n"
5968 "anglesy y: set y component of light angles\n"
5969 "anglesz z: set z component of light angles\n"
5970 "color r g b : set color of light (can be brighter than 1 1 1)\n"
5971 "radius radius : set radius (size) of light\n"
5972 "colorscale grey : multiply color of light (1 does nothing)\n"
5973 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
5974 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
5975 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
5976 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
5977 "cubemap basename : set filter cubemap of light (not yet supported)\n"
5978 "shadows 1/0 : turn on/off shadows\n"
5979 "corona n : set corona intensity\n"
5980 "coronasize n : set corona size (0-1)\n"
5981 "ambient n : set ambient intensity (0-1)\n"
5982 "diffuse n : set diffuse intensity (0-1)\n"
5983 "specular n : set specular intensity (0-1)\n"
5984 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
5985 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
5986 "<nothing> : print light properties to console\n"
5990 void R_Shadow_EditLights_CopyInfo_f(void)
5992 if (!r_editlights.integer)
5994 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
5997 if (!r_shadow_selectedlight)
5999 Con_Print("No selected light.\n");
6002 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
6003 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
6004 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
6005 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
6006 if (r_shadow_selectedlight->cubemapname)
6007 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
6009 r_shadow_bufferlight.cubemapname[0] = 0;
6010 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
6011 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
6012 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
6013 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
6014 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
6015 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
6016 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
6019 void R_Shadow_EditLights_PasteInfo_f(void)
6021 if (!r_editlights.integer)
6023 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
6026 if (!r_shadow_selectedlight)
6028 Con_Print("No selected light.\n");
6031 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);
6034 void R_Shadow_EditLights_Lock_f(void)
6036 if (!r_editlights.integer)
6038 Con_Print("Cannot lock on light when not in editing mode. Set r_editlights to 1.\n");
6041 if (r_editlights_lockcursor)
6043 r_editlights_lockcursor = false;
6046 if (!r_shadow_selectedlight)
6048 Con_Print("No selected light to lock on.\n");
6051 r_editlights_lockcursor = true;
6054 void R_Shadow_EditLights_Init(void)
6056 Cvar_RegisterVariable(&r_editlights);
6057 Cvar_RegisterVariable(&r_editlights_cursordistance);
6058 Cvar_RegisterVariable(&r_editlights_cursorpushback);
6059 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
6060 Cvar_RegisterVariable(&r_editlights_cursorgrid);
6061 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
6062 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
6063 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
6064 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)");
6065 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
6066 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
6067 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
6068 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)");
6069 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
6070 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
6071 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
6072 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
6073 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
6074 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
6075 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)");
6076 Cmd_AddCommand("r_editlights_lock", R_Shadow_EditLights_Lock_f, "lock selection to current light, if already locked - unlock");
6082 =============================================================================
6086 =============================================================================
6089 void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, int dynamic)
6091 VectorClear(diffusecolor);
6092 VectorClear(diffusenormal);
6094 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
6096 ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_refdef.scene.ambient;
6097 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
6100 VectorSet(ambientcolor, 1, 1, 1);
6107 for (i = 0;i < r_refdef.scene.numlights;i++)
6109 light = r_refdef.scene.lights[i];
6110 Matrix4x4_Transform(&light->matrix_worldtolight, p, v);
6111 f = 1 - VectorLength2(v);
6112 if (f > 0 && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
6113 VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);