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 void R_Shadow_RenderMode_ShadowMap(int side, int clear, int size)
2051 float nearclip, farclip, bias;
2052 r_viewport_t viewport;
2055 float clearcolor[4];
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 Vector4Set(clearcolor, 1,1,1,1);
2120 // completely different meaning than in OpenGL path
2121 r_shadow_shadowmap_parameters[1] = 0;
2122 r_shadow_shadowmap_parameters[3] = -bias;
2123 // we invert the cull mode because we flip the projection matrix
2124 // NOTE: this actually does nothing because the DrawShadowMap code sets it to doublesided...
2125 GL_CullFace(r_refdef.view.cullface_front);
2126 // D3D considers it an error to use a scissor larger than the viewport... clear just this view
2127 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2128 if (r_shadow_shadowmapsampler)
2130 GL_ColorMask(0,0,0,0);
2132 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
2136 GL_ColorMask(1,1,1,1);
2138 GL_Clear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
2141 case RENDERPATH_D3D10:
2142 case RENDERPATH_D3D11:
2143 // D3D considers it an error to use a scissor larger than the viewport... clear just this view
2144 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2145 GL_ColorMask(0,0,0,0);
2147 GL_Clear(GL_DEPTH_BUFFER_BIT, NULL, 1.0f, 0);
2152 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
2154 R_Mesh_ResetTextureState();
2155 R_Mesh_ResetRenderTargets();
2158 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2159 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2160 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2161 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2163 R_Shadow_RenderMode_Reset();
2164 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2166 GL_DepthFunc(GL_EQUAL);
2167 // do global setup needed for the chosen lighting mode
2168 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2169 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2170 r_shadow_usingshadowmap2d = shadowmapping;
2171 r_shadow_rendermode = r_shadow_lightingrendermode;
2172 // only draw light where this geometry was already rendered AND the
2173 // stencil is 128 (values other than this mean shadow)
2175 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2177 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
2180 static const unsigned short bboxelements[36] =
2190 static const float bboxpoints[8][3] =
2202 void R_Shadow_RenderMode_DrawDeferredLight(qboolean stenciltest, qboolean shadowmapping)
2205 float vertex3f[8*3];
2206 const matrix4x4_t *matrix = &rsurface.rtlight->matrix_lighttoworld;
2207 // do global setup needed for the chosen lighting mode
2208 R_Shadow_RenderMode_Reset();
2209 r_shadow_rendermode = r_shadow_lightingrendermode;
2210 R_EntityMatrix(&identitymatrix);
2211 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2212 // only draw light where this geometry was already rendered AND the
2213 // stencil is 128 (values other than this mean shadow)
2214 R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2215 R_Mesh_SetRenderTargets(r_shadow_prepasslightingfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
2217 r_shadow_usingshadowmap2d = shadowmapping;
2219 // render the lighting
2220 R_SetupShader_DeferredLight(rsurface.rtlight);
2221 for (i = 0;i < 8;i++)
2222 Matrix4x4_Transform(matrix, bboxpoints[i], vertex3f + i*3);
2223 GL_ColorMask(1,1,1,1);
2224 GL_DepthMask(false);
2225 GL_DepthRange(0, 1);
2226 GL_PolygonOffset(0, 0);
2228 GL_DepthFunc(GL_GREATER);
2229 GL_CullFace(r_refdef.view.cullface_back);
2230 R_Mesh_PrepareVertices_Position_Arrays(8, vertex3f);
2231 R_Mesh_Draw(0, 8, 0, 12, NULL, NULL, 0, bboxelements, NULL, 0);
2234 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
2236 R_Shadow_RenderMode_Reset();
2237 GL_BlendFunc(GL_ONE, GL_ONE);
2238 GL_DepthRange(0, 1);
2239 GL_DepthTest(r_showshadowvolumes.integer < 2);
2240 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
2241 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2242 GL_CullFace(GL_NONE);
2243 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
2246 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
2248 R_Shadow_RenderMode_Reset();
2249 GL_BlendFunc(GL_ONE, GL_ONE);
2250 GL_DepthRange(0, 1);
2251 GL_DepthTest(r_showlighting.integer < 2);
2252 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2254 GL_DepthFunc(GL_EQUAL);
2255 R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2256 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2259 void R_Shadow_RenderMode_End(void)
2261 R_Shadow_RenderMode_Reset();
2262 R_Shadow_RenderMode_ActiveLight(NULL);
2264 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2265 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2268 int bboxedges[12][2] =
2287 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2289 int i, ix1, iy1, ix2, iy2;
2290 float x1, y1, x2, y2;
2292 float vertex[20][3];
2301 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2302 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2303 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2304 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2306 if (!r_shadow_scissor.integer)
2309 // if view is inside the light box, just say yes it's visible
2310 if (BoxesOverlap(r_refdef.view.origin, r_refdef.view.origin, mins, maxs))
2313 x1 = y1 = x2 = y2 = 0;
2315 // transform all corners that are infront of the nearclip plane
2316 VectorNegate(r_refdef.view.frustum[4].normal, plane4f);
2317 plane4f[3] = r_refdef.view.frustum[4].dist;
2319 for (i = 0;i < 8;i++)
2321 Vector4Set(corner[i], (i & 1) ? maxs[0] : mins[0], (i & 2) ? maxs[1] : mins[1], (i & 4) ? maxs[2] : mins[2], 1);
2322 dist[i] = DotProduct4(corner[i], plane4f);
2323 sign[i] = dist[i] > 0;
2326 VectorCopy(corner[i], vertex[numvertices]);
2330 // if some points are behind the nearclip, add clipped edge points to make
2331 // sure that the scissor boundary is complete
2332 if (numvertices > 0 && numvertices < 8)
2334 // add clipped edge points
2335 for (i = 0;i < 12;i++)
2337 j = bboxedges[i][0];
2338 k = bboxedges[i][1];
2339 if (sign[j] != sign[k])
2341 f = dist[j] / (dist[j] - dist[k]);
2342 VectorLerp(corner[j], f, corner[k], vertex[numvertices]);
2348 // if we have no points to check, the light is behind the view plane
2352 // if we have some points to transform, check what screen area is covered
2353 x1 = y1 = x2 = y2 = 0;
2355 //Con_Printf("%i vertices to transform...\n", numvertices);
2356 for (i = 0;i < numvertices;i++)
2358 VectorCopy(vertex[i], v);
2359 R_Viewport_TransformToScreen(&r_refdef.view.viewport, v, v2);
2360 //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]);
2363 if (x1 > v2[0]) x1 = v2[0];
2364 if (x2 < v2[0]) x2 = v2[0];
2365 if (y1 > v2[1]) y1 = v2[1];
2366 if (y2 < v2[1]) y2 = v2[1];
2375 // now convert the scissor rectangle to integer screen coordinates
2376 ix1 = (int)(x1 - 1.0f);
2377 //iy1 = vid.height - (int)(y2 - 1.0f);
2378 //iy1 = r_refdef.view.viewport.width + 2 * r_refdef.view.viewport.x - (int)(y2 - 1.0f);
2379 iy1 = (int)(y1 - 1.0f);
2380 ix2 = (int)(x2 + 1.0f);
2381 //iy2 = vid.height - (int)(y1 + 1.0f);
2382 //iy2 = r_refdef.view.viewport.height + 2 * r_refdef.view.viewport.y - (int)(y1 + 1.0f);
2383 iy2 = (int)(y2 + 1.0f);
2384 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
2386 // clamp it to the screen
2387 if (ix1 < r_refdef.view.viewport.x) ix1 = r_refdef.view.viewport.x;
2388 if (iy1 < r_refdef.view.viewport.y) iy1 = r_refdef.view.viewport.y;
2389 if (ix2 > r_refdef.view.viewport.x + r_refdef.view.viewport.width) ix2 = r_refdef.view.viewport.x + r_refdef.view.viewport.width;
2390 if (iy2 > r_refdef.view.viewport.y + r_refdef.view.viewport.height) iy2 = r_refdef.view.viewport.y + r_refdef.view.viewport.height;
2392 // if it is inside out, it's not visible
2393 if (ix2 <= ix1 || iy2 <= iy1)
2396 // the light area is visible, set up the scissor rectangle
2397 r_shadow_lightscissor[0] = ix1;
2398 r_shadow_lightscissor[1] = iy1;
2399 r_shadow_lightscissor[2] = ix2 - ix1;
2400 r_shadow_lightscissor[3] = iy2 - iy1;
2402 // D3D Y coordinate is top to bottom, OpenGL is bottom to top, fix the D3D one
2403 switch(vid.renderpath)
2405 case RENDERPATH_D3D9:
2406 case RENDERPATH_D3D10:
2407 case RENDERPATH_D3D11:
2408 r_shadow_lightscissor[1] = vid.height - r_shadow_lightscissor[1] - r_shadow_lightscissor[3];
2410 case RENDERPATH_GL11:
2411 case RENDERPATH_GL13:
2412 case RENDERPATH_GL20:
2413 case RENDERPATH_CGGL:
2417 r_refdef.stats.lights_scissored++;
2421 VorteX: originally written by divVerent, that code is broken on ATI
2423 if (!r_shadow_scissor.integer)
2425 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2426 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2427 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2428 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2431 if(R_ScissorForBBox(mins, maxs, r_shadow_lightscissor))
2433 if(r_shadow_lightscissor[0] != r_refdef.view.viewport.x
2434 || r_shadow_lightscissor[1] != r_refdef.view.viewport.y
2435 || r_shadow_lightscissor[2] != r_refdef.view.viewport.width
2436 || r_shadow_lightscissor[3] != r_refdef.view.viewport.height)
2437 r_refdef.stats.lights_scissored++;
2441 return true; // invisible
2445 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, const float *diffusecolor, const float *ambientcolor)
2448 const float *vertex3f;
2449 const float *normal3f;
2451 float dist, dot, distintensity, shadeintensity, v[3], n[3];
2452 switch (r_shadow_rendermode)
2454 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2455 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2456 if (VectorLength2(diffusecolor) > 0)
2458 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)
2460 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2461 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2462 if ((dot = DotProduct(n, v)) < 0)
2464 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2465 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
2468 VectorCopy(ambientcolor, color4f);
2469 if (r_refdef.fogenabled)
2472 f = RSurf_FogVertex(vertex3f);
2473 VectorScale(color4f, f, color4f);
2480 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.array_passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
2482 VectorCopy(ambientcolor, color4f);
2483 if (r_refdef.fogenabled)
2486 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2487 f = RSurf_FogVertex(vertex3f);
2488 VectorScale(color4f + 4*i, f, color4f);
2494 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2495 if (VectorLength2(diffusecolor) > 0)
2497 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)
2499 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2500 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2502 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2503 if ((dot = DotProduct(n, v)) < 0)
2505 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2506 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2507 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2508 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2512 color4f[0] = ambientcolor[0] * distintensity;
2513 color4f[1] = ambientcolor[1] * distintensity;
2514 color4f[2] = ambientcolor[2] * distintensity;
2516 if (r_refdef.fogenabled)
2519 f = RSurf_FogVertex(vertex3f);
2520 VectorScale(color4f, f, color4f);
2524 VectorClear(color4f);
2530 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.array_passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
2532 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2533 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2535 color4f[0] = ambientcolor[0] * distintensity;
2536 color4f[1] = ambientcolor[1] * distintensity;
2537 color4f[2] = ambientcolor[2] * distintensity;
2538 if (r_refdef.fogenabled)
2541 f = RSurf_FogVertex(vertex3f);
2542 VectorScale(color4f, f, color4f);
2546 VectorClear(color4f);
2551 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2552 if (VectorLength2(diffusecolor) > 0)
2554 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)
2556 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2557 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2559 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2560 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2561 if ((dot = DotProduct(n, v)) < 0)
2563 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2564 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2565 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2566 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2570 color4f[0] = ambientcolor[0] * distintensity;
2571 color4f[1] = ambientcolor[1] * distintensity;
2572 color4f[2] = ambientcolor[2] * distintensity;
2574 if (r_refdef.fogenabled)
2577 f = RSurf_FogVertex(vertex3f);
2578 VectorScale(color4f, f, color4f);
2582 VectorClear(color4f);
2588 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.array_passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
2590 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2591 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2593 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2594 color4f[0] = ambientcolor[0] * distintensity;
2595 color4f[1] = ambientcolor[1] * distintensity;
2596 color4f[2] = ambientcolor[2] * distintensity;
2597 if (r_refdef.fogenabled)
2600 f = RSurf_FogVertex(vertex3f);
2601 VectorScale(color4f, f, color4f);
2605 VectorClear(color4f);
2615 static void R_Shadow_RenderLighting_VisibleLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
2617 // used to display how many times a surface is lit for level design purposes
2618 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
2619 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
2623 static void R_Shadow_RenderLighting_Light_GLSL(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale, float specularscale)
2625 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2626 R_SetupShader_Surface(lightcolor, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT, texturenumsurfaces, texturesurfacelist, NULL);
2627 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2628 GL_DepthFunc(GL_EQUAL);
2630 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2631 GL_DepthFunc(GL_LEQUAL);
2634 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
2641 int newnumtriangles;
2645 int maxtriangles = 4096;
2646 static int newelements[4096*3];
2647 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, diffusecolor2, ambientcolor2);
2648 for (renders = 0;renders < 4;renders++)
2653 newnumtriangles = 0;
2655 // due to low fillrate on the cards this vertex lighting path is
2656 // designed for, we manually cull all triangles that do not
2657 // contain a lit vertex
2658 // this builds batches of triangles from multiple surfaces and
2659 // renders them at once
2660 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
2662 if (VectorLength2(rsurface.array_passcolor4f + e[0] * 4) + VectorLength2(rsurface.array_passcolor4f + e[1] * 4) + VectorLength2(rsurface.array_passcolor4f + e[2] * 4) >= 0.01)
2664 if (newnumtriangles)
2666 newfirstvertex = min(newfirstvertex, e[0]);
2667 newlastvertex = max(newlastvertex, e[0]);
2671 newfirstvertex = e[0];
2672 newlastvertex = e[0];
2674 newfirstvertex = min(newfirstvertex, e[1]);
2675 newlastvertex = max(newlastvertex, e[1]);
2676 newfirstvertex = min(newfirstvertex, e[2]);
2677 newlastvertex = max(newlastvertex, e[2]);
2683 if (newnumtriangles >= maxtriangles)
2685 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
2686 newnumtriangles = 0;
2692 if (newnumtriangles >= 1)
2694 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
2697 // if we couldn't find any lit triangles, exit early
2700 // now reduce the intensity for the next overbright pass
2701 // we have to clamp to 0 here incase the drivers have improper
2702 // handling of negative colors
2703 // (some old drivers even have improper handling of >1 color)
2705 for (i = 0, c = rsurface.array_passcolor4f + 4 * firstvertex;i < numvertices;i++, c += 4)
2707 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
2709 c[0] = max(0, c[0] - 1);
2710 c[1] = max(0, c[1] - 1);
2711 c[2] = max(0, c[2] - 1);
2723 static void R_Shadow_RenderLighting_Light_Vertex(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale)
2725 // OpenGL 1.1 path (anything)
2726 float ambientcolorbase[3], diffusecolorbase[3];
2727 float ambientcolorpants[3], diffusecolorpants[3];
2728 float ambientcolorshirt[3], diffusecolorshirt[3];
2729 const float *surfacecolor = rsurface.texture->dlightcolor;
2730 const float *surfacepants = rsurface.colormap_pantscolor;
2731 const float *surfaceshirt = rsurface.colormap_shirtcolor;
2732 rtexture_t *basetexture = rsurface.texture->basetexture;
2733 rtexture_t *pantstexture = rsurface.texture->pantstexture;
2734 rtexture_t *shirttexture = rsurface.texture->shirttexture;
2735 qboolean dopants = pantstexture && VectorLength2(surfacepants) >= (1.0f / 1048576.0f);
2736 qboolean doshirt = shirttexture && VectorLength2(surfaceshirt) >= (1.0f / 1048576.0f);
2737 ambientscale *= 2 * r_refdef.view.colorscale;
2738 diffusescale *= 2 * r_refdef.view.colorscale;
2739 ambientcolorbase[0] = lightcolor[0] * ambientscale * surfacecolor[0];ambientcolorbase[1] = lightcolor[1] * ambientscale * surfacecolor[1];ambientcolorbase[2] = lightcolor[2] * ambientscale * surfacecolor[2];
2740 diffusecolorbase[0] = lightcolor[0] * diffusescale * surfacecolor[0];diffusecolorbase[1] = lightcolor[1] * diffusescale * surfacecolor[1];diffusecolorbase[2] = lightcolor[2] * diffusescale * surfacecolor[2];
2741 ambientcolorpants[0] = ambientcolorbase[0] * surfacepants[0];ambientcolorpants[1] = ambientcolorbase[1] * surfacepants[1];ambientcolorpants[2] = ambientcolorbase[2] * surfacepants[2];
2742 diffusecolorpants[0] = diffusecolorbase[0] * surfacepants[0];diffusecolorpants[1] = diffusecolorbase[1] * surfacepants[1];diffusecolorpants[2] = diffusecolorbase[2] * surfacepants[2];
2743 ambientcolorshirt[0] = ambientcolorbase[0] * surfaceshirt[0];ambientcolorshirt[1] = ambientcolorbase[1] * surfaceshirt[1];ambientcolorshirt[2] = ambientcolorbase[2] * surfaceshirt[2];
2744 diffusecolorshirt[0] = diffusecolorbase[0] * surfaceshirt[0];diffusecolorshirt[1] = diffusecolorbase[1] * surfaceshirt[1];diffusecolorshirt[2] = diffusecolorbase[2] * surfaceshirt[2];
2745 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | (diffusescale > 0 ? BATCHNEED_ARRAY_NORMAL : 0) | BATCHNEED_ARRAY_TEXCOORD, texturenumsurfaces, texturesurfacelist);
2746 R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
2747 R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.array_passcolor4f, 0, 0);
2748 R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
2749 R_Mesh_TexBind(0, basetexture);
2750 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
2751 R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
2752 switch(r_shadow_rendermode)
2754 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2755 R_Mesh_TexBind(1, r_shadow_attenuation3dtexture);
2756 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
2757 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
2758 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
2760 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2761 R_Mesh_TexBind(2, r_shadow_attenuation2dtexture);
2762 R_Mesh_TexMatrix(2, &rsurface.entitytoattenuationz);
2763 R_Mesh_TexCombine(2, GL_MODULATE, GL_MODULATE, 1, 1);
2764 R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
2766 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2767 R_Mesh_TexBind(1, r_shadow_attenuation2dtexture);
2768 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
2769 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
2770 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
2772 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2777 //R_Mesh_TexBind(0, basetexture);
2778 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorbase, ambientcolorbase);
2781 R_Mesh_TexBind(0, pantstexture);
2782 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorpants, ambientcolorpants);
2786 R_Mesh_TexBind(0, shirttexture);
2787 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorshirt, ambientcolorshirt);
2791 extern cvar_t gl_lightmaps;
2792 void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
2794 float ambientscale, diffusescale, specularscale;
2796 float lightcolor[3];
2797 VectorCopy(rsurface.rtlight->currentcolor, lightcolor);
2798 ambientscale = rsurface.rtlight->ambientscale;
2799 diffusescale = rsurface.rtlight->diffusescale;
2800 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
2801 if (!r_shadow_usenormalmap.integer)
2803 ambientscale += 1.0f * diffusescale;
2807 if ((ambientscale + diffusescale) * VectorLength2(lightcolor) + specularscale * VectorLength2(lightcolor) < (1.0f / 1048576.0f))
2809 negated = (lightcolor[0] + lightcolor[1] + lightcolor[2] < 0) && vid.support.ext_blend_subtract;
2812 VectorNegate(lightcolor, lightcolor);
2813 switch(vid.renderpath)
2815 case RENDERPATH_GL11:
2816 case RENDERPATH_GL13:
2817 case RENDERPATH_GL20:
2818 case RENDERPATH_CGGL:
2819 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
2821 case RENDERPATH_D3D9:
2823 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_SUBTRACT);
2826 case RENDERPATH_D3D10:
2827 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2829 case RENDERPATH_D3D11:
2830 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2834 RSurf_SetupDepthAndCulling();
2835 switch (r_shadow_rendermode)
2837 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2838 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2839 R_Shadow_RenderLighting_VisibleLighting(texturenumsurfaces, texturesurfacelist);
2841 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2842 R_Shadow_RenderLighting_Light_GLSL(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale, specularscale);
2844 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2845 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2846 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2847 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2848 R_Shadow_RenderLighting_Light_Vertex(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale);
2851 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2856 switch(vid.renderpath)
2858 case RENDERPATH_GL11:
2859 case RENDERPATH_GL13:
2860 case RENDERPATH_GL20:
2861 case RENDERPATH_CGGL:
2862 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
2864 case RENDERPATH_D3D9:
2866 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_ADD);
2869 case RENDERPATH_D3D10:
2870 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2872 case RENDERPATH_D3D11:
2873 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2879 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)
2881 matrix4x4_t tempmatrix = *matrix;
2882 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
2884 // if this light has been compiled before, free the associated data
2885 R_RTLight_Uncompile(rtlight);
2887 // clear it completely to avoid any lingering data
2888 memset(rtlight, 0, sizeof(*rtlight));
2890 // copy the properties
2891 rtlight->matrix_lighttoworld = tempmatrix;
2892 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
2893 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
2894 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
2895 VectorCopy(color, rtlight->color);
2896 rtlight->cubemapname[0] = 0;
2897 if (cubemapname && cubemapname[0])
2898 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
2899 rtlight->shadow = shadow;
2900 rtlight->corona = corona;
2901 rtlight->style = style;
2902 rtlight->isstatic = isstatic;
2903 rtlight->coronasizescale = coronasizescale;
2904 rtlight->ambientscale = ambientscale;
2905 rtlight->diffusescale = diffusescale;
2906 rtlight->specularscale = specularscale;
2907 rtlight->flags = flags;
2909 // compute derived data
2910 //rtlight->cullradius = rtlight->radius;
2911 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2912 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2913 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2914 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2915 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2916 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2917 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2920 // compiles rtlight geometry
2921 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2922 void R_RTLight_Compile(rtlight_t *rtlight)
2925 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
2926 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
2927 entity_render_t *ent = r_refdef.scene.worldentity;
2928 dp_model_t *model = r_refdef.scene.worldmodel;
2929 unsigned char *data;
2932 // compile the light
2933 rtlight->compiled = true;
2934 rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
2935 rtlight->static_numleafs = 0;
2936 rtlight->static_numleafpvsbytes = 0;
2937 rtlight->static_leaflist = NULL;
2938 rtlight->static_leafpvs = NULL;
2939 rtlight->static_numsurfaces = 0;
2940 rtlight->static_surfacelist = NULL;
2941 rtlight->static_shadowmap_receivers = 0x3F;
2942 rtlight->static_shadowmap_casters = 0x3F;
2943 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2944 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2945 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2946 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2947 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2948 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2950 if (model && model->GetLightInfo)
2952 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
2953 r_shadow_compilingrtlight = rtlight;
2954 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);
2955 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2956 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
2957 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
2958 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
2959 rtlight->static_numsurfaces = numsurfaces;
2960 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
2961 rtlight->static_numleafs = numleafs;
2962 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
2963 rtlight->static_numleafpvsbytes = numleafpvsbytes;
2964 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
2965 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
2966 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
2967 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
2968 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
2969 if (rtlight->static_numsurfaces)
2970 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
2971 if (rtlight->static_numleafs)
2972 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
2973 if (rtlight->static_numleafpvsbytes)
2974 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
2975 if (rtlight->static_numshadowtrispvsbytes)
2976 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
2977 if (rtlight->static_numlighttrispvsbytes)
2978 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
2979 switch (rtlight->shadowmode)
2981 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2982 if (model->CompileShadowMap && rtlight->shadow)
2983 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2986 if (model->CompileShadowVolume && rtlight->shadow)
2987 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2990 // now we're done compiling the rtlight
2991 r_shadow_compilingrtlight = NULL;
2995 // use smallest available cullradius - box radius or light radius
2996 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2997 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2999 shadowzpasstris = 0;
3000 if (rtlight->static_meshchain_shadow_zpass)
3001 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
3002 shadowzpasstris += mesh->numtriangles;
3004 shadowzfailtris = 0;
3005 if (rtlight->static_meshchain_shadow_zfail)
3006 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
3007 shadowzfailtris += mesh->numtriangles;
3010 if (rtlight->static_numlighttrispvsbytes)
3011 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3012 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3016 if (rtlight->static_numlighttrispvsbytes)
3017 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3018 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3021 if (developer_extra.integer)
3022 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);
3025 void R_RTLight_Uncompile(rtlight_t *rtlight)
3027 if (rtlight->compiled)
3029 if (rtlight->static_meshchain_shadow_zpass)
3030 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
3031 rtlight->static_meshchain_shadow_zpass = NULL;
3032 if (rtlight->static_meshchain_shadow_zfail)
3033 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
3034 rtlight->static_meshchain_shadow_zfail = NULL;
3035 if (rtlight->static_meshchain_shadow_shadowmap)
3036 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
3037 rtlight->static_meshchain_shadow_shadowmap = NULL;
3038 // these allocations are grouped
3039 if (rtlight->static_surfacelist)
3040 Mem_Free(rtlight->static_surfacelist);
3041 rtlight->static_numleafs = 0;
3042 rtlight->static_numleafpvsbytes = 0;
3043 rtlight->static_leaflist = NULL;
3044 rtlight->static_leafpvs = NULL;
3045 rtlight->static_numsurfaces = 0;
3046 rtlight->static_surfacelist = NULL;
3047 rtlight->static_numshadowtrispvsbytes = 0;
3048 rtlight->static_shadowtrispvs = NULL;
3049 rtlight->static_numlighttrispvsbytes = 0;
3050 rtlight->static_lighttrispvs = NULL;
3051 rtlight->compiled = false;
3055 void R_Shadow_UncompileWorldLights(void)
3059 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3060 for (lightindex = 0;lightindex < range;lightindex++)
3062 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3065 R_RTLight_Uncompile(&light->rtlight);
3069 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3073 // reset the count of frustum planes
3074 // see rtlight->cached_frustumplanes definition for how much this array
3076 rtlight->cached_numfrustumplanes = 0;
3078 // haven't implemented a culling path for ortho rendering
3079 if (!r_refdef.view.useperspective)
3081 // check if the light is on screen and copy the 4 planes if it is
3082 for (i = 0;i < 4;i++)
3083 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3086 for (i = 0;i < 4;i++)
3087 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3092 // generate a deformed frustum that includes the light origin, this is
3093 // used to cull shadow casting surfaces that can not possibly cast a
3094 // shadow onto the visible light-receiving surfaces, which can be a
3097 // if the light origin is onscreen the result will be 4 planes exactly
3098 // if the light origin is offscreen on only one axis the result will
3099 // be exactly 5 planes (split-side case)
3100 // if the light origin is offscreen on two axes the result will be
3101 // exactly 4 planes (stretched corner case)
3102 for (i = 0;i < 4;i++)
3104 // quickly reject standard frustum planes that put the light
3105 // origin outside the frustum
3106 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3109 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3111 // if all the standard frustum planes were accepted, the light is onscreen
3112 // otherwise we need to generate some more planes below...
3113 if (rtlight->cached_numfrustumplanes < 4)
3115 // at least one of the stock frustum planes failed, so we need to
3116 // create one or two custom planes to enclose the light origin
3117 for (i = 0;i < 4;i++)
3119 // create a plane using the view origin and light origin, and a
3120 // single point from the frustum corner set
3121 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3122 VectorNormalize(plane.normal);
3123 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3124 // see if this plane is backwards and flip it if so
3125 for (j = 0;j < 4;j++)
3126 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3130 VectorNegate(plane.normal, plane.normal);
3132 // flipped plane, test again to see if it is now valid
3133 for (j = 0;j < 4;j++)
3134 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3136 // if the plane is still not valid, then it is dividing the
3137 // frustum and has to be rejected
3141 // we have created a valid plane, compute extra info
3142 PlaneClassify(&plane);
3144 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3146 // if we've found 5 frustum planes then we have constructed a
3147 // proper split-side case and do not need to keep searching for
3148 // planes to enclose the light origin
3149 if (rtlight->cached_numfrustumplanes == 5)
3157 for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
3159 plane = rtlight->cached_frustumplanes[i];
3160 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));
3165 // now add the light-space box planes if the light box is rotated, as any
3166 // caster outside the oriented light box is irrelevant (even if it passed
3167 // the worldspace light box, which is axial)
3168 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3170 for (i = 0;i < 6;i++)
3174 v[i >> 1] = (i & 1) ? -1 : 1;
3175 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3176 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3177 plane.dist = VectorNormalizeLength(plane.normal);
3178 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3179 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3185 // add the world-space reduced box planes
3186 for (i = 0;i < 6;i++)
3188 VectorClear(plane.normal);
3189 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3190 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
3191 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3200 // reduce all plane distances to tightly fit the rtlight cull box, which
3202 VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3203 VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3204 VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3205 VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3206 VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3207 VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3208 VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3209 VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3210 oldnum = rtlight->cached_numfrustumplanes;
3211 rtlight->cached_numfrustumplanes = 0;
3212 for (j = 0;j < oldnum;j++)
3214 // find the nearest point on the box to this plane
3215 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
3216 for (i = 1;i < 8;i++)
3218 dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
3219 if (bestdist > dist)
3222 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);
3223 // if the nearest point is near or behind the plane, we want this
3224 // plane, otherwise the plane is useless as it won't cull anything
3225 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
3227 PlaneClassify(&rtlight->cached_frustumplanes[j]);
3228 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
3235 void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
3239 RSurf_ActiveWorldEntity();
3241 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3244 GL_CullFace(GL_NONE);
3245 mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3246 for (;mesh;mesh = mesh->next)
3248 if (!mesh->sidetotals[r_shadow_shadowmapside])
3250 r_refdef.stats.lights_shadowtriangles += mesh->sidetotals[r_shadow_shadowmapside];
3251 R_Mesh_PrepareVertices_Position(mesh->numverts, mesh->vertexposition, mesh->vertexpositionbuffer);
3252 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);
3256 else if (r_refdef.scene.worldentity->model)
3257 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);
3259 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3262 void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3264 qboolean zpass = false;
3267 int surfacelistindex;
3268 msurface_t *surface;
3270 RSurf_ActiveWorldEntity();
3272 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3275 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
3277 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
3278 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
3280 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
3281 for (;mesh;mesh = mesh->next)
3283 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
3284 R_Mesh_PrepareVertices_Position(mesh->numverts, mesh->vertexposition, mesh->vertexpositionbuffer);
3285 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
3287 // increment stencil if frontface is infront of depthbuffer
3288 GL_CullFace(r_refdef.view.cullface_back);
3289 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
3290 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);
3291 // decrement stencil if backface is infront of depthbuffer
3292 GL_CullFace(r_refdef.view.cullface_front);
3293 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
3295 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
3297 // decrement stencil if backface is behind depthbuffer
3298 GL_CullFace(r_refdef.view.cullface_front);
3299 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
3300 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);
3301 // increment stencil if frontface is behind depthbuffer
3302 GL_CullFace(r_refdef.view.cullface_back);
3303 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
3305 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);
3309 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh)
3311 // use the shadow trispvs calculated earlier by GetLightInfo to cull world triangles on this dynamic light
3312 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
3313 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
3315 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
3316 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
3317 if (CHECKPVSBIT(trispvs, t))
3318 shadowmarklist[numshadowmark++] = t;
3320 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);
3322 else if (numsurfaces)
3323 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);
3325 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3328 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3330 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3331 vec_t relativeshadowradius;
3332 RSurf_ActiveModelEntity(ent, false, false, false);
3333 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3334 // we need to re-init the shader for each entity because the matrix changed
3335 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3336 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3337 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3338 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3339 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3340 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3341 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3342 switch (r_shadow_rendermode)
3344 case R_SHADOW_RENDERMODE_SHADOWMAP2D:
3345 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
3348 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3351 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3354 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3356 // set up properties for rendering light onto this entity
3357 RSurf_ActiveModelEntity(ent, true, true, false);
3358 GL_AlphaTest(false);
3359 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3360 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3361 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3362 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3365 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
3367 if (!r_refdef.scene.worldmodel->DrawLight)
3370 // set up properties for rendering light onto this entity
3371 RSurf_ActiveWorldEntity();
3372 GL_AlphaTest(false);
3373 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3374 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3375 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3376 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3378 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
3380 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3383 void R_Shadow_DrawEntityLight(entity_render_t *ent)
3385 dp_model_t *model = ent->model;
3386 if (!model->DrawLight)
3389 R_Shadow_SetupEntityLight(ent);
3391 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3393 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3396 void R_Shadow_PrepareLight(rtlight_t *rtlight)
3400 int numleafs, numsurfaces;
3401 int *leaflist, *surfacelist;
3402 unsigned char *leafpvs;
3403 unsigned char *shadowtrispvs;
3404 unsigned char *lighttrispvs;
3405 //unsigned char *surfacesides;
3406 int numlightentities;
3407 int numlightentities_noselfshadow;
3408 int numshadowentities;
3409 int numshadowentities_noselfshadow;
3410 static entity_render_t *lightentities[MAX_EDICTS];
3411 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3412 static entity_render_t *shadowentities[MAX_EDICTS];
3413 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3416 rtlight->draw = false;
3418 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3419 // skip lights that are basically invisible (color 0 0 0)
3420 nolight = VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f);
3422 // loading is done before visibility checks because loading should happen
3423 // all at once at the start of a level, not when it stalls gameplay.
3424 // (especially important to benchmarks)
3426 if (rtlight->isstatic && !nolight && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
3428 if (rtlight->compiled)
3429 R_RTLight_Uncompile(rtlight);
3430 R_RTLight_Compile(rtlight);
3434 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
3436 // look up the light style value at this time
3437 f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3438 VectorScale(rtlight->color, f, rtlight->currentcolor);
3440 if (rtlight->selected)
3442 f = 2 + sin(realtime * M_PI * 4.0);
3443 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3447 // if lightstyle is currently off, don't draw the light
3448 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3451 // skip processing on corona-only lights
3455 // if the light box is offscreen, skip it
3456 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3459 VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
3460 VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
3462 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3464 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3466 // compiled light, world available and can receive realtime lighting
3467 // retrieve leaf information
3468 numleafs = rtlight->static_numleafs;
3469 leaflist = rtlight->static_leaflist;
3470 leafpvs = rtlight->static_leafpvs;
3471 numsurfaces = rtlight->static_numsurfaces;
3472 surfacelist = rtlight->static_surfacelist;
3473 //surfacesides = NULL;
3474 shadowtrispvs = rtlight->static_shadowtrispvs;
3475 lighttrispvs = rtlight->static_lighttrispvs;
3477 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3479 // dynamic light, world available and can receive realtime lighting
3480 // calculate lit surfaces and leafs
3481 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);
3482 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3483 leaflist = r_shadow_buffer_leaflist;
3484 leafpvs = r_shadow_buffer_leafpvs;
3485 surfacelist = r_shadow_buffer_surfacelist;
3486 //surfacesides = r_shadow_buffer_surfacesides;
3487 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3488 lighttrispvs = r_shadow_buffer_lighttrispvs;
3489 // if the reduced leaf bounds are offscreen, skip it
3490 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3501 //surfacesides = NULL;
3502 shadowtrispvs = NULL;
3503 lighttrispvs = NULL;
3505 // check if light is illuminating any visible leafs
3508 for (i = 0;i < numleafs;i++)
3509 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3515 // make a list of lit entities and shadow casting entities
3516 numlightentities = 0;
3517 numlightentities_noselfshadow = 0;
3518 numshadowentities = 0;
3519 numshadowentities_noselfshadow = 0;
3521 // add dynamic entities that are lit by the light
3522 for (i = 0;i < r_refdef.scene.numentities;i++)
3525 entity_render_t *ent = r_refdef.scene.entities[i];
3527 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3529 // skip the object entirely if it is not within the valid
3530 // shadow-casting region (which includes the lit region)
3531 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
3533 if (!(model = ent->model))
3535 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
3537 // this entity wants to receive light, is visible, and is
3538 // inside the light box
3539 // TODO: check if the surfaces in the model can receive light
3540 // so now check if it's 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 if (ent->flags & RENDER_NOSELFSHADOW)
3544 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
3546 lightentities[numlightentities++] = ent;
3547 // since it is lit, it probably also casts a shadow...
3548 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3549 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3550 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3552 // note: exterior models without the RENDER_NOSELFSHADOW
3553 // flag still create a RENDER_NOSELFSHADOW shadow but
3554 // are lit normally, this means that they are
3555 // self-shadowing but do not shadow other
3556 // RENDER_NOSELFSHADOW entities such as the gun
3557 // (very weird, but keeps the player shadow off the gun)
3558 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3559 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3561 shadowentities[numshadowentities++] = ent;
3564 else if (ent->flags & RENDER_SHADOW)
3566 // this entity is not receiving light, but may still need to
3568 // TODO: check if the surfaces in the model can cast shadow
3569 // now check if it is in a leaf seen by the light
3570 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))
3572 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3573 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3574 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3576 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3577 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3579 shadowentities[numshadowentities++] = ent;
3584 // return if there's nothing at all to light
3585 if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
3588 // count this light in the r_speeds
3589 r_refdef.stats.lights++;
3591 // flag it as worth drawing later
3592 rtlight->draw = true;
3594 // cache all the animated entities that cast a shadow but are not visible
3595 for (i = 0;i < numshadowentities;i++)
3596 if (!shadowentities[i]->animcache_vertex3f)
3597 R_AnimCache_GetEntity(shadowentities[i], false, false);
3598 for (i = 0;i < numshadowentities_noselfshadow;i++)
3599 if (!shadowentities_noselfshadow[i]->animcache_vertex3f)
3600 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
3602 // allocate some temporary memory for rendering this light later in the frame
3603 // reusable buffers need to be copied, static data can be used as-is
3604 rtlight->cached_numlightentities = numlightentities;
3605 rtlight->cached_numlightentities_noselfshadow = numlightentities_noselfshadow;
3606 rtlight->cached_numshadowentities = numshadowentities;
3607 rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
3608 rtlight->cached_numsurfaces = numsurfaces;
3609 rtlight->cached_lightentities = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
3610 rtlight->cached_lightentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
3611 rtlight->cached_shadowentities = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
3612 rtlight->cached_shadowentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
3613 if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
3615 int numshadowtrispvsbytes = (((r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles) + 7) >> 3);
3616 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
3617 rtlight->cached_shadowtrispvs = (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
3618 rtlight->cached_lighttrispvs = (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
3619 rtlight->cached_surfacelist = (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
3623 // compiled light data
3624 rtlight->cached_shadowtrispvs = shadowtrispvs;
3625 rtlight->cached_lighttrispvs = lighttrispvs;
3626 rtlight->cached_surfacelist = surfacelist;
3630 void R_Shadow_DrawLight(rtlight_t *rtlight)
3634 unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
3635 int numlightentities;
3636 int numlightentities_noselfshadow;
3637 int numshadowentities;
3638 int numshadowentities_noselfshadow;
3639 entity_render_t **lightentities;
3640 entity_render_t **lightentities_noselfshadow;
3641 entity_render_t **shadowentities;
3642 entity_render_t **shadowentities_noselfshadow;
3644 static unsigned char entitysides[MAX_EDICTS];
3645 static unsigned char entitysides_noselfshadow[MAX_EDICTS];
3646 vec3_t nearestpoint;
3648 qboolean castshadows;
3651 // check if we cached this light this frame (meaning it is worth drawing)
3655 // if R_FrameData_Store ran out of space we skip anything dependent on it
3656 if (r_framedata_failed)
3659 numlightentities = rtlight->cached_numlightentities;
3660 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
3661 numshadowentities = rtlight->cached_numshadowentities;
3662 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
3663 numsurfaces = rtlight->cached_numsurfaces;
3664 lightentities = rtlight->cached_lightentities;
3665 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
3666 shadowentities = rtlight->cached_shadowentities;
3667 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
3668 shadowtrispvs = rtlight->cached_shadowtrispvs;
3669 lighttrispvs = rtlight->cached_lighttrispvs;
3670 surfacelist = rtlight->cached_surfacelist;
3672 // set up a scissor rectangle for this light
3673 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3676 // don't let sound skip if going slow
3677 if (r_refdef.scene.extraupdate)
3680 // make this the active rtlight for rendering purposes
3681 R_Shadow_RenderMode_ActiveLight(rtlight);
3683 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
3685 // optionally draw visible shape of the shadow volumes
3686 // for performance analysis by level designers
3687 R_Shadow_RenderMode_VisibleShadowVolumes();
3689 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
3690 for (i = 0;i < numshadowentities;i++)
3691 R_Shadow_DrawEntityShadow(shadowentities[i]);
3692 for (i = 0;i < numshadowentities_noselfshadow;i++)
3693 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3694 R_Shadow_RenderMode_VisibleLighting(false, false);
3697 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
3699 // optionally draw the illuminated areas
3700 // for performance analysis by level designers
3701 R_Shadow_RenderMode_VisibleLighting(false, false);
3703 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3704 for (i = 0;i < numlightentities;i++)
3705 R_Shadow_DrawEntityLight(lightentities[i]);
3706 for (i = 0;i < numlightentities_noselfshadow;i++)
3707 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3710 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
3712 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
3713 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
3714 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
3715 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
3717 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance/rtlight->radius));
3718 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
3719 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
3721 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
3727 int receivermask = 0;
3728 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
3729 Matrix4x4_Abs(&radiustolight);
3731 r_shadow_shadowmaplod = 0;
3732 for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
3733 if ((r_shadow_shadowmapmaxsize >> i) > lodlinear)
3734 r_shadow_shadowmaplod = i;
3736 size = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
3738 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
3740 surfacesides = NULL;
3743 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3745 castermask = rtlight->static_shadowmap_casters;
3746 receivermask = rtlight->static_shadowmap_receivers;
3750 surfacesides = r_shadow_buffer_surfacesides;
3751 for(i = 0;i < numsurfaces;i++)
3753 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
3754 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3755 castermask |= surfacesides[i];
3756 receivermask |= surfacesides[i];
3760 if (receivermask < 0x3F)
3762 for (i = 0;i < numlightentities;i++)
3763 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3764 if (receivermask < 0x3F)
3765 for(i = 0; i < numlightentities_noselfshadow;i++)
3766 receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3769 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
3773 for (i = 0;i < numshadowentities;i++)
3774 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3775 for (i = 0;i < numshadowentities_noselfshadow;i++)
3776 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3779 //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
3781 // render shadow casters into 6 sided depth texture
3782 for (side = 0;side < 6;side++) if (receivermask & (1 << side))
3784 R_Shadow_RenderMode_ShadowMap(side, receivermask, size);
3785 if (! (castermask & (1 << side))) continue;
3787 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
3788 for (i = 0;i < numshadowentities;i++) if (entitysides[i] & (1 << side))
3789 R_Shadow_DrawEntityShadow(shadowentities[i]);
3792 if (numlightentities_noselfshadow)
3794 // render lighting using the depth texture as shadowmap
3795 // draw lighting in the unmasked areas
3796 R_Shadow_RenderMode_Lighting(false, false, true);
3797 for (i = 0;i < numlightentities_noselfshadow;i++)
3798 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3801 // render shadow casters into 6 sided depth texture
3802 if (numshadowentities_noselfshadow)
3804 for (side = 0;side < 6;side++) if ((receivermask & castermask) & (1 << side))
3806 R_Shadow_RenderMode_ShadowMap(side, 0, size);
3807 for (i = 0;i < numshadowentities_noselfshadow;i++) if (entitysides_noselfshadow[i] & (1 << side))
3808 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3812 // render lighting using the depth texture as shadowmap
3813 // draw lighting in the unmasked areas
3814 R_Shadow_RenderMode_Lighting(false, false, true);
3815 // draw lighting in the unmasked areas
3817 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3818 for (i = 0;i < numlightentities;i++)
3819 R_Shadow_DrawEntityLight(lightentities[i]);
3821 else if (castshadows && vid.stencil)
3823 // draw stencil shadow volumes to mask off pixels that are in shadow
3824 // so that they won't receive lighting
3825 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
3826 R_Shadow_ClearStencil();
3829 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
3830 for (i = 0;i < numshadowentities;i++)
3831 R_Shadow_DrawEntityShadow(shadowentities[i]);
3833 // draw lighting in the unmasked areas
3834 R_Shadow_RenderMode_Lighting(true, false, false);
3835 for (i = 0;i < numlightentities_noselfshadow;i++)
3836 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3838 for (i = 0;i < numshadowentities_noselfshadow;i++)
3839 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3841 // draw lighting in the unmasked areas
3842 R_Shadow_RenderMode_Lighting(true, false, false);
3844 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3845 for (i = 0;i < numlightentities;i++)
3846 R_Shadow_DrawEntityLight(lightentities[i]);
3850 // draw lighting in the unmasked areas
3851 R_Shadow_RenderMode_Lighting(false, false, false);
3853 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3854 for (i = 0;i < numlightentities;i++)
3855 R_Shadow_DrawEntityLight(lightentities[i]);
3856 for (i = 0;i < numlightentities_noselfshadow;i++)
3857 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3860 if (r_shadow_usingdeferredprepass)
3862 // when rendering deferred lighting, we simply rasterize the box
3863 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
3864 R_Shadow_RenderMode_DrawDeferredLight(false, true);
3865 else if (castshadows && vid.stencil)
3866 R_Shadow_RenderMode_DrawDeferredLight(true, false);
3868 R_Shadow_RenderMode_DrawDeferredLight(false, false);
3872 static void R_Shadow_FreeDeferred(void)
3874 R_Mesh_DestroyFramebufferObject(r_shadow_prepassgeometryfbo);
3875 r_shadow_prepassgeometryfbo = 0;
3877 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingfbo);
3878 r_shadow_prepasslightingfbo = 0;
3880 if (r_shadow_prepassgeometrydepthtexture)
3881 R_FreeTexture(r_shadow_prepassgeometrydepthtexture);
3882 r_shadow_prepassgeometrydepthtexture = NULL;
3884 if (r_shadow_prepassgeometrydepthcolortexture)
3885 R_FreeTexture(r_shadow_prepassgeometrydepthcolortexture);
3886 r_shadow_prepassgeometrydepthcolortexture = NULL;
3888 if (r_shadow_prepassgeometrynormalmaptexture)
3889 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
3890 r_shadow_prepassgeometrynormalmaptexture = NULL;
3892 if (r_shadow_prepasslightingdiffusetexture)
3893 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
3894 r_shadow_prepasslightingdiffusetexture = NULL;
3896 if (r_shadow_prepasslightingspeculartexture)
3897 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
3898 r_shadow_prepasslightingspeculartexture = NULL;
3901 void R_Shadow_DrawPrepass(void)
3909 entity_render_t *ent;
3910 float clearcolor[4];
3912 GL_AlphaTest(false);
3913 R_Mesh_ResetTextureState();
3915 GL_ColorMask(1,1,1,1);
3916 GL_BlendFunc(GL_ONE, GL_ZERO);
3919 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, r_shadow_prepassgeometrydepthcolortexture, NULL, NULL);
3920 Vector4Set(clearcolor, 0.5f,0.5f,0.5f,1.0f);
3921 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
3922 if (r_timereport_active)
3923 R_TimeReport("prepasscleargeom");
3925 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
3926 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
3927 if (r_timereport_active)
3928 R_TimeReport("prepassworld");
3930 for (i = 0;i < r_refdef.scene.numentities;i++)
3932 if (!r_refdef.viewcache.entityvisible[i])
3934 ent = r_refdef.scene.entities[i];
3935 if (ent->model && ent->model->DrawPrepass != NULL)
3936 ent->model->DrawPrepass(ent);
3939 if (r_timereport_active)
3940 R_TimeReport("prepassmodels");
3942 GL_DepthMask(false);
3943 GL_ColorMask(1,1,1,1);
3946 R_Mesh_SetRenderTargets(r_shadow_prepasslightingfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
3947 Vector4Set(clearcolor, 0, 0, 0, 0);
3948 GL_Clear(GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
3949 if (r_timereport_active)
3950 R_TimeReport("prepassclearlit");
3952 R_Shadow_RenderMode_Begin();
3954 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3955 if (r_shadow_debuglight.integer >= 0)
3957 lightindex = r_shadow_debuglight.integer;
3958 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3959 if (light && (light->flags & flag))
3960 R_Shadow_DrawLight(&light->rtlight);
3964 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3965 for (lightindex = 0;lightindex < range;lightindex++)
3967 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3968 if (light && (light->flags & flag))
3969 R_Shadow_DrawLight(&light->rtlight);
3972 if (r_refdef.scene.rtdlight)
3973 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
3974 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
3976 R_Mesh_ResetRenderTargets();
3978 R_Shadow_RenderMode_End();
3980 if (r_timereport_active)
3981 R_TimeReport("prepasslights");
3984 void R_Shadow_DrawLightSprites(void);
3985 void R_Shadow_PrepareLights(void)
3995 if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4) ||
3996 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
3997 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20) ||
3998 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
3999 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
4000 r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
4001 R_Shadow_FreeShadowMaps();
4003 r_shadow_usingshadowmaportho = false;
4005 switch (vid.renderpath)
4007 case RENDERPATH_GL20:
4008 case RENDERPATH_CGGL:
4009 case RENDERPATH_D3D9:
4010 case RENDERPATH_D3D10:
4011 case RENDERPATH_D3D11:
4012 if (!r_shadow_deferred.integer || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_STENCIL || !vid.support.ext_framebuffer_object || vid.maxdrawbuffers < 2)
4014 r_shadow_usingdeferredprepass = false;
4015 if (r_shadow_prepass_width)
4016 R_Shadow_FreeDeferred();
4017 r_shadow_prepass_width = r_shadow_prepass_height = 0;
4021 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
4023 R_Shadow_FreeDeferred();
4025 r_shadow_usingdeferredprepass = true;
4026 r_shadow_prepass_width = vid.width;
4027 r_shadow_prepass_height = vid.height;
4028 r_shadow_prepassgeometrydepthtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "prepassgeometrydepthmap", vid.width, vid.height, 24, false);
4029 switch (vid.renderpath)
4031 case RENDERPATH_D3D9:
4032 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);
4037 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);
4038 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);
4039 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);
4041 // set up the geometry pass fbo (depth + normalmap)
4042 r_shadow_prepassgeometryfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4043 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, r_shadow_prepassgeometrydepthcolortexture, NULL, NULL);
4044 // render depth into one texture and normalmap into the other
4045 if (qglDrawBuffersARB)
4047 qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);CHECKGLERROR
4048 qglReadBuffer(GL_NONE);CHECKGLERROR
4049 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4050 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4052 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4053 Cvar_SetValueQuick(&r_shadow_deferred, 0);
4054 r_shadow_usingdeferredprepass = false;
4058 // set up the lighting pass fbo (diffuse + specular)
4059 r_shadow_prepasslightingfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4060 R_Mesh_SetRenderTargets(r_shadow_prepasslightingfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4061 // render diffuse into one texture and specular into another,
4062 // with depth and normalmap bound as textures,
4063 // with depth bound as attachment as well
4064 if (qglDrawBuffersARB)
4066 qglDrawBuffersARB(2, r_shadow_prepasslightingdrawbuffers);CHECKGLERROR
4067 qglReadBuffer(GL_NONE);CHECKGLERROR
4068 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4069 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4071 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4072 Cvar_SetValueQuick(&r_shadow_deferred, 0);
4073 r_shadow_usingdeferredprepass = false;
4078 case RENDERPATH_GL13:
4079 case RENDERPATH_GL11:
4080 r_shadow_usingdeferredprepass = false;
4084 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);
4086 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4087 if (r_shadow_debuglight.integer >= 0)
4089 lightindex = r_shadow_debuglight.integer;
4090 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4091 if (light && (light->flags & flag))
4092 R_Shadow_PrepareLight(&light->rtlight);
4096 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4097 for (lightindex = 0;lightindex < range;lightindex++)
4099 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4100 if (light && (light->flags & flag))
4101 R_Shadow_PrepareLight(&light->rtlight);
4104 if (r_refdef.scene.rtdlight)
4106 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4107 R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
4109 else if(gl_flashblend.integer)
4111 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4113 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
4114 f = (rtlight->style >= 0 ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4115 VectorScale(rtlight->color, f, rtlight->currentcolor);
4119 if (r_editlights.integer)
4120 R_Shadow_DrawLightSprites();
4123 void R_Shadow_DrawLights(void)
4131 R_Shadow_RenderMode_Begin();
4133 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4134 if (r_shadow_debuglight.integer >= 0)
4136 lightindex = r_shadow_debuglight.integer;
4137 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4138 if (light && (light->flags & flag))
4139 R_Shadow_DrawLight(&light->rtlight);
4143 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4144 for (lightindex = 0;lightindex < range;lightindex++)
4146 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4147 if (light && (light->flags & flag))
4148 R_Shadow_DrawLight(&light->rtlight);
4151 if (r_refdef.scene.rtdlight)
4152 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4153 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4155 R_Shadow_RenderMode_End();
4158 extern const float r_screenvertex3f[12];
4159 extern void R_SetupView(qboolean allowwaterclippingplane);
4160 extern void R_ResetViewRendering3D(void);
4161 extern void R_ResetViewRendering2D(void);
4162 extern cvar_t r_shadows;
4163 extern cvar_t r_shadows_darken;
4164 extern cvar_t r_shadows_drawafterrtlighting;
4165 extern cvar_t r_shadows_castfrombmodels;
4166 extern cvar_t r_shadows_throwdistance;
4167 extern cvar_t r_shadows_throwdirection;
4168 extern cvar_t r_shadows_focus;
4169 extern cvar_t r_shadows_shadowmapscale;
4171 void R_Shadow_PrepareModelShadows(void)
4174 float scale, size, radius, dot1, dot2;
4175 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
4176 entity_render_t *ent;
4178 if (!r_refdef.scene.numentities)
4181 switch (r_shadow_shadowmode)
4183 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4184 if (r_shadows.integer >= 2)
4187 case R_SHADOW_SHADOWMODE_STENCIL:
4188 for (i = 0;i < r_refdef.scene.numentities;i++)
4190 ent = r_refdef.scene.entities[i];
4191 if (!ent->animcache_vertex3f && ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4192 R_AnimCache_GetEntity(ent, false, false);
4199 size = 2*r_shadow_shadowmapmaxsize;
4200 scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
4201 radius = 0.5f * size / scale;
4203 Math_atov(r_shadows_throwdirection.string, shadowdir);
4204 VectorNormalize(shadowdir);
4205 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4206 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4207 if (fabs(dot1) <= fabs(dot2))
4208 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4210 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4211 VectorNormalize(shadowforward);
4212 CrossProduct(shadowdir, shadowforward, shadowright);
4213 Math_atov(r_shadows_focus.string, shadowfocus);
4214 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4215 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4216 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4217 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4218 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4220 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4222 shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4223 shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4224 shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4225 shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4226 shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4227 shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4229 for (i = 0;i < r_refdef.scene.numentities;i++)
4231 ent = r_refdef.scene.entities[i];
4232 if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
4234 // cast shadows from anything of the map (submodels are optional)
4235 if (!ent->animcache_vertex3f && ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4236 R_AnimCache_GetEntity(ent, false, false);
4240 void R_DrawModelShadowMaps(void)
4243 float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
4244 entity_render_t *ent;
4245 vec3_t relativelightorigin;
4246 vec3_t relativelightdirection, relativeforward, relativeright;
4247 vec3_t relativeshadowmins, relativeshadowmaxs;
4248 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
4250 matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
4251 r_viewport_t viewport;
4253 float clearcolor[4];
4255 if (!r_refdef.scene.numentities)
4258 switch (r_shadow_shadowmode)
4260 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4266 R_ResetViewRendering3D();
4267 R_Shadow_RenderMode_Begin();
4268 R_Shadow_RenderMode_ActiveLight(NULL);
4270 switch (r_shadow_shadowmode)
4272 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4273 if (!r_shadow_shadowmap2dtexture)
4274 R_Shadow_MakeShadowMap(0, r_shadow_shadowmapmaxsize);
4275 fbo = r_shadow_fbo2d;
4276 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
4277 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
4278 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
4284 size = 2*r_shadow_shadowmapmaxsize;
4285 scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
4286 radius = 0.5f / scale;
4287 nearclip = -r_shadows_throwdistance.value;
4288 farclip = r_shadows_throwdistance.value;
4289 bias = r_shadow_shadowmapping_bias.value * r_shadow_shadowmapping_nearclip.value / (2 * r_shadows_throwdistance.value) * (1024.0f / size);
4291 r_shadow_shadowmap_parameters[0] = size;
4292 r_shadow_shadowmap_parameters[1] = size;
4293 r_shadow_shadowmap_parameters[2] = 1.0;
4294 r_shadow_shadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
4296 Math_atov(r_shadows_throwdirection.string, shadowdir);
4297 VectorNormalize(shadowdir);
4298 Math_atov(r_shadows_focus.string, shadowfocus);
4299 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4300 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4301 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4302 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4303 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4304 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4305 if (fabs(dot1) <= fabs(dot2))
4306 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4308 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4309 VectorNormalize(shadowforward);
4310 VectorM(scale, shadowforward, &m[0]);
4311 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4313 m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
4314 CrossProduct(shadowdir, shadowforward, shadowright);
4315 VectorM(scale, shadowright, &m[4]);
4316 m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
4317 VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
4318 m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
4319 Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
4320 Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
4321 R_Viewport_InitOrtho(&viewport, &cameramatrix, 0, 0, size, size, 0, 0, 1, 1, 0, -1, NULL);
4323 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4325 R_Mesh_SetRenderTargets(fbo, r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
4326 R_SetupShader_DepthOrShadow();
4327 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
4330 R_SetViewport(&viewport);
4331 GL_Scissor(viewport.x, viewport.y, min(viewport.width + r_shadow_shadowmapborder, 2*r_shadow_shadowmapmaxsize), viewport.height + r_shadow_shadowmapborder);
4332 Vector4Set(clearcolor, 1,1,1,1);
4333 // in D3D9 we have to render to a color texture shadowmap
4334 // in GL we render directly to a depth texture only
4335 if (r_shadow_shadowmap2dtexture)
4336 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4338 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4339 // render into a slightly restricted region so that the borders of the
4340 // shadowmap area fade away, rather than streaking across everything
4341 // outside the usable area
4342 GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
4346 R_Mesh_ResetRenderTargets();
4347 R_SetupShader_ShowDepth();
4348 GL_ColorMask(1,1,1,1);
4349 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4352 for (i = 0;i < r_refdef.scene.numentities;i++)
4354 ent = r_refdef.scene.entities[i];
4356 // cast shadows from anything of the map (submodels are optional)
4357 if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4359 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4360 Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
4361 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4362 Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
4363 Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
4364 relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4365 relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4366 relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4367 relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4368 relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4369 relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4370 RSurf_ActiveModelEntity(ent, false, false, false);
4371 ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
4372 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4379 unsigned char *rawpixels = Z_Malloc(viewport.width*viewport.height*4);
4381 qglReadPixels(viewport.x, viewport.y, viewport.width, viewport.height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, rawpixels);
4383 Image_WriteTGABGRA("r_shadows_2.tga", viewport.width, viewport.height, rawpixels);
4384 Cvar_SetValueQuick(&r_test, 0);
4389 R_Shadow_RenderMode_End();
4391 Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
4392 Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
4393 Matrix4x4_CreateScale3(&scalematrix, size, -size, 1);
4394 Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
4395 Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
4396 Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
4398 switch (vid.renderpath)
4400 case RENDERPATH_GL11:
4401 case RENDERPATH_GL13:
4402 case RENDERPATH_GL20:
4403 case RENDERPATH_CGGL:
4405 case RENDERPATH_D3D9:
4406 case RENDERPATH_D3D10:
4407 case RENDERPATH_D3D11:
4408 #ifdef OPENGL_ORIENTATION
4409 r_shadow_shadowmapmatrix.m[0][0] *= -1.0f;
4410 r_shadow_shadowmapmatrix.m[0][1] *= -1.0f;
4411 r_shadow_shadowmapmatrix.m[0][2] *= -1.0f;
4412 r_shadow_shadowmapmatrix.m[0][3] *= -1.0f;
4414 r_shadow_shadowmapmatrix.m[0][0] *= -1.0f;
4415 r_shadow_shadowmapmatrix.m[1][0] *= -1.0f;
4416 r_shadow_shadowmapmatrix.m[2][0] *= -1.0f;
4417 r_shadow_shadowmapmatrix.m[3][0] *= -1.0f;
4422 r_shadow_usingshadowmaportho = true;
4423 switch (r_shadow_shadowmode)
4425 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4426 r_shadow_usingshadowmap2d = true;
4433 void R_DrawModelShadows(void)
4436 float relativethrowdistance;
4437 entity_render_t *ent;
4438 vec3_t relativelightorigin;
4439 vec3_t relativelightdirection;
4440 vec3_t relativeshadowmins, relativeshadowmaxs;
4441 vec3_t tmp, shadowdir;
4443 if (!r_refdef.scene.numentities || !vid.stencil || (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL && r_shadows.integer != 1))
4446 R_ResetViewRendering3D();
4447 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4448 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4449 R_Shadow_RenderMode_Begin();
4450 R_Shadow_RenderMode_ActiveLight(NULL);
4451 r_shadow_lightscissor[0] = r_refdef.view.x;
4452 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
4453 r_shadow_lightscissor[2] = r_refdef.view.width;
4454 r_shadow_lightscissor[3] = r_refdef.view.height;
4455 R_Shadow_RenderMode_StencilShadowVolumes(false);
4458 if (r_shadows.integer == 2)
4460 Math_atov(r_shadows_throwdirection.string, shadowdir);
4461 VectorNormalize(shadowdir);
4464 R_Shadow_ClearStencil();
4466 for (i = 0;i < r_refdef.scene.numentities;i++)
4468 ent = r_refdef.scene.entities[i];
4470 // cast shadows from anything of the map (submodels are optional)
4471 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4473 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4474 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
4475 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
4476 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
4477 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4480 if(ent->entitynumber != 0)
4482 if(ent->entitynumber >= MAX_EDICTS) // csqc entity
4484 // FIXME handle this
4485 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4489 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
4490 int entnum, entnum2, recursion;
4491 entnum = entnum2 = ent->entitynumber;
4492 for(recursion = 32; recursion > 0; --recursion)
4494 entnum2 = cl.entities[entnum].state_current.tagentity;
4495 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
4500 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
4502 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
4503 // transform into modelspace of OUR entity
4504 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
4505 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
4508 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4512 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4515 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
4516 RSurf_ActiveModelEntity(ent, false, false, false);
4517 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4518 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4522 // not really the right mode, but this will disable any silly stencil features
4523 R_Shadow_RenderMode_End();
4525 // set up ortho view for rendering this pass
4526 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4527 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4528 //GL_ScissorTest(true);
4529 //R_EntityMatrix(&identitymatrix);
4530 //R_Mesh_ResetTextureState();
4531 R_ResetViewRendering2D();
4533 // set up a darkening blend on shadowed areas
4534 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4535 //GL_DepthRange(0, 1);
4536 //GL_DepthTest(false);
4537 //GL_DepthMask(false);
4538 //GL_PolygonOffset(0, 0);CHECKGLERROR
4539 GL_Color(0, 0, 0, r_shadows_darken.value);
4540 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4541 //GL_DepthFunc(GL_ALWAYS);
4542 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_NOTEQUAL, 128, 255);
4544 // apply the blend to the shadowed areas
4545 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, NULL);
4546 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
4547 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4549 // restore the viewport
4550 R_SetViewport(&r_refdef.view.viewport);
4552 // restore other state to normal
4553 //R_Shadow_RenderMode_End();
4556 void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4559 vec3_t centerorigin;
4561 // if it's too close, skip it
4562 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
4564 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4567 if (usequery && r_numqueries + 2 <= r_maxqueries)
4569 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4570 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4571 // 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
4572 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4574 switch(vid.renderpath)
4576 case RENDERPATH_GL20:
4577 case RENDERPATH_GL13:
4578 case RENDERPATH_GL11:
4579 case RENDERPATH_CGGL:
4581 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use GL_DepthFunc instead
4582 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
4583 GL_DepthFunc(GL_ALWAYS);
4584 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4585 R_Mesh_PrepareVertices_Position_Arrays(4, vertex3f);
4586 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4587 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4588 GL_DepthFunc(GL_LEQUAL);
4589 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
4590 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4591 R_Mesh_PrepareVertices_Position_Arrays(4, vertex3f);
4592 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4593 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4596 case RENDERPATH_D3D9:
4597 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4599 case RENDERPATH_D3D10:
4600 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4602 case RENDERPATH_D3D11:
4603 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4607 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4610 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
4612 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4615 GLint allpixels = 0, visiblepixels = 0;
4616 // now we have to check the query result
4617 if (rtlight->corona_queryindex_visiblepixels)
4619 switch(vid.renderpath)
4621 case RENDERPATH_GL20:
4622 case RENDERPATH_GL13:
4623 case RENDERPATH_GL11:
4624 case RENDERPATH_CGGL:
4626 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
4627 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
4630 case RENDERPATH_D3D9:
4631 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4633 case RENDERPATH_D3D10:
4634 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4636 case RENDERPATH_D3D11:
4637 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4640 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
4641 if (visiblepixels < 1 || allpixels < 1)
4643 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
4644 cscale *= rtlight->corona_visibility;
4648 // FIXME: these traces should scan all render entities instead of cl.world
4649 if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
4652 VectorScale(rtlight->currentcolor, cscale, color);
4653 if (VectorLength(color) > (1.0f / 256.0f))
4656 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
4659 VectorNegate(color, color);
4660 switch(vid.renderpath)
4662 case RENDERPATH_GL11:
4663 case RENDERPATH_GL13:
4664 case RENDERPATH_GL20:
4665 case RENDERPATH_CGGL:
4666 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
4668 case RENDERPATH_D3D9:
4670 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_SUBTRACT);
4673 case RENDERPATH_D3D10:
4674 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4676 case RENDERPATH_D3D11:
4677 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4681 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4682 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);
4683 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4686 switch(vid.renderpath)
4688 case RENDERPATH_GL11:
4689 case RENDERPATH_GL13:
4690 case RENDERPATH_GL20:
4691 case RENDERPATH_CGGL:
4692 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
4694 case RENDERPATH_D3D9:
4696 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_ADD);
4699 case RENDERPATH_D3D10:
4700 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4702 case RENDERPATH_D3D11:
4703 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4710 void R_Shadow_DrawCoronas(void)
4713 qboolean usequery = false;
4718 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4720 if (r_waterstate.renderingscene)
4722 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4723 R_EntityMatrix(&identitymatrix);
4725 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4727 // check occlusion of coronas
4728 // use GL_ARB_occlusion_query if available
4729 // otherwise use raytraces
4731 switch (vid.renderpath)
4733 case RENDERPATH_GL11:
4734 case RENDERPATH_GL13:
4735 case RENDERPATH_GL20:
4736 case RENDERPATH_CGGL:
4737 usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
4740 GL_ColorMask(0,0,0,0);
4741 if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
4742 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
4745 r_maxqueries = (range + r_refdef.scene.numlights) * 4;
4746 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
4748 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
4751 RSurf_ActiveWorldEntity();
4752 GL_BlendFunc(GL_ONE, GL_ZERO);
4753 GL_CullFace(GL_NONE);
4754 GL_DepthMask(false);
4755 GL_DepthRange(0, 1);
4756 GL_PolygonOffset(0, 0);
4758 R_Mesh_ResetTextureState();
4759 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
4762 case RENDERPATH_D3D9:
4764 //Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4766 case RENDERPATH_D3D10:
4767 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4769 case RENDERPATH_D3D11:
4770 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4773 for (lightindex = 0;lightindex < range;lightindex++)
4775 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4778 rtlight = &light->rtlight;
4779 rtlight->corona_visibility = 0;
4780 rtlight->corona_queryindex_visiblepixels = 0;
4781 rtlight->corona_queryindex_allpixels = 0;
4782 if (!(rtlight->flags & flag))
4784 if (rtlight->corona <= 0)
4786 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4788 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4790 for (i = 0;i < r_refdef.scene.numlights;i++)
4792 rtlight = r_refdef.scene.lights[i];
4793 rtlight->corona_visibility = 0;
4794 rtlight->corona_queryindex_visiblepixels = 0;
4795 rtlight->corona_queryindex_allpixels = 0;
4796 if (!(rtlight->flags & flag))
4798 if (rtlight->corona <= 0)
4800 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4803 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4805 // now draw the coronas using the query data for intensity info
4806 for (lightindex = 0;lightindex < range;lightindex++)
4808 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4811 rtlight = &light->rtlight;
4812 if (rtlight->corona_visibility <= 0)
4814 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4816 for (i = 0;i < r_refdef.scene.numlights;i++)
4818 rtlight = r_refdef.scene.lights[i];
4819 if (rtlight->corona_visibility <= 0)
4821 if (gl_flashblend.integer)
4822 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4824 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4830 dlight_t *R_Shadow_NewWorldLight(void)
4832 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4835 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)
4838 // validate parameters
4839 if (style < 0 || style >= MAX_LIGHTSTYLES)
4841 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
4847 // copy to light properties
4848 VectorCopy(origin, light->origin);
4849 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4850 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4851 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4853 light->color[0] = max(color[0], 0);
4854 light->color[1] = max(color[1], 0);
4855 light->color[2] = max(color[2], 0);
4857 light->color[0] = color[0];
4858 light->color[1] = color[1];
4859 light->color[2] = color[2];
4860 light->radius = max(radius, 0);
4861 light->style = style;
4862 light->shadow = shadowenable;
4863 light->corona = corona;
4864 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4865 light->coronasizescale = coronasizescale;
4866 light->ambientscale = ambientscale;
4867 light->diffusescale = diffusescale;
4868 light->specularscale = specularscale;
4869 light->flags = flags;
4871 // update renderable light data
4872 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4873 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);
4876 void R_Shadow_FreeWorldLight(dlight_t *light)
4878 if (r_shadow_selectedlight == light)
4879 r_shadow_selectedlight = NULL;
4880 R_RTLight_Uncompile(&light->rtlight);
4881 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4884 void R_Shadow_ClearWorldLights(void)
4888 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4889 for (lightindex = 0;lightindex < range;lightindex++)
4891 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4893 R_Shadow_FreeWorldLight(light);
4895 r_shadow_selectedlight = NULL;
4898 void R_Shadow_SelectLight(dlight_t *light)
4900 if (r_shadow_selectedlight)
4901 r_shadow_selectedlight->selected = false;
4902 r_shadow_selectedlight = light;
4903 if (r_shadow_selectedlight)
4904 r_shadow_selectedlight->selected = true;
4907 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4909 // this is never batched (there can be only one)
4911 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
4912 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4913 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4916 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4921 skinframe_t *skinframe;
4924 // this is never batched (due to the ent parameter changing every time)
4925 // so numsurfaces == 1 and surfacelist[0] == lightnumber
4926 const dlight_t *light = (dlight_t *)ent;
4929 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
4932 VectorScale(light->color, intensity, spritecolor);
4933 if (VectorLength(spritecolor) < 0.1732f)
4934 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
4935 if (VectorLength(spritecolor) > 1.0f)
4936 VectorNormalize(spritecolor);
4938 // draw light sprite
4939 if (light->cubemapname[0] && !light->shadow)
4940 skinframe = r_editlights_sprcubemapnoshadowlight;
4941 else if (light->cubemapname[0])
4942 skinframe = r_editlights_sprcubemaplight;
4943 else if (!light->shadow)
4944 skinframe = r_editlights_sprnoshadowlight;
4946 skinframe = r_editlights_sprlight;
4948 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);
4949 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4951 // draw selection sprite if light is selected
4952 if (light->selected)
4954 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4955 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4956 // VorteX todo: add normalmode/realtime mode light overlay sprites?
4960 void R_Shadow_DrawLightSprites(void)
4964 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4965 for (lightindex = 0;lightindex < range;lightindex++)
4967 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4969 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
4971 if (!r_editlights_lockcursor)
4972 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
4975 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
4980 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
4981 if (lightindex >= range)
4983 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4986 rtlight = &light->rtlight;
4987 //if (!(rtlight->flags & flag))
4989 VectorCopy(rtlight->shadoworigin, origin);
4990 *radius = rtlight->radius;
4991 VectorCopy(rtlight->color, color);
4995 void R_Shadow_SelectLightInView(void)
4997 float bestrating, rating, temp[3];
5001 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5005 if (r_editlights_lockcursor)
5007 for (lightindex = 0;lightindex < range;lightindex++)
5009 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5012 VectorSubtract(light->origin, r_refdef.view.origin, temp);
5013 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
5016 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
5017 if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1.0f)
5019 bestrating = rating;
5024 R_Shadow_SelectLight(best);
5027 void R_Shadow_LoadWorldLights(void)
5029 int n, a, style, shadow, flags;
5030 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
5031 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
5032 if (cl.worldmodel == NULL)
5034 Con_Print("No map loaded.\n");
5037 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
5038 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5048 for (;COM_Parse(t, true) && strcmp(
5049 if (COM_Parse(t, true))
5051 if (com_token[0] == '!')
5054 origin[0] = atof(com_token+1);
5057 origin[0] = atof(com_token);
5062 while (*s && *s != '\n' && *s != '\r')
5068 // check for modifier flags
5075 #if _MSC_VER >= 1400
5076 #define sscanf sscanf_s
5078 cubemapname[sizeof(cubemapname)-1] = 0;
5079 #if MAX_QPATH != 128
5080 #error update this code if MAX_QPATH changes
5082 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
5083 #if _MSC_VER >= 1400
5084 , sizeof(cubemapname)
5086 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
5089 flags = LIGHTFLAG_REALTIMEMODE;
5097 coronasizescale = 0.25f;
5099 VectorClear(angles);
5102 if (a < 9 || !strcmp(cubemapname, "\"\""))
5104 // remove quotes on cubemapname
5105 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
5108 namelen = strlen(cubemapname) - 2;
5109 memmove(cubemapname, cubemapname + 1, namelen);
5110 cubemapname[namelen] = '\0';
5114 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);
5117 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5125 Con_Printf("invalid rtlights file \"%s\"\n", name);
5126 Mem_Free(lightsstring);
5130 void R_Shadow_SaveWorldLights(void)
5134 size_t bufchars, bufmaxchars;
5136 char name[MAX_QPATH];
5137 char line[MAX_INPUTLINE];
5138 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
5139 // I hate lines which are 3 times my screen size :( --blub
5142 if (cl.worldmodel == NULL)
5144 Con_Print("No map loaded.\n");
5147 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
5148 bufchars = bufmaxchars = 0;
5150 for (lightindex = 0;lightindex < range;lightindex++)
5152 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5155 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
5156 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);
5157 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
5158 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]);
5160 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);
5161 if (bufchars + strlen(line) > bufmaxchars)
5163 bufmaxchars = bufchars + strlen(line) + 2048;
5165 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
5169 memcpy(buf, oldbuf, bufchars);
5175 memcpy(buf + bufchars, line, strlen(line));
5176 bufchars += strlen(line);
5180 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
5185 void R_Shadow_LoadLightsFile(void)
5188 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
5189 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
5190 if (cl.worldmodel == NULL)
5192 Con_Print("No map loaded.\n");
5195 dpsnprintf(name, sizeof(name), "%s.lights", cl.worldnamenoextension);
5196 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5204 while (*s && *s != '\n' && *s != '\r')
5210 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);
5214 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);
5217 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
5218 radius = bound(15, radius, 4096);
5219 VectorScale(color, (2.0f / (8388608.0f)), color);
5220 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5228 Con_Printf("invalid lights file \"%s\"\n", name);
5229 Mem_Free(lightsstring);
5233 // tyrlite/hmap2 light types in the delay field
5234 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
5236 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
5248 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
5249 char key[256], value[MAX_INPUTLINE];
5251 if (cl.worldmodel == NULL)
5253 Con_Print("No map loaded.\n");
5256 // try to load a .ent file first
5257 dpsnprintf(key, sizeof(key), "%s.ent", cl.worldnamenoextension);
5258 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
5259 // and if that is not found, fall back to the bsp file entity string
5261 data = cl.worldmodel->brush.entities;
5264 for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
5266 type = LIGHTTYPE_MINUSX;
5267 origin[0] = origin[1] = origin[2] = 0;
5268 originhack[0] = originhack[1] = originhack[2] = 0;
5269 angles[0] = angles[1] = angles[2] = 0;
5270 color[0] = color[1] = color[2] = 1;
5271 light[0] = light[1] = light[2] = 1;light[3] = 300;
5272 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
5282 if (!COM_ParseToken_Simple(&data, false, false))
5284 if (com_token[0] == '}')
5285 break; // end of entity
5286 if (com_token[0] == '_')
5287 strlcpy(key, com_token + 1, sizeof(key));
5289 strlcpy(key, com_token, sizeof(key));
5290 while (key[strlen(key)-1] == ' ') // remove trailing spaces
5291 key[strlen(key)-1] = 0;
5292 if (!COM_ParseToken_Simple(&data, false, false))
5294 strlcpy(value, com_token, sizeof(value));
5296 // now that we have the key pair worked out...
5297 if (!strcmp("light", key))
5299 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5303 light[0] = vec[0] * (1.0f / 256.0f);
5304 light[1] = vec[0] * (1.0f / 256.0f);
5305 light[2] = vec[0] * (1.0f / 256.0f);
5311 light[0] = vec[0] * (1.0f / 255.0f);
5312 light[1] = vec[1] * (1.0f / 255.0f);
5313 light[2] = vec[2] * (1.0f / 255.0f);
5317 else if (!strcmp("delay", key))
5319 else if (!strcmp("origin", key))
5320 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5321 else if (!strcmp("angle", key))
5322 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5323 else if (!strcmp("angles", key))
5324 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5325 else if (!strcmp("color", key))
5326 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5327 else if (!strcmp("wait", key))
5328 fadescale = atof(value);
5329 else if (!strcmp("classname", key))
5331 if (!strncmp(value, "light", 5))
5334 if (!strcmp(value, "light_fluoro"))
5339 overridecolor[0] = 1;
5340 overridecolor[1] = 1;
5341 overridecolor[2] = 1;
5343 if (!strcmp(value, "light_fluorospark"))
5348 overridecolor[0] = 1;
5349 overridecolor[1] = 1;
5350 overridecolor[2] = 1;
5352 if (!strcmp(value, "light_globe"))
5357 overridecolor[0] = 1;
5358 overridecolor[1] = 0.8;
5359 overridecolor[2] = 0.4;
5361 if (!strcmp(value, "light_flame_large_yellow"))
5366 overridecolor[0] = 1;
5367 overridecolor[1] = 0.5;
5368 overridecolor[2] = 0.1;
5370 if (!strcmp(value, "light_flame_small_yellow"))
5375 overridecolor[0] = 1;
5376 overridecolor[1] = 0.5;
5377 overridecolor[2] = 0.1;
5379 if (!strcmp(value, "light_torch_small_white"))
5384 overridecolor[0] = 1;
5385 overridecolor[1] = 0.5;
5386 overridecolor[2] = 0.1;
5388 if (!strcmp(value, "light_torch_small_walltorch"))
5393 overridecolor[0] = 1;
5394 overridecolor[1] = 0.5;
5395 overridecolor[2] = 0.1;
5399 else if (!strcmp("style", key))
5400 style = atoi(value);
5401 else if (!strcmp("skin", key))
5402 skin = (int)atof(value);
5403 else if (!strcmp("pflags", key))
5404 pflags = (int)atof(value);
5405 //else if (!strcmp("effects", key))
5406 // effects = (int)atof(value);
5407 else if (cl.worldmodel->type == mod_brushq3)
5409 if (!strcmp("scale", key))
5410 lightscale = atof(value);
5411 if (!strcmp("fade", key))
5412 fadescale = atof(value);
5417 if (lightscale <= 0)
5421 if (color[0] == color[1] && color[0] == color[2])
5423 color[0] *= overridecolor[0];
5424 color[1] *= overridecolor[1];
5425 color[2] *= overridecolor[2];
5427 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5428 color[0] = color[0] * light[0];
5429 color[1] = color[1] * light[1];
5430 color[2] = color[2] * light[2];
5433 case LIGHTTYPE_MINUSX:
5435 case LIGHTTYPE_RECIPX:
5437 VectorScale(color, (1.0f / 16.0f), color);
5439 case LIGHTTYPE_RECIPXX:
5441 VectorScale(color, (1.0f / 16.0f), color);
5444 case LIGHTTYPE_NONE:
5448 case LIGHTTYPE_MINUSXX:
5451 VectorAdd(origin, originhack, origin);
5453 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);
5456 Mem_Free(entfiledata);
5460 void R_Shadow_SetCursorLocationForView(void)
5463 vec3_t dest, endpos;
5465 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5466 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
5467 if (trace.fraction < 1)
5469 dist = trace.fraction * r_editlights_cursordistance.value;
5470 push = r_editlights_cursorpushback.value;
5474 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5475 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5479 VectorClear( endpos );
5481 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5482 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5483 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5486 void R_Shadow_UpdateWorldLightSelection(void)
5488 if (r_editlights.integer)
5490 R_Shadow_SetCursorLocationForView();
5491 R_Shadow_SelectLightInView();
5494 R_Shadow_SelectLight(NULL);
5497 void R_Shadow_EditLights_Clear_f(void)
5499 R_Shadow_ClearWorldLights();
5502 void R_Shadow_EditLights_Reload_f(void)
5506 strlcpy(r_shadow_mapname, cl.worldname, sizeof(r_shadow_mapname));
5507 R_Shadow_ClearWorldLights();
5508 R_Shadow_LoadWorldLights();
5509 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5511 R_Shadow_LoadLightsFile();
5512 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5513 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5517 void R_Shadow_EditLights_Save_f(void)
5521 R_Shadow_SaveWorldLights();
5524 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
5526 R_Shadow_ClearWorldLights();
5527 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5530 void R_Shadow_EditLights_ImportLightsFile_f(void)
5532 R_Shadow_ClearWorldLights();
5533 R_Shadow_LoadLightsFile();
5536 void R_Shadow_EditLights_Spawn_f(void)
5539 if (!r_editlights.integer)
5541 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5544 if (Cmd_Argc() != 1)
5546 Con_Print("r_editlights_spawn does not take parameters\n");
5549 color[0] = color[1] = color[2] = 1;
5550 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5553 void R_Shadow_EditLights_Edit_f(void)
5555 vec3_t origin, angles, color;
5556 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5557 int style, shadows, flags, normalmode, realtimemode;
5558 char cubemapname[MAX_INPUTLINE];
5559 if (!r_editlights.integer)
5561 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5564 if (!r_shadow_selectedlight)
5566 Con_Print("No selected light.\n");
5569 VectorCopy(r_shadow_selectedlight->origin, origin);
5570 VectorCopy(r_shadow_selectedlight->angles, angles);
5571 VectorCopy(r_shadow_selectedlight->color, color);
5572 radius = r_shadow_selectedlight->radius;
5573 style = r_shadow_selectedlight->style;
5574 if (r_shadow_selectedlight->cubemapname)
5575 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5578 shadows = r_shadow_selectedlight->shadow;
5579 corona = r_shadow_selectedlight->corona;
5580 coronasizescale = r_shadow_selectedlight->coronasizescale;
5581 ambientscale = r_shadow_selectedlight->ambientscale;
5582 diffusescale = r_shadow_selectedlight->diffusescale;
5583 specularscale = r_shadow_selectedlight->specularscale;
5584 flags = r_shadow_selectedlight->flags;
5585 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5586 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5587 if (!strcmp(Cmd_Argv(1), "origin"))
5589 if (Cmd_Argc() != 5)
5591 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5594 origin[0] = atof(Cmd_Argv(2));
5595 origin[1] = atof(Cmd_Argv(3));
5596 origin[2] = atof(Cmd_Argv(4));
5598 else if (!strcmp(Cmd_Argv(1), "originx"))
5600 if (Cmd_Argc() != 3)
5602 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5605 origin[0] = atof(Cmd_Argv(2));
5607 else if (!strcmp(Cmd_Argv(1), "originy"))
5609 if (Cmd_Argc() != 3)
5611 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5614 origin[1] = atof(Cmd_Argv(2));
5616 else if (!strcmp(Cmd_Argv(1), "originz"))
5618 if (Cmd_Argc() != 3)
5620 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5623 origin[2] = atof(Cmd_Argv(2));
5625 else if (!strcmp(Cmd_Argv(1), "move"))
5627 if (Cmd_Argc() != 5)
5629 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5632 origin[0] += atof(Cmd_Argv(2));
5633 origin[1] += atof(Cmd_Argv(3));
5634 origin[2] += atof(Cmd_Argv(4));
5636 else if (!strcmp(Cmd_Argv(1), "movex"))
5638 if (Cmd_Argc() != 3)
5640 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5643 origin[0] += atof(Cmd_Argv(2));
5645 else if (!strcmp(Cmd_Argv(1), "movey"))
5647 if (Cmd_Argc() != 3)
5649 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5652 origin[1] += atof(Cmd_Argv(2));
5654 else if (!strcmp(Cmd_Argv(1), "movez"))
5656 if (Cmd_Argc() != 3)
5658 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5661 origin[2] += atof(Cmd_Argv(2));
5663 else if (!strcmp(Cmd_Argv(1), "angles"))
5665 if (Cmd_Argc() != 5)
5667 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5670 angles[0] = atof(Cmd_Argv(2));
5671 angles[1] = atof(Cmd_Argv(3));
5672 angles[2] = atof(Cmd_Argv(4));
5674 else if (!strcmp(Cmd_Argv(1), "anglesx"))
5676 if (Cmd_Argc() != 3)
5678 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5681 angles[0] = atof(Cmd_Argv(2));
5683 else if (!strcmp(Cmd_Argv(1), "anglesy"))
5685 if (Cmd_Argc() != 3)
5687 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5690 angles[1] = atof(Cmd_Argv(2));
5692 else if (!strcmp(Cmd_Argv(1), "anglesz"))
5694 if (Cmd_Argc() != 3)
5696 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5699 angles[2] = atof(Cmd_Argv(2));
5701 else if (!strcmp(Cmd_Argv(1), "color"))
5703 if (Cmd_Argc() != 5)
5705 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
5708 color[0] = atof(Cmd_Argv(2));
5709 color[1] = atof(Cmd_Argv(3));
5710 color[2] = atof(Cmd_Argv(4));
5712 else if (!strcmp(Cmd_Argv(1), "radius"))
5714 if (Cmd_Argc() != 3)
5716 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5719 radius = atof(Cmd_Argv(2));
5721 else if (!strcmp(Cmd_Argv(1), "colorscale"))
5723 if (Cmd_Argc() == 3)
5725 double scale = atof(Cmd_Argv(2));
5732 if (Cmd_Argc() != 5)
5734 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
5737 color[0] *= atof(Cmd_Argv(2));
5738 color[1] *= atof(Cmd_Argv(3));
5739 color[2] *= atof(Cmd_Argv(4));
5742 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
5744 if (Cmd_Argc() != 3)
5746 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5749 radius *= atof(Cmd_Argv(2));
5751 else if (!strcmp(Cmd_Argv(1), "style"))
5753 if (Cmd_Argc() != 3)
5755 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5758 style = atoi(Cmd_Argv(2));
5760 else if (!strcmp(Cmd_Argv(1), "cubemap"))
5764 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5767 if (Cmd_Argc() == 3)
5768 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
5772 else if (!strcmp(Cmd_Argv(1), "shadows"))
5774 if (Cmd_Argc() != 3)
5776 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5779 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5781 else if (!strcmp(Cmd_Argv(1), "corona"))
5783 if (Cmd_Argc() != 3)
5785 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5788 corona = atof(Cmd_Argv(2));
5790 else if (!strcmp(Cmd_Argv(1), "coronasize"))
5792 if (Cmd_Argc() != 3)
5794 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5797 coronasizescale = atof(Cmd_Argv(2));
5799 else if (!strcmp(Cmd_Argv(1), "ambient"))
5801 if (Cmd_Argc() != 3)
5803 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5806 ambientscale = atof(Cmd_Argv(2));
5808 else if (!strcmp(Cmd_Argv(1), "diffuse"))
5810 if (Cmd_Argc() != 3)
5812 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5815 diffusescale = atof(Cmd_Argv(2));
5817 else if (!strcmp(Cmd_Argv(1), "specular"))
5819 if (Cmd_Argc() != 3)
5821 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5824 specularscale = atof(Cmd_Argv(2));
5826 else if (!strcmp(Cmd_Argv(1), "normalmode"))
5828 if (Cmd_Argc() != 3)
5830 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5833 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5835 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
5837 if (Cmd_Argc() != 3)
5839 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5842 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5846 Con_Print("usage: r_editlights_edit [property] [value]\n");
5847 Con_Print("Selected light's properties:\n");
5848 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5849 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5850 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5851 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
5852 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
5853 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
5854 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5855 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
5856 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
5857 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
5858 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
5859 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
5860 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5861 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5864 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5865 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5868 void R_Shadow_EditLights_EditAll_f(void)
5871 dlight_t *light, *oldselected;
5874 if (!r_editlights.integer)
5876 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5880 oldselected = r_shadow_selectedlight;
5881 // EditLights doesn't seem to have a "remove" command or something so:
5882 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5883 for (lightindex = 0;lightindex < range;lightindex++)
5885 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5888 R_Shadow_SelectLight(light);
5889 R_Shadow_EditLights_Edit_f();
5891 // return to old selected (to not mess editing once selection is locked)
5892 R_Shadow_SelectLight(oldselected);
5895 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
5897 int lightnumber, lightcount;
5898 size_t lightindex, range;
5902 if (!r_editlights.integer)
5904 x = vid_conwidth.value - 240;
5906 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
5909 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5910 for (lightindex = 0;lightindex < range;lightindex++)
5912 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5915 if (light == r_shadow_selectedlight)
5916 lightnumber = lightindex;
5919 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;
5920 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;
5922 if (r_shadow_selectedlight == NULL)
5924 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;
5925 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;
5926 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;
5927 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;
5928 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;
5929 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;
5930 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;
5931 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;
5932 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;
5933 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;
5934 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;
5935 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;
5936 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;
5937 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;
5938 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;
5941 void R_Shadow_EditLights_ToggleShadow_f(void)
5943 if (!r_editlights.integer)
5945 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5948 if (!r_shadow_selectedlight)
5950 Con_Print("No selected light.\n");
5953 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);
5956 void R_Shadow_EditLights_ToggleCorona_f(void)
5958 if (!r_editlights.integer)
5960 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5963 if (!r_shadow_selectedlight)
5965 Con_Print("No selected light.\n");
5968 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);
5971 void R_Shadow_EditLights_Remove_f(void)
5973 if (!r_editlights.integer)
5975 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
5978 if (!r_shadow_selectedlight)
5980 Con_Print("No selected light.\n");
5983 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
5984 r_shadow_selectedlight = NULL;
5987 void R_Shadow_EditLights_Help_f(void)
5990 "Documentation on r_editlights system:\n"
5992 "r_editlights : enable/disable editing mode\n"
5993 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
5994 "r_editlights_cursorpushback : push back cursor this far from surface\n"
5995 "r_editlights_cursorpushoff : push cursor off surface this far\n"
5996 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
5997 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
5999 "r_editlights_help : this help\n"
6000 "r_editlights_clear : remove all lights\n"
6001 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
6002 "r_editlights_lock : lock selection to current light, if already locked - unlock\n"
6003 "r_editlights_save : save to .rtlights file\n"
6004 "r_editlights_spawn : create a light with default settings\n"
6005 "r_editlights_edit command : edit selected light - more documentation below\n"
6006 "r_editlights_remove : remove selected light\n"
6007 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
6008 "r_editlights_importlightentitiesfrommap : reload light entities\n"
6009 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
6011 "origin x y z : set light location\n"
6012 "originx x: set x component of light location\n"
6013 "originy y: set y component of light location\n"
6014 "originz z: set z component of light location\n"
6015 "move x y z : adjust light location\n"
6016 "movex x: adjust x component of light location\n"
6017 "movey y: adjust y component of light location\n"
6018 "movez z: adjust z component of light location\n"
6019 "angles x y z : set light angles\n"
6020 "anglesx x: set x component of light angles\n"
6021 "anglesy y: set y component of light angles\n"
6022 "anglesz z: set z component of light angles\n"
6023 "color r g b : set color of light (can be brighter than 1 1 1)\n"
6024 "radius radius : set radius (size) of light\n"
6025 "colorscale grey : multiply color of light (1 does nothing)\n"
6026 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
6027 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
6028 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
6029 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
6030 "cubemap basename : set filter cubemap of light (not yet supported)\n"
6031 "shadows 1/0 : turn on/off shadows\n"
6032 "corona n : set corona intensity\n"
6033 "coronasize n : set corona size (0-1)\n"
6034 "ambient n : set ambient intensity (0-1)\n"
6035 "diffuse n : set diffuse intensity (0-1)\n"
6036 "specular n : set specular intensity (0-1)\n"
6037 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
6038 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
6039 "<nothing> : print light properties to console\n"
6043 void R_Shadow_EditLights_CopyInfo_f(void)
6045 if (!r_editlights.integer)
6047 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
6050 if (!r_shadow_selectedlight)
6052 Con_Print("No selected light.\n");
6055 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
6056 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
6057 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
6058 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
6059 if (r_shadow_selectedlight->cubemapname)
6060 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
6062 r_shadow_bufferlight.cubemapname[0] = 0;
6063 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
6064 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
6065 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
6066 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
6067 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
6068 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
6069 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
6072 void R_Shadow_EditLights_PasteInfo_f(void)
6074 if (!r_editlights.integer)
6076 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
6079 if (!r_shadow_selectedlight)
6081 Con_Print("No selected light.\n");
6084 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);
6087 void R_Shadow_EditLights_Lock_f(void)
6089 if (!r_editlights.integer)
6091 Con_Print("Cannot lock on light when not in editing mode. Set r_editlights to 1.\n");
6094 if (r_editlights_lockcursor)
6096 r_editlights_lockcursor = false;
6099 if (!r_shadow_selectedlight)
6101 Con_Print("No selected light to lock on.\n");
6104 r_editlights_lockcursor = true;
6107 void R_Shadow_EditLights_Init(void)
6109 Cvar_RegisterVariable(&r_editlights);
6110 Cvar_RegisterVariable(&r_editlights_cursordistance);
6111 Cvar_RegisterVariable(&r_editlights_cursorpushback);
6112 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
6113 Cvar_RegisterVariable(&r_editlights_cursorgrid);
6114 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
6115 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
6116 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
6117 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)");
6118 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
6119 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
6120 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
6121 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)");
6122 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
6123 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
6124 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
6125 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
6126 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
6127 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
6128 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)");
6129 Cmd_AddCommand("r_editlights_lock", R_Shadow_EditLights_Lock_f, "lock selection to current light, if already locked - unlock");
6135 =============================================================================
6139 =============================================================================
6142 void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, int dynamic)
6144 VectorClear(diffusecolor);
6145 VectorClear(diffusenormal);
6147 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
6149 ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_refdef.scene.ambient;
6150 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
6153 VectorSet(ambientcolor, 1, 1, 1);
6160 for (i = 0;i < r_refdef.scene.numlights;i++)
6162 light = r_refdef.scene.lights[i];
6163 Matrix4x4_Transform(&light->matrix_worldtolight, p, v);
6164 f = 1 - VectorLength2(v);
6165 if (f > 0 && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
6166 VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);