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_prepassgeometrynormalmaptexture;
258 rtexture_t *r_shadow_prepasslightingdiffusetexture;
259 rtexture_t *r_shadow_prepasslightingspeculartexture;
261 // lights are reloaded when this changes
262 char r_shadow_mapname[MAX_QPATH];
264 // used only for light filters (cubemaps)
265 rtexturepool_t *r_shadow_filters_texturepool;
267 static const GLenum r_shadow_prepasslightingdrawbuffers[2] = {GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT};
269 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"};
270 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"};
271 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
272 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"};
273 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)"};
274 //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"};
275 cvar_t r_shadow_usenormalmap = {CVAR_SAVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"};
276 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)"};
277 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"};
278 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
279 cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
280 cvar_t r_shadow_gloss2exponent = {0, "r_shadow_gloss2exponent", "32", "same as r_shadow_glossexponent but for forced gloss (gloss 2) surfaces"};
281 cvar_t r_shadow_glossexact = {0, "r_shadow_glossexact", "0", "use exact reflection math for gloss (slightly slower, but should look a tad better)"};
282 cvar_t r_shadow_lightattenuationdividebias = {0, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"};
283 cvar_t r_shadow_lightattenuationlinearscale = {0, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"};
284 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
285 cvar_t r_shadow_lightradiusscale = {0, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
286 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "0", "how far to cast shadows"};
287 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)"};
288 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
289 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
290 cvar_t r_shadow_realtime_dlight_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
291 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
292 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)"};
293 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"};
294 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
295 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
296 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"};
297 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)"};
298 cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "0", "enables portal-based culling optimization during compilation (overrides compilesvbsp)"};
299 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)"};
300 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"};
301 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)"};
302 cvar_t r_shadow_shadowmapping_depthbits = {CVAR_SAVE, "r_shadow_shadowmapping_depthbits", "24", "requested minimum shadowmap texture depth bits"};
303 cvar_t r_shadow_shadowmapping_vsdct = {CVAR_SAVE, "r_shadow_shadowmapping_vsdct", "1", "enables use of virtual shadow depth cube texture"};
304 cvar_t r_shadow_shadowmapping_minsize = {CVAR_SAVE, "r_shadow_shadowmapping_minsize", "32", "shadowmap size limit"};
305 cvar_t r_shadow_shadowmapping_maxsize = {CVAR_SAVE, "r_shadow_shadowmapping_maxsize", "512", "shadowmap size limit"};
306 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"};
307 //cvar_t r_shadow_shadowmapping_lod_bias = {CVAR_SAVE, "r_shadow_shadowmapping_lod_bias", "16", "shadowmap size bias"};
308 //cvar_t r_shadow_shadowmapping_lod_scale = {CVAR_SAVE, "r_shadow_shadowmapping_lod_scale", "128", "shadowmap size scaling parameter"};
309 cvar_t r_shadow_shadowmapping_bordersize = {CVAR_SAVE, "r_shadow_shadowmapping_bordersize", "4", "shadowmap size bias for filtering"};
310 cvar_t r_shadow_shadowmapping_nearclip = {CVAR_SAVE, "r_shadow_shadowmapping_nearclip", "1", "shadowmap nearclip in world units"};
311 cvar_t r_shadow_shadowmapping_bias = {CVAR_SAVE, "r_shadow_shadowmapping_bias", "0.03", "shadowmap bias parameter (this is multiplied by nearclip * 1024 / lodsize)"};
312 cvar_t r_shadow_shadowmapping_polygonfactor = {CVAR_SAVE, "r_shadow_shadowmapping_polygonfactor", "2", "slope-dependent shadowmapping bias"};
313 cvar_t r_shadow_shadowmapping_polygonoffset = {CVAR_SAVE, "r_shadow_shadowmapping_polygonoffset", "0", "constant shadowmapping bias"};
314 cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
315 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)"};
316 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)"};
317 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "1", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
318 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"};
319 cvar_t r_coronas_occlusionquery = {CVAR_SAVE, "r_coronas_occlusionquery", "1", "use GL_ARB_occlusion_query extension if supported (fades coronas according to visibility)"};
320 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
321 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
322 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
323 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
324 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
325 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
326 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
327 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
328 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
330 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
331 #define ATTENTABLESIZE 256
332 // 1D gradient, 2D circle and 3D sphere attenuation textures
333 #define ATTEN1DSIZE 32
334 #define ATTEN2DSIZE 64
335 #define ATTEN3DSIZE 32
337 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
338 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
339 static float r_shadow_attentable[ATTENTABLESIZE+1];
341 rtlight_t *r_shadow_compilingrtlight;
342 static memexpandablearray_t r_shadow_worldlightsarray;
343 dlight_t *r_shadow_selectedlight;
344 dlight_t r_shadow_bufferlight;
345 vec3_t r_editlights_cursorlocation;
346 qboolean r_editlights_lockcursor;
348 extern int con_vislines;
350 void R_Shadow_UncompileWorldLights(void);
351 void R_Shadow_ClearWorldLights(void);
352 void R_Shadow_SaveWorldLights(void);
353 void R_Shadow_LoadWorldLights(void);
354 void R_Shadow_LoadLightsFile(void);
355 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
356 void R_Shadow_EditLights_Reload_f(void);
357 void R_Shadow_ValidateCvars(void);
358 static void R_Shadow_MakeTextures(void);
360 #define EDLIGHTSPRSIZE 8
361 skinframe_t *r_editlights_sprcursor;
362 skinframe_t *r_editlights_sprlight;
363 skinframe_t *r_editlights_sprnoshadowlight;
364 skinframe_t *r_editlights_sprcubemaplight;
365 skinframe_t *r_editlights_sprcubemapnoshadowlight;
366 skinframe_t *r_editlights_sprselection;
368 void R_Shadow_SetShadowMode(void)
370 r_shadow_shadowmapmaxsize = bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4);
371 r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20;
372 r_shadow_shadowmapfilterquality = r_shadow_shadowmapping_filterquality.integer;
373 r_shadow_shadowmapdepthbits = r_shadow_shadowmapping_depthbits.integer;
374 r_shadow_shadowmapborder = bound(0, r_shadow_shadowmapping_bordersize.integer, 16);
375 r_shadow_shadowmaplod = -1;
376 r_shadow_shadowmapsize = 0;
377 r_shadow_shadowmapsampler = false;
378 r_shadow_shadowmappcf = 0;
379 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
380 if ((r_shadow_shadowmapping.integer || r_shadow_deferred.integer) && vid.support.ext_framebuffer_object)
382 switch(vid.renderpath)
384 case RENDERPATH_GL20:
385 if(r_shadow_shadowmapfilterquality < 0)
387 if(vid.support.amd_texture_texture4 || vid.support.arb_texture_gather)
388 r_shadow_shadowmappcf = 1;
389 else if(strstr(gl_vendor, "NVIDIA") || strstr(gl_renderer, "Radeon HD"))
391 r_shadow_shadowmapsampler = vid.support.arb_shadow;
392 r_shadow_shadowmappcf = 1;
394 else if(strstr(gl_vendor, "ATI"))
395 r_shadow_shadowmappcf = 1;
397 r_shadow_shadowmapsampler = vid.support.arb_shadow;
401 switch (r_shadow_shadowmapfilterquality)
404 r_shadow_shadowmapsampler = vid.support.arb_shadow;
407 r_shadow_shadowmapsampler = vid.support.arb_shadow;
408 r_shadow_shadowmappcf = 1;
411 r_shadow_shadowmappcf = 1;
414 r_shadow_shadowmappcf = 2;
418 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
419 // Cg has very little choice in depth texture sampling
421 r_shadow_shadowmapsampler = false;
423 case RENDERPATH_CGGL:
424 case RENDERPATH_D3D9:
425 case RENDERPATH_D3D10:
426 case RENDERPATH_D3D11:
427 r_shadow_shadowmapsampler = false;
428 r_shadow_shadowmappcf = 1;
429 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
431 case RENDERPATH_GL13:
433 case RENDERPATH_GL11:
439 qboolean R_Shadow_ShadowMappingEnabled(void)
441 switch (r_shadow_shadowmode)
443 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
450 void R_Shadow_FreeShadowMaps(void)
452 R_Shadow_SetShadowMode();
454 R_Mesh_DestroyFramebufferObject(r_shadow_fbo2d);
458 if (r_shadow_shadowmap2dtexture)
459 R_FreeTexture(r_shadow_shadowmap2dtexture);
460 r_shadow_shadowmap2dtexture = NULL;
462 if (r_shadow_shadowmap2dcolortexture)
463 R_FreeTexture(r_shadow_shadowmap2dcolortexture);
464 r_shadow_shadowmap2dcolortexture = NULL;
466 if (r_shadow_shadowmapvsdcttexture)
467 R_FreeTexture(r_shadow_shadowmapvsdcttexture);
468 r_shadow_shadowmapvsdcttexture = NULL;
471 void r_shadow_start(void)
473 // allocate vertex processing arrays
474 r_shadow_attenuationgradienttexture = NULL;
475 r_shadow_attenuation2dtexture = NULL;
476 r_shadow_attenuation3dtexture = NULL;
477 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
478 r_shadow_shadowmap2dtexture = NULL;
479 r_shadow_shadowmap2dcolortexture = NULL;
480 r_shadow_shadowmapvsdcttexture = NULL;
481 r_shadow_shadowmapmaxsize = 0;
482 r_shadow_shadowmapsize = 0;
483 r_shadow_shadowmaplod = 0;
484 r_shadow_shadowmapfilterquality = -1;
485 r_shadow_shadowmapdepthbits = 0;
486 r_shadow_shadowmapvsdct = false;
487 r_shadow_shadowmapsampler = false;
488 r_shadow_shadowmappcf = 0;
491 R_Shadow_FreeShadowMaps();
493 r_shadow_texturepool = NULL;
494 r_shadow_filters_texturepool = NULL;
495 R_Shadow_ValidateCvars();
496 R_Shadow_MakeTextures();
497 maxshadowtriangles = 0;
498 shadowelements = NULL;
499 maxshadowvertices = 0;
500 shadowvertex3f = NULL;
508 shadowmarklist = NULL;
513 shadowsideslist = NULL;
514 r_shadow_buffer_numleafpvsbytes = 0;
515 r_shadow_buffer_visitingleafpvs = NULL;
516 r_shadow_buffer_leafpvs = NULL;
517 r_shadow_buffer_leaflist = NULL;
518 r_shadow_buffer_numsurfacepvsbytes = 0;
519 r_shadow_buffer_surfacepvs = NULL;
520 r_shadow_buffer_surfacelist = NULL;
521 r_shadow_buffer_surfacesides = NULL;
522 r_shadow_buffer_numshadowtrispvsbytes = 0;
523 r_shadow_buffer_shadowtrispvs = NULL;
524 r_shadow_buffer_numlighttrispvsbytes = 0;
525 r_shadow_buffer_lighttrispvs = NULL;
527 r_shadow_usingdeferredprepass = false;
528 r_shadow_prepass_width = r_shadow_prepass_height = 0;
531 static void R_Shadow_FreeDeferred(void);
532 void r_shadow_shutdown(void)
535 R_Shadow_UncompileWorldLights();
537 R_Shadow_FreeShadowMaps();
539 r_shadow_usingdeferredprepass = false;
540 if (r_shadow_prepass_width)
541 R_Shadow_FreeDeferred();
542 r_shadow_prepass_width = r_shadow_prepass_height = 0;
545 r_shadow_attenuationgradienttexture = NULL;
546 r_shadow_attenuation2dtexture = NULL;
547 r_shadow_attenuation3dtexture = NULL;
548 R_FreeTexturePool(&r_shadow_texturepool);
549 R_FreeTexturePool(&r_shadow_filters_texturepool);
550 maxshadowtriangles = 0;
552 Mem_Free(shadowelements);
553 shadowelements = NULL;
555 Mem_Free(shadowvertex3f);
556 shadowvertex3f = NULL;
559 Mem_Free(vertexupdate);
562 Mem_Free(vertexremap);
568 Mem_Free(shadowmark);
571 Mem_Free(shadowmarklist);
572 shadowmarklist = NULL;
577 Mem_Free(shadowsides);
580 Mem_Free(shadowsideslist);
581 shadowsideslist = NULL;
582 r_shadow_buffer_numleafpvsbytes = 0;
583 if (r_shadow_buffer_visitingleafpvs)
584 Mem_Free(r_shadow_buffer_visitingleafpvs);
585 r_shadow_buffer_visitingleafpvs = NULL;
586 if (r_shadow_buffer_leafpvs)
587 Mem_Free(r_shadow_buffer_leafpvs);
588 r_shadow_buffer_leafpvs = NULL;
589 if (r_shadow_buffer_leaflist)
590 Mem_Free(r_shadow_buffer_leaflist);
591 r_shadow_buffer_leaflist = NULL;
592 r_shadow_buffer_numsurfacepvsbytes = 0;
593 if (r_shadow_buffer_surfacepvs)
594 Mem_Free(r_shadow_buffer_surfacepvs);
595 r_shadow_buffer_surfacepvs = NULL;
596 if (r_shadow_buffer_surfacelist)
597 Mem_Free(r_shadow_buffer_surfacelist);
598 r_shadow_buffer_surfacelist = NULL;
599 if (r_shadow_buffer_surfacesides)
600 Mem_Free(r_shadow_buffer_surfacesides);
601 r_shadow_buffer_surfacesides = NULL;
602 r_shadow_buffer_numshadowtrispvsbytes = 0;
603 if (r_shadow_buffer_shadowtrispvs)
604 Mem_Free(r_shadow_buffer_shadowtrispvs);
605 r_shadow_buffer_numlighttrispvsbytes = 0;
606 if (r_shadow_buffer_lighttrispvs)
607 Mem_Free(r_shadow_buffer_lighttrispvs);
610 void r_shadow_newmap(void)
612 if (r_shadow_lightcorona) R_SkinFrame_MarkUsed(r_shadow_lightcorona);
613 if (r_editlights_sprcursor) R_SkinFrame_MarkUsed(r_editlights_sprcursor);
614 if (r_editlights_sprlight) R_SkinFrame_MarkUsed(r_editlights_sprlight);
615 if (r_editlights_sprnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprnoshadowlight);
616 if (r_editlights_sprcubemaplight) R_SkinFrame_MarkUsed(r_editlights_sprcubemaplight);
617 if (r_editlights_sprcubemapnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprcubemapnoshadowlight);
618 if (r_editlights_sprselection) R_SkinFrame_MarkUsed(r_editlights_sprselection);
619 if (strncmp(cl.worldname, r_shadow_mapname, sizeof(r_shadow_mapname)))
620 R_Shadow_EditLights_Reload_f();
623 void R_Shadow_Init(void)
625 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
626 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
627 Cvar_RegisterVariable(&r_shadow_usenormalmap);
628 Cvar_RegisterVariable(&r_shadow_debuglight);
629 Cvar_RegisterVariable(&r_shadow_deferred);
630 Cvar_RegisterVariable(&r_shadow_deferred_8bitrange);
631 // Cvar_RegisterVariable(&r_shadow_deferred_fp);
632 Cvar_RegisterVariable(&r_shadow_gloss);
633 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
634 Cvar_RegisterVariable(&r_shadow_glossintensity);
635 Cvar_RegisterVariable(&r_shadow_glossexponent);
636 Cvar_RegisterVariable(&r_shadow_gloss2exponent);
637 Cvar_RegisterVariable(&r_shadow_glossexact);
638 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
639 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
640 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
641 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
642 Cvar_RegisterVariable(&r_shadow_projectdistance);
643 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
644 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
645 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
646 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
647 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
648 Cvar_RegisterVariable(&r_shadow_realtime_world);
649 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
650 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
651 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
652 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
653 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
654 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
655 Cvar_RegisterVariable(&r_shadow_scissor);
656 Cvar_RegisterVariable(&r_shadow_shadowmapping);
657 Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
658 Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
659 Cvar_RegisterVariable(&r_shadow_shadowmapping_depthbits);
660 Cvar_RegisterVariable(&r_shadow_shadowmapping_precision);
661 Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
662 Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
663 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
664 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
665 Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
666 Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
667 Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
668 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonfactor);
669 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonoffset);
670 Cvar_RegisterVariable(&r_shadow_polygonfactor);
671 Cvar_RegisterVariable(&r_shadow_polygonoffset);
672 Cvar_RegisterVariable(&r_shadow_texture3d);
673 Cvar_RegisterVariable(&r_coronas);
674 Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
675 Cvar_RegisterVariable(&r_coronas_occlusionquery);
676 Cvar_RegisterVariable(&gl_flashblend);
677 Cvar_RegisterVariable(&gl_ext_separatestencil);
678 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
679 if (gamemode == GAME_TENEBRAE)
681 Cvar_SetValue("r_shadow_gloss", 2);
682 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
684 R_Shadow_EditLights_Init();
685 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
686 maxshadowtriangles = 0;
687 shadowelements = NULL;
688 maxshadowvertices = 0;
689 shadowvertex3f = NULL;
697 shadowmarklist = NULL;
702 shadowsideslist = NULL;
703 r_shadow_buffer_numleafpvsbytes = 0;
704 r_shadow_buffer_visitingleafpvs = NULL;
705 r_shadow_buffer_leafpvs = NULL;
706 r_shadow_buffer_leaflist = NULL;
707 r_shadow_buffer_numsurfacepvsbytes = 0;
708 r_shadow_buffer_surfacepvs = NULL;
709 r_shadow_buffer_surfacelist = NULL;
710 r_shadow_buffer_surfacesides = NULL;
711 r_shadow_buffer_shadowtrispvs = NULL;
712 r_shadow_buffer_lighttrispvs = NULL;
713 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap, NULL, NULL);
716 matrix4x4_t matrix_attenuationxyz =
719 {0.5, 0.0, 0.0, 0.5},
720 {0.0, 0.5, 0.0, 0.5},
721 {0.0, 0.0, 0.5, 0.5},
726 matrix4x4_t matrix_attenuationz =
729 {0.0, 0.0, 0.5, 0.5},
730 {0.0, 0.0, 0.0, 0.5},
731 {0.0, 0.0, 0.0, 0.5},
736 void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles, int vertscale, int triscale)
738 numvertices = ((numvertices + 255) & ~255) * vertscale;
739 numtriangles = ((numtriangles + 255) & ~255) * triscale;
740 // make sure shadowelements is big enough for this volume
741 if (maxshadowtriangles < numtriangles)
743 maxshadowtriangles = numtriangles;
745 Mem_Free(shadowelements);
746 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[3]));
748 // make sure shadowvertex3f is big enough for this volume
749 if (maxshadowvertices < numvertices)
751 maxshadowvertices = numvertices;
753 Mem_Free(shadowvertex3f);
754 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[3]));
758 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
760 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
761 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
762 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
763 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
764 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
766 if (r_shadow_buffer_visitingleafpvs)
767 Mem_Free(r_shadow_buffer_visitingleafpvs);
768 if (r_shadow_buffer_leafpvs)
769 Mem_Free(r_shadow_buffer_leafpvs);
770 if (r_shadow_buffer_leaflist)
771 Mem_Free(r_shadow_buffer_leaflist);
772 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
773 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
774 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
775 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
777 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
779 if (r_shadow_buffer_surfacepvs)
780 Mem_Free(r_shadow_buffer_surfacepvs);
781 if (r_shadow_buffer_surfacelist)
782 Mem_Free(r_shadow_buffer_surfacelist);
783 if (r_shadow_buffer_surfacesides)
784 Mem_Free(r_shadow_buffer_surfacesides);
785 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
786 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
787 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
788 r_shadow_buffer_surfacesides = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
790 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
792 if (r_shadow_buffer_shadowtrispvs)
793 Mem_Free(r_shadow_buffer_shadowtrispvs);
794 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
795 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
797 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
799 if (r_shadow_buffer_lighttrispvs)
800 Mem_Free(r_shadow_buffer_lighttrispvs);
801 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
802 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
806 void R_Shadow_PrepareShadowMark(int numtris)
808 // make sure shadowmark is big enough for this volume
809 if (maxshadowmark < numtris)
811 maxshadowmark = numtris;
813 Mem_Free(shadowmark);
815 Mem_Free(shadowmarklist);
816 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
817 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
821 // if shadowmarkcount wrapped we clear the array and adjust accordingly
822 if (shadowmarkcount == 0)
825 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
830 void R_Shadow_PrepareShadowSides(int numtris)
832 if (maxshadowsides < numtris)
834 maxshadowsides = numtris;
836 Mem_Free(shadowsides);
838 Mem_Free(shadowsideslist);
839 shadowsides = (unsigned char *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsides));
840 shadowsideslist = (int *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsideslist));
845 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)
848 int outtriangles = 0, outvertices = 0;
851 float ratio, direction[3], projectvector[3];
853 if (projectdirection)
854 VectorScale(projectdirection, projectdistance, projectvector);
856 VectorClear(projectvector);
858 // create the vertices
859 if (projectdirection)
861 for (i = 0;i < numshadowmarktris;i++)
863 element = inelement3i + shadowmarktris[i] * 3;
864 for (j = 0;j < 3;j++)
866 if (vertexupdate[element[j]] != vertexupdatenum)
868 vertexupdate[element[j]] = vertexupdatenum;
869 vertexremap[element[j]] = outvertices;
870 vertex = invertex3f + element[j] * 3;
871 // project one copy of the vertex according to projectvector
872 VectorCopy(vertex, outvertex3f);
873 VectorAdd(vertex, projectvector, (outvertex3f + 3));
882 for (i = 0;i < numshadowmarktris;i++)
884 element = inelement3i + shadowmarktris[i] * 3;
885 for (j = 0;j < 3;j++)
887 if (vertexupdate[element[j]] != vertexupdatenum)
889 vertexupdate[element[j]] = vertexupdatenum;
890 vertexremap[element[j]] = outvertices;
891 vertex = invertex3f + element[j] * 3;
892 // project one copy of the vertex to the sphere radius of the light
893 // (FIXME: would projecting it to the light box be better?)
894 VectorSubtract(vertex, projectorigin, direction);
895 ratio = projectdistance / VectorLength(direction);
896 VectorCopy(vertex, outvertex3f);
897 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
905 if (r_shadow_frontsidecasting.integer)
907 for (i = 0;i < numshadowmarktris;i++)
909 int remappedelement[3];
911 const int *neighbortriangle;
913 markindex = shadowmarktris[i] * 3;
914 element = inelement3i + markindex;
915 neighbortriangle = inneighbor3i + markindex;
916 // output the front and back triangles
917 outelement3i[0] = vertexremap[element[0]];
918 outelement3i[1] = vertexremap[element[1]];
919 outelement3i[2] = vertexremap[element[2]];
920 outelement3i[3] = vertexremap[element[2]] + 1;
921 outelement3i[4] = vertexremap[element[1]] + 1;
922 outelement3i[5] = vertexremap[element[0]] + 1;
926 // output the sides (facing outward from this triangle)
927 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
929 remappedelement[0] = vertexremap[element[0]];
930 remappedelement[1] = vertexremap[element[1]];
931 outelement3i[0] = remappedelement[1];
932 outelement3i[1] = remappedelement[0];
933 outelement3i[2] = remappedelement[0] + 1;
934 outelement3i[3] = remappedelement[1];
935 outelement3i[4] = remappedelement[0] + 1;
936 outelement3i[5] = remappedelement[1] + 1;
941 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
943 remappedelement[1] = vertexremap[element[1]];
944 remappedelement[2] = vertexremap[element[2]];
945 outelement3i[0] = remappedelement[2];
946 outelement3i[1] = remappedelement[1];
947 outelement3i[2] = remappedelement[1] + 1;
948 outelement3i[3] = remappedelement[2];
949 outelement3i[4] = remappedelement[1] + 1;
950 outelement3i[5] = remappedelement[2] + 1;
955 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
957 remappedelement[0] = vertexremap[element[0]];
958 remappedelement[2] = vertexremap[element[2]];
959 outelement3i[0] = remappedelement[0];
960 outelement3i[1] = remappedelement[2];
961 outelement3i[2] = remappedelement[2] + 1;
962 outelement3i[3] = remappedelement[0];
963 outelement3i[4] = remappedelement[2] + 1;
964 outelement3i[5] = remappedelement[0] + 1;
973 for (i = 0;i < numshadowmarktris;i++)
975 int remappedelement[3];
977 const int *neighbortriangle;
979 markindex = shadowmarktris[i] * 3;
980 element = inelement3i + markindex;
981 neighbortriangle = inneighbor3i + markindex;
982 // output the front and back triangles
983 outelement3i[0] = vertexremap[element[2]];
984 outelement3i[1] = vertexremap[element[1]];
985 outelement3i[2] = vertexremap[element[0]];
986 outelement3i[3] = vertexremap[element[0]] + 1;
987 outelement3i[4] = vertexremap[element[1]] + 1;
988 outelement3i[5] = vertexremap[element[2]] + 1;
992 // output the sides (facing outward from this triangle)
993 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
995 remappedelement[0] = vertexremap[element[0]];
996 remappedelement[1] = vertexremap[element[1]];
997 outelement3i[0] = remappedelement[0];
998 outelement3i[1] = remappedelement[1];
999 outelement3i[2] = remappedelement[1] + 1;
1000 outelement3i[3] = remappedelement[0];
1001 outelement3i[4] = remappedelement[1] + 1;
1002 outelement3i[5] = remappedelement[0] + 1;
1007 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1009 remappedelement[1] = vertexremap[element[1]];
1010 remappedelement[2] = vertexremap[element[2]];
1011 outelement3i[0] = remappedelement[1];
1012 outelement3i[1] = remappedelement[2];
1013 outelement3i[2] = remappedelement[2] + 1;
1014 outelement3i[3] = remappedelement[1];
1015 outelement3i[4] = remappedelement[2] + 1;
1016 outelement3i[5] = remappedelement[1] + 1;
1021 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1023 remappedelement[0] = vertexremap[element[0]];
1024 remappedelement[2] = vertexremap[element[2]];
1025 outelement3i[0] = remappedelement[2];
1026 outelement3i[1] = remappedelement[0];
1027 outelement3i[2] = remappedelement[0] + 1;
1028 outelement3i[3] = remappedelement[2];
1029 outelement3i[4] = remappedelement[0] + 1;
1030 outelement3i[5] = remappedelement[2] + 1;
1038 *outnumvertices = outvertices;
1039 return outtriangles;
1042 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)
1045 int outtriangles = 0, outvertices = 0;
1047 const float *vertex;
1048 float ratio, direction[3], projectvector[3];
1051 if (projectdirection)
1052 VectorScale(projectdirection, projectdistance, projectvector);
1054 VectorClear(projectvector);
1056 for (i = 0;i < numshadowmarktris;i++)
1058 int remappedelement[3];
1060 const int *neighbortriangle;
1062 markindex = shadowmarktris[i] * 3;
1063 neighbortriangle = inneighbor3i + markindex;
1064 side[0] = shadowmark[neighbortriangle[0]] == shadowmarkcount;
1065 side[1] = shadowmark[neighbortriangle[1]] == shadowmarkcount;
1066 side[2] = shadowmark[neighbortriangle[2]] == shadowmarkcount;
1067 if (side[0] + side[1] + side[2] == 0)
1071 element = inelement3i + markindex;
1073 // create the vertices
1074 for (j = 0;j < 3;j++)
1076 if (side[j] + side[j+1] == 0)
1079 if (vertexupdate[k] != vertexupdatenum)
1081 vertexupdate[k] = vertexupdatenum;
1082 vertexremap[k] = outvertices;
1083 vertex = invertex3f + k * 3;
1084 VectorCopy(vertex, outvertex3f);
1085 if (projectdirection)
1087 // project one copy of the vertex according to projectvector
1088 VectorAdd(vertex, projectvector, (outvertex3f + 3));
1092 // project one copy of the vertex to the sphere radius of the light
1093 // (FIXME: would projecting it to the light box be better?)
1094 VectorSubtract(vertex, projectorigin, direction);
1095 ratio = projectdistance / VectorLength(direction);
1096 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1103 // output the sides (facing outward from this triangle)
1106 remappedelement[0] = vertexremap[element[0]];
1107 remappedelement[1] = vertexremap[element[1]];
1108 outelement3i[0] = remappedelement[1];
1109 outelement3i[1] = remappedelement[0];
1110 outelement3i[2] = remappedelement[0] + 1;
1111 outelement3i[3] = remappedelement[1];
1112 outelement3i[4] = remappedelement[0] + 1;
1113 outelement3i[5] = remappedelement[1] + 1;
1120 remappedelement[1] = vertexremap[element[1]];
1121 remappedelement[2] = vertexremap[element[2]];
1122 outelement3i[0] = remappedelement[2];
1123 outelement3i[1] = remappedelement[1];
1124 outelement3i[2] = remappedelement[1] + 1;
1125 outelement3i[3] = remappedelement[2];
1126 outelement3i[4] = remappedelement[1] + 1;
1127 outelement3i[5] = remappedelement[2] + 1;
1134 remappedelement[0] = vertexremap[element[0]];
1135 remappedelement[2] = vertexremap[element[2]];
1136 outelement3i[0] = remappedelement[0];
1137 outelement3i[1] = remappedelement[2];
1138 outelement3i[2] = remappedelement[2] + 1;
1139 outelement3i[3] = remappedelement[0];
1140 outelement3i[4] = remappedelement[2] + 1;
1141 outelement3i[5] = remappedelement[0] + 1;
1148 *outnumvertices = outvertices;
1149 return outtriangles;
1152 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)
1158 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1160 tend = firsttriangle + numtris;
1161 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1163 // surface box entirely inside light box, no box cull
1164 if (projectdirection)
1166 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1168 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
1169 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1170 shadowmarklist[numshadowmark++] = t;
1175 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1176 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
1177 shadowmarklist[numshadowmark++] = t;
1182 // surface box not entirely inside light box, cull each triangle
1183 if (projectdirection)
1185 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1187 v[0] = invertex3f + e[0] * 3;
1188 v[1] = invertex3f + e[1] * 3;
1189 v[2] = invertex3f + e[2] * 3;
1190 TriangleNormal(v[0], v[1], v[2], normal);
1191 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1192 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1193 shadowmarklist[numshadowmark++] = t;
1198 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1200 v[0] = invertex3f + e[0] * 3;
1201 v[1] = invertex3f + e[1] * 3;
1202 v[2] = invertex3f + e[2] * 3;
1203 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1204 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1205 shadowmarklist[numshadowmark++] = t;
1211 qboolean R_Shadow_UseZPass(vec3_t mins, vec3_t maxs)
1216 if (r_shadow_compilingrtlight || !r_shadow_frontsidecasting.integer || !r_shadow_usezpassifpossible.integer)
1218 // check if the shadow volume intersects the near plane
1220 // a ray between the eye and light origin may intersect the caster,
1221 // indicating that the shadow may touch the eye location, however we must
1222 // test the near plane (a polygon), not merely the eye location, so it is
1223 // easiest to enlarge the caster bounding shape slightly for this.
1229 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)
1231 int i, tris, outverts;
1232 if (projectdistance < 0.1)
1234 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
1237 if (!numverts || !nummarktris)
1239 // make sure shadowelements is big enough for this volume
1240 if (maxshadowtriangles < nummarktris*8 || maxshadowvertices < numverts*2)
1241 R_Shadow_ResizeShadowArrays(numverts, nummarktris, 2, 8);
1243 if (maxvertexupdate < numverts)
1245 maxvertexupdate = numverts;
1247 Mem_Free(vertexupdate);
1249 Mem_Free(vertexremap);
1250 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1251 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1252 vertexupdatenum = 0;
1255 if (vertexupdatenum == 0)
1257 vertexupdatenum = 1;
1258 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
1259 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
1262 for (i = 0;i < nummarktris;i++)
1263 shadowmark[marktris[i]] = shadowmarkcount;
1265 if (r_shadow_compilingrtlight)
1267 // if we're compiling an rtlight, capture the mesh
1268 //tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1269 //Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zpass, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1270 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1271 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zfail, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1273 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
1275 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1276 R_Mesh_PrepareVertices_Position_Arrays(outverts, shadowvertex3f);
1277 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1281 // decide which type of shadow to generate and set stencil mode
1282 R_Shadow_RenderMode_StencilShadowVolumes(R_Shadow_UseZPass(trismins, trismaxs));
1283 // generate the sides or a solid volume, depending on type
1284 if (r_shadow_rendermode >= R_SHADOW_RENDERMODE_ZPASS_STENCIL && r_shadow_rendermode <= R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE)
1285 tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1287 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1288 r_refdef.stats.lights_dynamicshadowtriangles += tris;
1289 r_refdef.stats.lights_shadowtriangles += tris;
1290 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
1292 // increment stencil if frontface is infront of depthbuffer
1293 GL_CullFace(r_refdef.view.cullface_front);
1294 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
1295 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1296 // decrement stencil if backface is infront of depthbuffer
1297 GL_CullFace(r_refdef.view.cullface_back);
1298 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
1300 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
1302 // decrement stencil if backface is behind depthbuffer
1303 GL_CullFace(r_refdef.view.cullface_front);
1304 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
1305 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1306 // increment stencil if frontface is behind depthbuffer
1307 GL_CullFace(r_refdef.view.cullface_back);
1308 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
1310 R_Mesh_PrepareVertices_Position_Arrays(outverts, shadowvertex3f);
1311 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, NULL, NULL, 0);
1315 int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias)
1317 // p1, p2, p3 are in the cubemap's local coordinate system
1318 // bias = border/(size - border)
1321 float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1322 dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2),
1323 dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3);
1324 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1326 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1327 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1328 | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1329 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1331 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1332 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1333 | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1335 dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1336 dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2),
1337 dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3);
1338 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1340 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1341 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1342 | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1343 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1345 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1346 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1347 | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1349 dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1350 dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2),
1351 dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3);
1352 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1354 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1355 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1356 | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1357 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1359 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1360 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1361 | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1366 int R_Shadow_CalcBBoxSideMask(const vec3_t mins, const vec3_t maxs, const matrix4x4_t *worldtolight, const matrix4x4_t *radiustolight, float bias)
1368 vec3_t center, radius, lightcenter, lightradius, pmin, pmax;
1369 float dp1, dn1, ap1, an1, dp2, dn2, ap2, an2;
1372 VectorSubtract(maxs, mins, radius);
1373 VectorScale(radius, 0.5f, radius);
1374 VectorAdd(mins, radius, center);
1375 Matrix4x4_Transform(worldtolight, center, lightcenter);
1376 Matrix4x4_Transform3x3(radiustolight, radius, lightradius);
1377 VectorSubtract(lightcenter, lightradius, pmin);
1378 VectorAdd(lightcenter, lightradius, pmax);
1380 dp1 = pmax[0] + pmax[1], dn1 = pmax[0] - pmin[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1381 dp2 = pmin[0] + pmin[1], dn2 = pmin[0] - pmax[1], ap2 = fabs(dp2), an2 = fabs(dn2);
1382 if(ap1 > bias*an1 && ap2 > bias*an2)
1384 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1385 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1386 if(an1 > bias*ap1 && an2 > bias*ap2)
1388 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1389 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1391 dp1 = pmax[1] + pmax[2], dn1 = pmax[1] - pmin[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1392 dp2 = pmin[1] + pmin[2], dn2 = pmin[1] - pmax[2], ap2 = fabs(dp2), an2 = fabs(dn2);
1393 if(ap1 > bias*an1 && ap2 > bias*an2)
1395 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1396 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1397 if(an1 > bias*ap1 && an2 > bias*ap2)
1399 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1400 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1402 dp1 = pmax[2] + pmax[0], dn1 = pmax[2] - pmin[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1403 dp2 = pmin[2] + pmin[0], dn2 = pmin[2] - pmax[0], ap2 = fabs(dp2), an2 = fabs(dn2);
1404 if(ap1 > bias*an1 && ap2 > bias*an2)
1406 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1407 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1408 if(an1 > bias*ap1 && an2 > bias*ap2)
1410 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1411 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1416 #define R_Shadow_CalcEntitySideMask(ent, worldtolight, radiustolight, bias) R_Shadow_CalcBBoxSideMask((ent)->mins, (ent)->maxs, worldtolight, radiustolight, bias)
1418 int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
1420 // p is in the cubemap's local coordinate system
1421 // bias = border/(size - border)
1422 float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn);
1423 float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn);
1424 float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn);
1426 if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
1427 if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
1428 if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
1429 if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
1430 if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
1431 if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
1435 int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
1439 int sides = 0x3F, masks[6] = { 3<<4, 3<<4, 3<<0, 3<<0, 3<<2, 3<<2 };
1440 float scale = (size - 2*border)/size, len;
1441 float bias = border / (float)(size - border), dp, dn, ap, an;
1442 // check if cone enclosing side would cross frustum plane
1443 scale = 2 / (scale*scale + 2);
1444 for (i = 0;i < 5;i++)
1446 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) > -0.03125)
1448 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[i].normal, n);
1449 len = scale*VectorLength2(n);
1450 if(n[0]*n[0] > len) sides &= n[0] < 0 ? ~(1<<0) : ~(2 << 0);
1451 if(n[1]*n[1] > len) sides &= n[1] < 0 ? ~(1<<2) : ~(2 << 2);
1452 if(n[2]*n[2] > len) sides &= n[2] < 0 ? ~(1<<4) : ~(2 << 4);
1454 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[4]) >= r_refdef.farclip - r_refdef.nearclip + 0.03125)
1456 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[4].normal, n);
1457 len = scale*VectorLength(n);
1458 if(n[0]*n[0] > len) sides &= n[0] >= 0 ? ~(1<<0) : ~(2 << 0);
1459 if(n[1]*n[1] > len) sides &= n[1] >= 0 ? ~(1<<2) : ~(2 << 2);
1460 if(n[2]*n[2] > len) sides &= n[2] >= 0 ? ~(1<<4) : ~(2 << 4);
1462 // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results
1463 // check if frustum corners/origin cross plane sides
1465 // infinite version, assumes frustum corners merely give direction and extend to infinite distance
1466 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.origin, p);
1467 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1468 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1469 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1470 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1471 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1472 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1473 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1474 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1475 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1476 for (i = 0;i < 4;i++)
1478 Matrix4x4_Transform(&rtlight->matrix_worldtolight, r_refdef.view.frustumcorner[i], n);
1479 VectorSubtract(n, p, n);
1480 dp = n[0] + n[1], dn = n[0] - n[1], ap = fabs(dp), an = fabs(dn);
1481 if(ap > 0) masks[0] |= dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2);
1482 if(an > 0) masks[1] |= dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2);
1483 dp = n[1] + n[2], dn = n[1] - n[2], ap = fabs(dp), an = fabs(dn);
1484 if(ap > 0) masks[2] |= dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4);
1485 if(an > 0) masks[3] |= dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4);
1486 dp = n[2] + n[0], dn = n[2] - n[0], ap = fabs(dp), an = fabs(dn);
1487 if(ap > 0) masks[4] |= dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0);
1488 if(an > 0) masks[5] |= dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0);
1491 // finite version, assumes corners are a finite distance from origin dependent on far plane
1492 for (i = 0;i < 5;i++)
1494 Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p);
1495 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn);
1496 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1497 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1498 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn);
1499 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1500 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1501 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn);
1502 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1503 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1506 return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5];
1509 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)
1517 int mask, surfacemask = 0;
1518 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1520 bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
1521 tend = firsttriangle + numtris;
1522 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1524 // surface box entirely inside light box, no box cull
1525 if (projectdirection)
1527 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1529 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1530 TriangleNormal(v[0], v[1], v[2], normal);
1531 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1533 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1534 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1535 surfacemask |= mask;
1538 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;
1539 shadowsides[numshadowsides] = mask;
1540 shadowsideslist[numshadowsides++] = t;
1547 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1549 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1550 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]))
1552 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1553 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1554 surfacemask |= mask;
1557 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;
1558 shadowsides[numshadowsides] = mask;
1559 shadowsideslist[numshadowsides++] = t;
1567 // surface box not entirely inside light box, cull each triangle
1568 if (projectdirection)
1570 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1572 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1573 TriangleNormal(v[0], v[1], v[2], normal);
1574 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1575 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1577 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1578 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1579 surfacemask |= mask;
1582 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;
1583 shadowsides[numshadowsides] = mask;
1584 shadowsideslist[numshadowsides++] = t;
1591 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1593 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1594 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1595 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1597 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1598 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1599 surfacemask |= mask;
1602 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;
1603 shadowsides[numshadowsides] = mask;
1604 shadowsideslist[numshadowsides++] = t;
1613 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)
1615 int i, j, outtriangles = 0;
1616 int *outelement3i[6];
1617 if (!numverts || !numsidetris || !r_shadow_compilingrtlight)
1619 outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5];
1620 // make sure shadowelements is big enough for this mesh
1621 if (maxshadowtriangles < outtriangles)
1622 R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1);
1624 // compute the offset and size of the separate index lists for each cubemap side
1626 for (i = 0;i < 6;i++)
1628 outelement3i[i] = shadowelements + outtriangles * 3;
1629 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles;
1630 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i];
1631 outtriangles += sidetotals[i];
1634 // gather up the (sparse) triangles into separate index lists for each cubemap side
1635 for (i = 0;i < numsidetris;i++)
1637 const int *element = elements + sidetris[i] * 3;
1638 for (j = 0;j < 6;j++)
1640 if (sides[i] & (1 << j))
1642 outelement3i[j][0] = element[0];
1643 outelement3i[j][1] = element[1];
1644 outelement3i[j][2] = element[2];
1645 outelement3i[j] += 3;
1650 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, outtriangles, shadowelements);
1653 static void R_Shadow_MakeTextures_MakeCorona(void)
1657 unsigned char pixels[32][32][4];
1658 for (y = 0;y < 32;y++)
1660 dy = (y - 15.5f) * (1.0f / 16.0f);
1661 for (x = 0;x < 32;x++)
1663 dx = (x - 15.5f) * (1.0f / 16.0f);
1664 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1665 a = bound(0, a, 255);
1666 pixels[y][x][0] = a;
1667 pixels[y][x][1] = a;
1668 pixels[y][x][2] = a;
1669 pixels[y][x][3] = 255;
1672 r_shadow_lightcorona = R_SkinFrame_LoadInternalBGRA("lightcorona", TEXF_FORCELINEAR, &pixels[0][0][0], 32, 32);
1675 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1677 float dist = sqrt(x*x+y*y+z*z);
1678 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1679 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1680 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1683 static void R_Shadow_MakeTextures(void)
1686 float intensity, dist;
1688 R_Shadow_FreeShadowMaps();
1689 R_FreeTexturePool(&r_shadow_texturepool);
1690 r_shadow_texturepool = R_AllocTexturePool();
1691 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1692 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1693 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1694 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1695 for (x = 0;x <= ATTENTABLESIZE;x++)
1697 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1698 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1699 r_shadow_attentable[x] = bound(0, intensity, 1);
1701 // 1D gradient texture
1702 for (x = 0;x < ATTEN1DSIZE;x++)
1703 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1704 r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1705 // 2D circle texture
1706 for (y = 0;y < ATTEN2DSIZE;y++)
1707 for (x = 0;x < ATTEN2DSIZE;x++)
1708 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);
1709 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, -1, NULL);
1710 // 3D sphere texture
1711 if (r_shadow_texture3d.integer && vid.support.ext_texture_3d)
1713 for (z = 0;z < ATTEN3DSIZE;z++)
1714 for (y = 0;y < ATTEN3DSIZE;y++)
1715 for (x = 0;x < ATTEN3DSIZE;x++)
1716 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));
1717 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);
1720 r_shadow_attenuation3dtexture = NULL;
1723 R_Shadow_MakeTextures_MakeCorona();
1725 // Editor light sprites
1726 r_editlights_sprcursor = R_SkinFrame_LoadInternal8bit("gfx/editlights/cursor", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1743 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1744 r_editlights_sprlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/light", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1761 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1762 r_editlights_sprnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/noshadow", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1779 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1780 r_editlights_sprcubemaplight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemaplight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1797 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1798 r_editlights_sprcubemapnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemapnoshadowlight", TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1815 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1816 r_editlights_sprselection = R_SkinFrame_LoadInternal8bit("gfx/editlights/selection", TEXF_ALPHA | TEXF_CLAMP, (unsigned char *)
1833 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1836 void R_Shadow_ValidateCvars(void)
1838 if (r_shadow_texture3d.integer && !vid.support.ext_texture_3d)
1839 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1840 if (gl_ext_separatestencil.integer && !vid.support.ati_separate_stencil)
1841 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
1842 if (gl_ext_stenciltwoside.integer && !vid.support.ext_stencil_two_side)
1843 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1846 //static const r_vertexposition_t resetvertexposition[3] = {{0, 0, 0}};
1848 void R_Shadow_RenderMode_Begin(void)
1854 R_Shadow_ValidateCvars();
1856 if (!r_shadow_attenuation2dtexture
1857 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1858 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1859 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1860 R_Shadow_MakeTextures();
1863 R_Mesh_ResetTextureState();
1864 // R_Mesh_PrepareVertices_Position(0, resetvertexposition, NULL);
1865 GL_BlendFunc(GL_ONE, GL_ZERO);
1866 GL_DepthRange(0, 1);
1867 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1869 GL_DepthMask(false);
1870 GL_Color(0, 0, 0, 1);
1871 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1873 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1875 if (gl_ext_separatestencil.integer && vid.support.ati_separate_stencil)
1877 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
1878 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
1880 else if (gl_ext_stenciltwoside.integer && vid.support.ext_stencil_two_side)
1882 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
1883 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
1887 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
1888 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
1891 switch(vid.renderpath)
1893 case RENDERPATH_GL20:
1894 case RENDERPATH_CGGL:
1895 case RENDERPATH_D3D9:
1896 case RENDERPATH_D3D10:
1897 case RENDERPATH_D3D11:
1898 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1900 case RENDERPATH_GL13:
1901 case RENDERPATH_GL11:
1902 if (r_textureunits.integer >= 2 && vid.texunits >= 2 && r_shadow_texture3d.integer && r_shadow_attenuation3dtexture)
1903 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN;
1904 else if (r_textureunits.integer >= 3 && vid.texunits >= 3)
1905 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN;
1906 else if (r_textureunits.integer >= 2 && vid.texunits >= 2)
1907 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN;
1909 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1915 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
1916 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
1917 r_shadow_drawbuffer = drawbuffer;
1918 r_shadow_readbuffer = readbuffer;
1920 r_shadow_cullface_front = r_refdef.view.cullface_front;
1921 r_shadow_cullface_back = r_refdef.view.cullface_back;
1924 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
1926 rsurface.rtlight = rtlight;
1929 void R_Shadow_RenderMode_Reset(void)
1931 R_Mesh_ResetRenderTargets();
1932 R_SetViewport(&r_refdef.view.viewport);
1933 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
1934 R_Mesh_ResetTextureState();
1935 // R_Mesh_PrepareVertices_Position(0, resetvertexposition, NULL);
1936 GL_DepthRange(0, 1);
1938 GL_DepthMask(false);
1939 GL_DepthFunc(GL_LEQUAL);
1940 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1941 r_refdef.view.cullface_front = r_shadow_cullface_front;
1942 r_refdef.view.cullface_back = r_shadow_cullface_back;
1943 GL_CullFace(r_refdef.view.cullface_back);
1944 GL_Color(1, 1, 1, 1);
1945 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
1946 GL_BlendFunc(GL_ONE, GL_ZERO);
1947 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
1948 r_shadow_usingshadowmap2d = false;
1949 r_shadow_usingshadowmaportho = false;
1950 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
1953 void R_Shadow_ClearStencil(void)
1955 GL_Clear(GL_STENCIL_BUFFER_BIT, NULL, 1.0f, 128);
1956 r_refdef.stats.lights_clears++;
1959 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
1961 r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
1962 if (r_shadow_rendermode == mode)
1964 R_Shadow_RenderMode_Reset();
1965 GL_DepthFunc(GL_LESS);
1966 GL_ColorMask(0, 0, 0, 0);
1967 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1968 GL_CullFace(GL_NONE);
1969 R_SetupShader_DepthOrShadow();
1970 r_shadow_rendermode = mode;
1975 case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
1976 case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
1977 R_SetStencilSeparate(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, GL_ALWAYS, 128, 255);
1979 case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
1980 case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
1981 R_SetStencilSeparate(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, GL_ALWAYS, 128, 255);
1986 static void R_Shadow_MakeVSDCT(void)
1988 // maps to a 2x3 texture rectangle with normalized coordinates
1993 // stores abs(dir.xy), offset.xy/2.5
1994 unsigned char data[4*6] =
1996 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
1997 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
1998 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
1999 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
2000 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
2001 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
2003 r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, -1, NULL);
2006 static void R_Shadow_MakeShadowMap(int side, int size)
2008 switch (r_shadow_shadowmode)
2010 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2011 if (r_shadow_shadowmap2dtexture) return;
2012 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);
2013 r_shadow_shadowmap2dcolortexture = NULL;
2014 switch(vid.renderpath)
2017 case RENDERPATH_D3D9:
2018 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);
2019 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
2023 r_shadow_fbo2d = R_Mesh_CreateFramebufferObject(r_shadow_shadowmap2dtexture, NULL, NULL, NULL, NULL);
2031 // render depth into the fbo, do not render color at all
2032 // validate the fbo now
2036 qglDrawBuffer(GL_NONE);CHECKGLERROR
2037 qglReadBuffer(GL_NONE);CHECKGLERROR
2038 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2039 if (status != GL_FRAMEBUFFER_COMPLETE_EXT && (r_shadow_shadowmapping.integer || r_shadow_deferred.integer))
2041 Con_Printf("R_Shadow_MakeShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2042 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2043 Cvar_SetValueQuick(&r_shadow_deferred, 0);
2048 static float testcolor[4] = {0,1,0,1};
2049 void R_Shadow_RenderMode_ShadowMap(int side, int clear, int size)
2051 float nearclip, farclip, bias;
2052 r_viewport_t viewport;
2055 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
2057 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
2058 r_shadow_shadowmap_parameters[1] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
2059 r_shadow_shadowmap_parameters[3] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
2060 r_shadow_shadowmapside = side;
2061 r_shadow_shadowmapsize = size;
2063 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2064 r_shadow_shadowmap_parameters[2] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2065 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
2066 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D) goto init_done;
2068 // complex unrolled cube approach (more flexible)
2069 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2070 R_Shadow_MakeVSDCT();
2071 if (!r_shadow_shadowmap2dtexture)
2072 R_Shadow_MakeShadowMap(side, r_shadow_shadowmapmaxsize);
2073 if (r_shadow_shadowmap2dtexture) fbo = r_shadow_fbo2d;
2074 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
2075 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
2076 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
2078 R_Mesh_ResetTextureState();
2079 R_Mesh_ResetRenderTargets();
2080 R_Shadow_RenderMode_Reset();
2083 R_Mesh_SetRenderTargets(fbo, r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
2084 R_SetupShader_DepthOrShadow();
2087 R_SetupShader_ShowDepth();
2088 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
2093 R_SetViewport(&viewport);
2094 flipped = (side & 1) ^ (side >> 2);
2095 r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
2096 r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
2097 switch(vid.renderpath)
2099 case RENDERPATH_GL11:
2100 case RENDERPATH_GL13:
2101 case RENDERPATH_GL20:
2102 case RENDERPATH_CGGL:
2103 GL_CullFace(r_refdef.view.cullface_back);
2104 // OpenGL lets us scissor larger than the viewport, so go ahead and clear all views at once
2105 if ((clear & ((2 << side) - 1)) == (1 << side)) // only clear if the side is the first in the mask
2107 // get tightest scissor rectangle that encloses all viewports in the clear mask
2108 int x1 = clear & 0x15 ? 0 : size;
2109 int x2 = clear & 0x2A ? 2 * size : size;
2110 int y1 = clear & 0x03 ? 0 : (clear & 0xC ? size : 2 * size);
2111 int y2 = clear & 0x30 ? 3 * size : (clear & 0xC ? 2 * size : size);
2112 GL_Scissor(x1, y1, x2 - x1, y2 - y1);
2113 GL_Clear(GL_DEPTH_BUFFER_BIT, NULL, 1.0f, 0);
2115 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2117 case RENDERPATH_D3D9:
2118 // completely different meaning than in OpenGL path
2119 r_shadow_shadowmap_parameters[1] = 0;
2120 r_shadow_shadowmap_parameters[3] = -bias;
2121 // we invert the cull mode because we flip the projection matrix
2122 // NOTE: this actually does nothing because the DrawShadowMap code sets it to doublesided...
2123 GL_CullFace(r_refdef.view.cullface_front);
2124 // D3D considers it an error to use a scissor larger than the viewport... clear just this view
2125 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2126 if (r_shadow_shadowmapsampler)
2128 GL_ColorMask(0,0,0,0);
2130 GL_Clear(GL_DEPTH_BUFFER_BIT, testcolor, 1.0f, 0);
2134 GL_ColorMask(1,1,1,1);
2136 GL_Clear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT, testcolor, 1.0f, 0);
2139 case RENDERPATH_D3D10:
2140 case RENDERPATH_D3D11:
2141 // D3D considers it an error to use a scissor larger than the viewport... clear just this view
2142 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2143 GL_ColorMask(0,0,0,0);
2145 GL_Clear(GL_DEPTH_BUFFER_BIT, NULL, 1.0f, 0);
2150 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
2152 R_Mesh_ResetTextureState();
2153 R_Mesh_ResetRenderTargets();
2156 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2157 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2158 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2159 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2161 R_Shadow_RenderMode_Reset();
2162 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2164 GL_DepthFunc(GL_EQUAL);
2165 // do global setup needed for the chosen lighting mode
2166 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2167 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2168 r_shadow_usingshadowmap2d = shadowmapping;
2169 r_shadow_rendermode = r_shadow_lightingrendermode;
2170 // only draw light where this geometry was already rendered AND the
2171 // stencil is 128 (values other than this mean shadow)
2173 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2175 R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
2178 static const unsigned short bboxelements[36] =
2188 static const float bboxpoints[8][3] =
2200 void R_Shadow_RenderMode_DrawDeferredLight(qboolean stenciltest, qboolean shadowmapping)
2203 float vertex3f[8*3];
2204 const matrix4x4_t *matrix = &rsurface.rtlight->matrix_lighttoworld;
2205 // do global setup needed for the chosen lighting mode
2206 R_Shadow_RenderMode_Reset();
2207 r_shadow_rendermode = r_shadow_lightingrendermode;
2208 R_EntityMatrix(&identitymatrix);
2209 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2210 // only draw light where this geometry was already rendered AND the
2211 // stencil is 128 (values other than this mean shadow)
2212 R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2213 R_Mesh_SetRenderTargets(r_shadow_prepasslightingfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
2215 r_shadow_usingshadowmap2d = shadowmapping;
2217 // render the lighting
2218 R_SetupShader_DeferredLight(rsurface.rtlight);
2219 for (i = 0;i < 8;i++)
2220 Matrix4x4_Transform(matrix, bboxpoints[i], vertex3f + i*3);
2221 GL_ColorMask(1,1,1,1);
2222 GL_DepthMask(false);
2223 GL_DepthRange(0, 1);
2224 GL_PolygonOffset(0, 0);
2226 GL_DepthFunc(GL_GREATER);
2227 GL_CullFace(r_refdef.view.cullface_back);
2228 R_Mesh_PrepareVertices_Position_Arrays(8, vertex3f);
2229 R_Mesh_Draw(0, 8, 0, 12, NULL, NULL, 0, bboxelements, NULL, 0);
2232 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
2234 R_Shadow_RenderMode_Reset();
2235 GL_BlendFunc(GL_ONE, GL_ONE);
2236 GL_DepthRange(0, 1);
2237 GL_DepthTest(r_showshadowvolumes.integer < 2);
2238 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
2239 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2240 GL_CullFace(GL_NONE);
2241 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
2244 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
2246 R_Shadow_RenderMode_Reset();
2247 GL_BlendFunc(GL_ONE, GL_ONE);
2248 GL_DepthRange(0, 1);
2249 GL_DepthTest(r_showlighting.integer < 2);
2250 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2252 GL_DepthFunc(GL_EQUAL);
2253 R_SetStencil(stenciltest, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_EQUAL, 128, 255);
2254 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2257 void R_Shadow_RenderMode_End(void)
2259 R_Shadow_RenderMode_Reset();
2260 R_Shadow_RenderMode_ActiveLight(NULL);
2262 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2263 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2266 int bboxedges[12][2] =
2285 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2287 int i, ix1, iy1, ix2, iy2;
2288 float x1, y1, x2, y2;
2290 float vertex[20][3];
2299 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2300 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2301 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2302 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2304 if (!r_shadow_scissor.integer)
2307 // if view is inside the light box, just say yes it's visible
2308 if (BoxesOverlap(r_refdef.view.origin, r_refdef.view.origin, mins, maxs))
2311 x1 = y1 = x2 = y2 = 0;
2313 // transform all corners that are infront of the nearclip plane
2314 VectorNegate(r_refdef.view.frustum[4].normal, plane4f);
2315 plane4f[3] = r_refdef.view.frustum[4].dist;
2317 for (i = 0;i < 8;i++)
2319 Vector4Set(corner[i], (i & 1) ? maxs[0] : mins[0], (i & 2) ? maxs[1] : mins[1], (i & 4) ? maxs[2] : mins[2], 1);
2320 dist[i] = DotProduct4(corner[i], plane4f);
2321 sign[i] = dist[i] > 0;
2324 VectorCopy(corner[i], vertex[numvertices]);
2328 // if some points are behind the nearclip, add clipped edge points to make
2329 // sure that the scissor boundary is complete
2330 if (numvertices > 0 && numvertices < 8)
2332 // add clipped edge points
2333 for (i = 0;i < 12;i++)
2335 j = bboxedges[i][0];
2336 k = bboxedges[i][1];
2337 if (sign[j] != sign[k])
2339 f = dist[j] / (dist[j] - dist[k]);
2340 VectorLerp(corner[j], f, corner[k], vertex[numvertices]);
2346 // if we have no points to check, the light is behind the view plane
2350 // if we have some points to transform, check what screen area is covered
2351 x1 = y1 = x2 = y2 = 0;
2353 //Con_Printf("%i vertices to transform...\n", numvertices);
2354 for (i = 0;i < numvertices;i++)
2356 VectorCopy(vertex[i], v);
2357 R_Viewport_TransformToScreen(&r_refdef.view.viewport, v, v2);
2358 //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]);
2361 if (x1 > v2[0]) x1 = v2[0];
2362 if (x2 < v2[0]) x2 = v2[0];
2363 if (y1 > v2[1]) y1 = v2[1];
2364 if (y2 < v2[1]) y2 = v2[1];
2373 // now convert the scissor rectangle to integer screen coordinates
2374 ix1 = (int)(x1 - 1.0f);
2375 iy1 = vid.height - (int)(y2 - 1.0f);
2376 ix2 = (int)(x2 + 1.0f);
2377 iy2 = vid.height - (int)(y1 + 1.0f);
2378 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
2380 // clamp it to the screen
2381 if (ix1 < r_refdef.view.viewport.x) ix1 = r_refdef.view.viewport.x;
2382 if (iy1 < r_refdef.view.viewport.y) iy1 = r_refdef.view.viewport.y;
2383 if (ix2 > r_refdef.view.viewport.x + r_refdef.view.viewport.width) ix2 = r_refdef.view.viewport.x + r_refdef.view.viewport.width;
2384 if (iy2 > r_refdef.view.viewport.y + r_refdef.view.viewport.height) iy2 = r_refdef.view.viewport.y + r_refdef.view.viewport.height;
2386 // if it is inside out, it's not visible
2387 if (ix2 <= ix1 || iy2 <= iy1)
2390 // the light area is visible, set up the scissor rectangle
2391 r_shadow_lightscissor[0] = ix1;
2392 r_shadow_lightscissor[1] = iy1;
2393 r_shadow_lightscissor[2] = ix2 - ix1;
2394 r_shadow_lightscissor[3] = iy2 - iy1;
2396 // D3D Y coordinate is top to bottom, OpenGL is bottom to top, fix the D3D one
2397 switch(vid.renderpath)
2399 case RENDERPATH_D3D9:
2400 case RENDERPATH_D3D10:
2401 case RENDERPATH_D3D11:
2402 r_shadow_lightscissor[1] = vid.height - r_shadow_lightscissor[1] - r_shadow_lightscissor[3];
2404 case RENDERPATH_GL11:
2405 case RENDERPATH_GL13:
2406 case RENDERPATH_GL20:
2407 case RENDERPATH_CGGL:
2411 r_refdef.stats.lights_scissored++;
2415 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, const float *diffusecolor, const float *ambientcolor)
2418 const float *vertex3f;
2419 const float *normal3f;
2421 float dist, dot, distintensity, shadeintensity, v[3], n[3];
2422 switch (r_shadow_rendermode)
2424 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2425 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2426 if (VectorLength2(diffusecolor) > 0)
2428 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)
2430 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2431 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2432 if ((dot = DotProduct(n, v)) < 0)
2434 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2435 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
2438 VectorCopy(ambientcolor, color4f);
2439 if (r_refdef.fogenabled)
2442 f = RSurf_FogVertex(vertex3f);
2443 VectorScale(color4f, f, color4f);
2450 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.array_passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
2452 VectorCopy(ambientcolor, color4f);
2453 if (r_refdef.fogenabled)
2456 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2457 f = RSurf_FogVertex(vertex3f);
2458 VectorScale(color4f + 4*i, f, color4f);
2464 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2465 if (VectorLength2(diffusecolor) > 0)
2467 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)
2469 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2470 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2472 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2473 if ((dot = DotProduct(n, v)) < 0)
2475 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2476 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2477 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2478 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2482 color4f[0] = ambientcolor[0] * distintensity;
2483 color4f[1] = ambientcolor[1] * distintensity;
2484 color4f[2] = ambientcolor[2] * distintensity;
2486 if (r_refdef.fogenabled)
2489 f = RSurf_FogVertex(vertex3f);
2490 VectorScale(color4f, f, color4f);
2494 VectorClear(color4f);
2500 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.array_passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
2502 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2503 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2505 color4f[0] = ambientcolor[0] * distintensity;
2506 color4f[1] = ambientcolor[1] * distintensity;
2507 color4f[2] = ambientcolor[2] * distintensity;
2508 if (r_refdef.fogenabled)
2511 f = RSurf_FogVertex(vertex3f);
2512 VectorScale(color4f, f, color4f);
2516 VectorClear(color4f);
2521 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2522 if (VectorLength2(diffusecolor) > 0)
2524 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)
2526 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2527 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2529 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2530 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2531 if ((dot = DotProduct(n, v)) < 0)
2533 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2534 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2535 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2536 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2540 color4f[0] = ambientcolor[0] * distintensity;
2541 color4f[1] = ambientcolor[1] * distintensity;
2542 color4f[2] = ambientcolor[2] * distintensity;
2544 if (r_refdef.fogenabled)
2547 f = RSurf_FogVertex(vertex3f);
2548 VectorScale(color4f, f, color4f);
2552 VectorClear(color4f);
2558 for (i = 0, vertex3f = rsurface.batchvertex3f + 3*firstvertex, color4f = rsurface.array_passcolor4f + 4 * firstvertex;i < numverts;i++, vertex3f += 3, color4f += 4)
2560 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2561 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2563 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2564 color4f[0] = ambientcolor[0] * distintensity;
2565 color4f[1] = ambientcolor[1] * distintensity;
2566 color4f[2] = ambientcolor[2] * distintensity;
2567 if (r_refdef.fogenabled)
2570 f = RSurf_FogVertex(vertex3f);
2571 VectorScale(color4f, f, color4f);
2575 VectorClear(color4f);
2585 static void R_Shadow_RenderLighting_VisibleLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
2587 // used to display how many times a surface is lit for level design purposes
2588 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
2589 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
2593 static void R_Shadow_RenderLighting_Light_GLSL(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale, float specularscale)
2595 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2596 R_SetupShader_Surface(lightcolor, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT, texturenumsurfaces, texturesurfacelist, NULL);
2597 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2598 GL_DepthFunc(GL_EQUAL);
2600 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2601 GL_DepthFunc(GL_LEQUAL);
2604 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
2611 int newnumtriangles;
2615 int maxtriangles = 4096;
2616 static int newelements[4096*3];
2617 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, diffusecolor2, ambientcolor2);
2618 for (renders = 0;renders < 4;renders++)
2623 newnumtriangles = 0;
2625 // due to low fillrate on the cards this vertex lighting path is
2626 // designed for, we manually cull all triangles that do not
2627 // contain a lit vertex
2628 // this builds batches of triangles from multiple surfaces and
2629 // renders them at once
2630 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
2632 if (VectorLength2(rsurface.array_passcolor4f + e[0] * 4) + VectorLength2(rsurface.array_passcolor4f + e[1] * 4) + VectorLength2(rsurface.array_passcolor4f + e[2] * 4) >= 0.01)
2634 if (newnumtriangles)
2636 newfirstvertex = min(newfirstvertex, e[0]);
2637 newlastvertex = max(newlastvertex, e[0]);
2641 newfirstvertex = e[0];
2642 newlastvertex = e[0];
2644 newfirstvertex = min(newfirstvertex, e[1]);
2645 newlastvertex = max(newlastvertex, e[1]);
2646 newfirstvertex = min(newfirstvertex, e[2]);
2647 newlastvertex = max(newlastvertex, e[2]);
2653 if (newnumtriangles >= maxtriangles)
2655 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
2656 newnumtriangles = 0;
2662 if (newnumtriangles >= 1)
2664 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, NULL, NULL, 0);
2667 // if we couldn't find any lit triangles, exit early
2670 // now reduce the intensity for the next overbright pass
2671 // we have to clamp to 0 here incase the drivers have improper
2672 // handling of negative colors
2673 // (some old drivers even have improper handling of >1 color)
2675 for (i = 0, c = rsurface.array_passcolor4f + 4 * firstvertex;i < numvertices;i++, c += 4)
2677 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
2679 c[0] = max(0, c[0] - 1);
2680 c[1] = max(0, c[1] - 1);
2681 c[2] = max(0, c[2] - 1);
2693 static void R_Shadow_RenderLighting_Light_Vertex(int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t lightcolor, float ambientscale, float diffusescale)
2695 // OpenGL 1.1 path (anything)
2696 float ambientcolorbase[3], diffusecolorbase[3];
2697 float ambientcolorpants[3], diffusecolorpants[3];
2698 float ambientcolorshirt[3], diffusecolorshirt[3];
2699 const float *surfacecolor = rsurface.texture->dlightcolor;
2700 const float *surfacepants = rsurface.colormap_pantscolor;
2701 const float *surfaceshirt = rsurface.colormap_shirtcolor;
2702 rtexture_t *basetexture = rsurface.texture->basetexture;
2703 rtexture_t *pantstexture = rsurface.texture->pantstexture;
2704 rtexture_t *shirttexture = rsurface.texture->shirttexture;
2705 qboolean dopants = pantstexture && VectorLength2(surfacepants) >= (1.0f / 1048576.0f);
2706 qboolean doshirt = shirttexture && VectorLength2(surfaceshirt) >= (1.0f / 1048576.0f);
2707 ambientscale *= 2 * r_refdef.view.colorscale;
2708 diffusescale *= 2 * r_refdef.view.colorscale;
2709 ambientcolorbase[0] = lightcolor[0] * ambientscale * surfacecolor[0];ambientcolorbase[1] = lightcolor[1] * ambientscale * surfacecolor[1];ambientcolorbase[2] = lightcolor[2] * ambientscale * surfacecolor[2];
2710 diffusecolorbase[0] = lightcolor[0] * diffusescale * surfacecolor[0];diffusecolorbase[1] = lightcolor[1] * diffusescale * surfacecolor[1];diffusecolorbase[2] = lightcolor[2] * diffusescale * surfacecolor[2];
2711 ambientcolorpants[0] = ambientcolorbase[0] * surfacepants[0];ambientcolorpants[1] = ambientcolorbase[1] * surfacepants[1];ambientcolorpants[2] = ambientcolorbase[2] * surfacepants[2];
2712 diffusecolorpants[0] = diffusecolorbase[0] * surfacepants[0];diffusecolorpants[1] = diffusecolorbase[1] * surfacepants[1];diffusecolorpants[2] = diffusecolorbase[2] * surfacepants[2];
2713 ambientcolorshirt[0] = ambientcolorbase[0] * surfaceshirt[0];ambientcolorshirt[1] = ambientcolorbase[1] * surfaceshirt[1];ambientcolorshirt[2] = ambientcolorbase[2] * surfaceshirt[2];
2714 diffusecolorshirt[0] = diffusecolorbase[0] * surfaceshirt[0];diffusecolorshirt[1] = diffusecolorbase[1] * surfaceshirt[1];diffusecolorshirt[2] = diffusecolorbase[2] * surfaceshirt[2];
2715 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | (diffusescale > 0 ? BATCHNEED_ARRAY_NORMAL : 0) | BATCHNEED_ARRAY_TEXCOORD, texturenumsurfaces, texturesurfacelist);
2716 R_Mesh_VertexPointer(3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
2717 R_Mesh_ColorPointer(4, GL_FLOAT, sizeof(float[4]), rsurface.array_passcolor4f, 0, 0);
2718 R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
2719 R_Mesh_TexBind(0, basetexture);
2720 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
2721 R_Mesh_TexCombine(0, GL_MODULATE, GL_MODULATE, 1, 1);
2722 switch(r_shadow_rendermode)
2724 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2725 R_Mesh_TexBind(1, r_shadow_attenuation3dtexture);
2726 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
2727 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
2728 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
2730 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2731 R_Mesh_TexBind(2, r_shadow_attenuation2dtexture);
2732 R_Mesh_TexMatrix(2, &rsurface.entitytoattenuationz);
2733 R_Mesh_TexCombine(2, GL_MODULATE, GL_MODULATE, 1, 1);
2734 R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
2736 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2737 R_Mesh_TexBind(1, r_shadow_attenuation2dtexture);
2738 R_Mesh_TexMatrix(1, &rsurface.entitytoattenuationxyz);
2739 R_Mesh_TexCombine(1, GL_MODULATE, GL_MODULATE, 1, 1);
2740 R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
2742 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2747 //R_Mesh_TexBind(0, basetexture);
2748 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorbase, ambientcolorbase);
2751 R_Mesh_TexBind(0, pantstexture);
2752 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorpants, ambientcolorpants);
2756 R_Mesh_TexBind(0, shirttexture);
2757 R_Shadow_RenderLighting_Light_Vertex_Pass(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchnumtriangles, rsurface.batchelement3i + 3*rsurface.batchfirsttriangle, diffusecolorshirt, ambientcolorshirt);
2761 extern cvar_t gl_lightmaps;
2762 void R_Shadow_RenderLighting(int texturenumsurfaces, const msurface_t **texturesurfacelist)
2764 float ambientscale, diffusescale, specularscale;
2766 float lightcolor[3];
2767 VectorCopy(rsurface.rtlight->currentcolor, lightcolor);
2768 ambientscale = rsurface.rtlight->ambientscale;
2769 diffusescale = rsurface.rtlight->diffusescale;
2770 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
2771 if (!r_shadow_usenormalmap.integer)
2773 ambientscale += 1.0f * diffusescale;
2777 if ((ambientscale + diffusescale) * VectorLength2(lightcolor) + specularscale * VectorLength2(lightcolor) < (1.0f / 1048576.0f))
2779 negated = (lightcolor[0] + lightcolor[1] + lightcolor[2] < 0) && vid.support.ext_blend_subtract;
2782 VectorNegate(lightcolor, lightcolor);
2783 switch(vid.renderpath)
2785 case RENDERPATH_GL11:
2786 case RENDERPATH_GL13:
2787 case RENDERPATH_GL20:
2788 case RENDERPATH_CGGL:
2789 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
2791 case RENDERPATH_D3D9:
2793 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_SUBTRACT);
2796 case RENDERPATH_D3D10:
2797 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2799 case RENDERPATH_D3D11:
2800 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2804 RSurf_SetupDepthAndCulling();
2805 switch (r_shadow_rendermode)
2807 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2808 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2809 R_Shadow_RenderLighting_VisibleLighting(texturenumsurfaces, texturesurfacelist);
2811 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2812 R_Shadow_RenderLighting_Light_GLSL(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale, specularscale);
2814 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2815 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2816 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2817 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2818 R_Shadow_RenderLighting_Light_Vertex(texturenumsurfaces, texturesurfacelist, lightcolor, ambientscale, diffusescale);
2821 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2826 switch(vid.renderpath)
2828 case RENDERPATH_GL11:
2829 case RENDERPATH_GL13:
2830 case RENDERPATH_GL20:
2831 case RENDERPATH_CGGL:
2832 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
2834 case RENDERPATH_D3D9:
2836 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_ADD);
2839 case RENDERPATH_D3D10:
2840 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2842 case RENDERPATH_D3D11:
2843 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
2849 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)
2851 matrix4x4_t tempmatrix = *matrix;
2852 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
2854 // if this light has been compiled before, free the associated data
2855 R_RTLight_Uncompile(rtlight);
2857 // clear it completely to avoid any lingering data
2858 memset(rtlight, 0, sizeof(*rtlight));
2860 // copy the properties
2861 rtlight->matrix_lighttoworld = tempmatrix;
2862 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
2863 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
2864 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
2865 VectorCopy(color, rtlight->color);
2866 rtlight->cubemapname[0] = 0;
2867 if (cubemapname && cubemapname[0])
2868 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
2869 rtlight->shadow = shadow;
2870 rtlight->corona = corona;
2871 rtlight->style = style;
2872 rtlight->isstatic = isstatic;
2873 rtlight->coronasizescale = coronasizescale;
2874 rtlight->ambientscale = ambientscale;
2875 rtlight->diffusescale = diffusescale;
2876 rtlight->specularscale = specularscale;
2877 rtlight->flags = flags;
2879 // compute derived data
2880 //rtlight->cullradius = rtlight->radius;
2881 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2882 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2883 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2884 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2885 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2886 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2887 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2890 // compiles rtlight geometry
2891 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2892 void R_RTLight_Compile(rtlight_t *rtlight)
2895 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
2896 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
2897 entity_render_t *ent = r_refdef.scene.worldentity;
2898 dp_model_t *model = r_refdef.scene.worldmodel;
2899 unsigned char *data;
2902 // compile the light
2903 rtlight->compiled = true;
2904 rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
2905 rtlight->static_numleafs = 0;
2906 rtlight->static_numleafpvsbytes = 0;
2907 rtlight->static_leaflist = NULL;
2908 rtlight->static_leafpvs = NULL;
2909 rtlight->static_numsurfaces = 0;
2910 rtlight->static_surfacelist = NULL;
2911 rtlight->static_shadowmap_receivers = 0x3F;
2912 rtlight->static_shadowmap_casters = 0x3F;
2913 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2914 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2915 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2916 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2917 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2918 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2920 if (model && model->GetLightInfo)
2922 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
2923 r_shadow_compilingrtlight = rtlight;
2924 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);
2925 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
2926 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
2927 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
2928 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
2929 rtlight->static_numsurfaces = numsurfaces;
2930 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
2931 rtlight->static_numleafs = numleafs;
2932 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
2933 rtlight->static_numleafpvsbytes = numleafpvsbytes;
2934 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
2935 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
2936 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
2937 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
2938 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
2939 if (rtlight->static_numsurfaces)
2940 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
2941 if (rtlight->static_numleafs)
2942 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
2943 if (rtlight->static_numleafpvsbytes)
2944 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
2945 if (rtlight->static_numshadowtrispvsbytes)
2946 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
2947 if (rtlight->static_numlighttrispvsbytes)
2948 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
2949 switch (rtlight->shadowmode)
2951 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
2952 if (model->CompileShadowMap && rtlight->shadow)
2953 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2956 if (model->CompileShadowVolume && rtlight->shadow)
2957 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
2960 // now we're done compiling the rtlight
2961 r_shadow_compilingrtlight = NULL;
2965 // use smallest available cullradius - box radius or light radius
2966 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
2967 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
2969 shadowzpasstris = 0;
2970 if (rtlight->static_meshchain_shadow_zpass)
2971 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
2972 shadowzpasstris += mesh->numtriangles;
2974 shadowzfailtris = 0;
2975 if (rtlight->static_meshchain_shadow_zfail)
2976 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
2977 shadowzfailtris += mesh->numtriangles;
2980 if (rtlight->static_numlighttrispvsbytes)
2981 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
2982 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
2986 if (rtlight->static_numlighttrispvsbytes)
2987 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
2988 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
2991 if (developer_extra.integer)
2992 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);
2995 void R_RTLight_Uncompile(rtlight_t *rtlight)
2997 if (rtlight->compiled)
2999 if (rtlight->static_meshchain_shadow_zpass)
3000 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
3001 rtlight->static_meshchain_shadow_zpass = NULL;
3002 if (rtlight->static_meshchain_shadow_zfail)
3003 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
3004 rtlight->static_meshchain_shadow_zfail = NULL;
3005 if (rtlight->static_meshchain_shadow_shadowmap)
3006 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
3007 rtlight->static_meshchain_shadow_shadowmap = NULL;
3008 // these allocations are grouped
3009 if (rtlight->static_surfacelist)
3010 Mem_Free(rtlight->static_surfacelist);
3011 rtlight->static_numleafs = 0;
3012 rtlight->static_numleafpvsbytes = 0;
3013 rtlight->static_leaflist = NULL;
3014 rtlight->static_leafpvs = NULL;
3015 rtlight->static_numsurfaces = 0;
3016 rtlight->static_surfacelist = NULL;
3017 rtlight->static_numshadowtrispvsbytes = 0;
3018 rtlight->static_shadowtrispvs = NULL;
3019 rtlight->static_numlighttrispvsbytes = 0;
3020 rtlight->static_lighttrispvs = NULL;
3021 rtlight->compiled = false;
3025 void R_Shadow_UncompileWorldLights(void)
3029 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3030 for (lightindex = 0;lightindex < range;lightindex++)
3032 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3035 R_RTLight_Uncompile(&light->rtlight);
3039 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3043 // reset the count of frustum planes
3044 // see rtlight->cached_frustumplanes definition for how much this array
3046 rtlight->cached_numfrustumplanes = 0;
3048 // haven't implemented a culling path for ortho rendering
3049 if (!r_refdef.view.useperspective)
3051 // check if the light is on screen and copy the 4 planes if it is
3052 for (i = 0;i < 4;i++)
3053 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3056 for (i = 0;i < 4;i++)
3057 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3062 // generate a deformed frustum that includes the light origin, this is
3063 // used to cull shadow casting surfaces that can not possibly cast a
3064 // shadow onto the visible light-receiving surfaces, which can be a
3067 // if the light origin is onscreen the result will be 4 planes exactly
3068 // if the light origin is offscreen on only one axis the result will
3069 // be exactly 5 planes (split-side case)
3070 // if the light origin is offscreen on two axes the result will be
3071 // exactly 4 planes (stretched corner case)
3072 for (i = 0;i < 4;i++)
3074 // quickly reject standard frustum planes that put the light
3075 // origin outside the frustum
3076 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3079 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3081 // if all the standard frustum planes were accepted, the light is onscreen
3082 // otherwise we need to generate some more planes below...
3083 if (rtlight->cached_numfrustumplanes < 4)
3085 // at least one of the stock frustum planes failed, so we need to
3086 // create one or two custom planes to enclose the light origin
3087 for (i = 0;i < 4;i++)
3089 // create a plane using the view origin and light origin, and a
3090 // single point from the frustum corner set
3091 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3092 VectorNormalize(plane.normal);
3093 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3094 // see if this plane is backwards and flip it if so
3095 for (j = 0;j < 4;j++)
3096 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3100 VectorNegate(plane.normal, plane.normal);
3102 // flipped plane, test again to see if it is now valid
3103 for (j = 0;j < 4;j++)
3104 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3106 // if the plane is still not valid, then it is dividing the
3107 // frustum and has to be rejected
3111 // we have created a valid plane, compute extra info
3112 PlaneClassify(&plane);
3114 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3116 // if we've found 5 frustum planes then we have constructed a
3117 // proper split-side case and do not need to keep searching for
3118 // planes to enclose the light origin
3119 if (rtlight->cached_numfrustumplanes == 5)
3127 for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
3129 plane = rtlight->cached_frustumplanes[i];
3130 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));
3135 // now add the light-space box planes if the light box is rotated, as any
3136 // caster outside the oriented light box is irrelevant (even if it passed
3137 // the worldspace light box, which is axial)
3138 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3140 for (i = 0;i < 6;i++)
3144 v[i >> 1] = (i & 1) ? -1 : 1;
3145 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3146 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3147 plane.dist = VectorNormalizeLength(plane.normal);
3148 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3149 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3155 // add the world-space reduced box planes
3156 for (i = 0;i < 6;i++)
3158 VectorClear(plane.normal);
3159 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3160 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
3161 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3170 // reduce all plane distances to tightly fit the rtlight cull box, which
3172 VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3173 VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3174 VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3175 VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3176 VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3177 VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3178 VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3179 VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3180 oldnum = rtlight->cached_numfrustumplanes;
3181 rtlight->cached_numfrustumplanes = 0;
3182 for (j = 0;j < oldnum;j++)
3184 // find the nearest point on the box to this plane
3185 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
3186 for (i = 1;i < 8;i++)
3188 dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
3189 if (bestdist > dist)
3192 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);
3193 // if the nearest point is near or behind the plane, we want this
3194 // plane, otherwise the plane is useless as it won't cull anything
3195 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
3197 PlaneClassify(&rtlight->cached_frustumplanes[j]);
3198 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
3205 void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
3209 RSurf_ActiveWorldEntity();
3211 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3214 GL_CullFace(GL_NONE);
3215 mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3216 for (;mesh;mesh = mesh->next)
3218 if (!mesh->sidetotals[r_shadow_shadowmapside])
3220 r_refdef.stats.lights_shadowtriangles += mesh->sidetotals[r_shadow_shadowmapside];
3221 R_Mesh_PrepareVertices_Position(mesh->numverts, mesh->vertexposition, mesh->vertexpositionbuffer);
3222 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);
3226 else if (r_refdef.scene.worldentity->model)
3227 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);
3229 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3232 void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3234 qboolean zpass = false;
3237 int surfacelistindex;
3238 msurface_t *surface;
3240 RSurf_ActiveWorldEntity();
3242 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3245 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
3247 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
3248 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
3250 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
3251 for (;mesh;mesh = mesh->next)
3253 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
3254 R_Mesh_PrepareVertices_Position(mesh->numverts, mesh->vertexposition, mesh->vertexpositionbuffer);
3255 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
3257 // increment stencil if frontface is infront of depthbuffer
3258 GL_CullFace(r_refdef.view.cullface_back);
3259 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_INCR, GL_ALWAYS, 128, 255);
3260 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);
3261 // decrement stencil if backface is infront of depthbuffer
3262 GL_CullFace(r_refdef.view.cullface_front);
3263 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_DECR, GL_ALWAYS, 128, 255);
3265 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
3267 // decrement stencil if backface is behind depthbuffer
3268 GL_CullFace(r_refdef.view.cullface_front);
3269 R_SetStencil(true, 255, GL_KEEP, GL_DECR, GL_KEEP, GL_ALWAYS, 128, 255);
3270 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);
3271 // increment stencil if frontface is behind depthbuffer
3272 GL_CullFace(r_refdef.view.cullface_back);
3273 R_SetStencil(true, 255, GL_KEEP, GL_INCR, GL_KEEP, GL_ALWAYS, 128, 255);
3275 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);
3279 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh)
3281 // use the shadow trispvs calculated earlier by GetLightInfo to cull world triangles on this dynamic light
3282 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
3283 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
3285 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
3286 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
3287 if (CHECKPVSBIT(trispvs, t))
3288 shadowmarklist[numshadowmark++] = t;
3290 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);
3292 else if (numsurfaces)
3293 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);
3295 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3298 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3300 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3301 vec_t relativeshadowradius;
3302 RSurf_ActiveModelEntity(ent, false, false, false);
3303 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3304 // we need to re-init the shader for each entity because the matrix changed
3305 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3306 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3307 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3308 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3309 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3310 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3311 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3312 switch (r_shadow_rendermode)
3314 case R_SHADOW_RENDERMODE_SHADOWMAP2D:
3315 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
3318 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3321 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3324 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3326 // set up properties for rendering light onto this entity
3327 RSurf_ActiveModelEntity(ent, true, true, false);
3328 GL_AlphaTest(false);
3329 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3330 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3331 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3332 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3335 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *lighttrispvs)
3337 if (!r_refdef.scene.worldmodel->DrawLight)
3340 // set up properties for rendering light onto this entity
3341 RSurf_ActiveWorldEntity();
3342 GL_AlphaTest(false);
3343 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3344 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3345 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3346 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3348 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, lighttrispvs);
3350 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3353 void R_Shadow_DrawEntityLight(entity_render_t *ent)
3355 dp_model_t *model = ent->model;
3356 if (!model->DrawLight)
3359 R_Shadow_SetupEntityLight(ent);
3361 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3363 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3366 void R_Shadow_PrepareLight(rtlight_t *rtlight)
3370 int numleafs, numsurfaces;
3371 int *leaflist, *surfacelist;
3372 unsigned char *leafpvs;
3373 unsigned char *shadowtrispvs;
3374 unsigned char *lighttrispvs;
3375 //unsigned char *surfacesides;
3376 int numlightentities;
3377 int numlightentities_noselfshadow;
3378 int numshadowentities;
3379 int numshadowentities_noselfshadow;
3380 static entity_render_t *lightentities[MAX_EDICTS];
3381 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3382 static entity_render_t *shadowentities[MAX_EDICTS];
3383 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3386 rtlight->draw = false;
3388 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3389 // skip lights that are basically invisible (color 0 0 0)
3390 nolight = VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f);
3392 // loading is done before visibility checks because loading should happen
3393 // all at once at the start of a level, not when it stalls gameplay.
3394 // (especially important to benchmarks)
3396 if (rtlight->isstatic && !nolight && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
3398 if (rtlight->compiled)
3399 R_RTLight_Uncompile(rtlight);
3400 R_RTLight_Compile(rtlight);
3404 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_GetCubemap(rtlight->cubemapname) : r_texture_whitecube;
3406 // look up the light style value at this time
3407 f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3408 VectorScale(rtlight->color, f, rtlight->currentcolor);
3410 if (rtlight->selected)
3412 f = 2 + sin(realtime * M_PI * 4.0);
3413 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3417 // if lightstyle is currently off, don't draw the light
3418 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3421 // skip processing on corona-only lights
3425 // if the light box is offscreen, skip it
3426 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3429 VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
3430 VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
3432 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3434 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3436 // compiled light, world available and can receive realtime lighting
3437 // retrieve leaf information
3438 numleafs = rtlight->static_numleafs;
3439 leaflist = rtlight->static_leaflist;
3440 leafpvs = rtlight->static_leafpvs;
3441 numsurfaces = rtlight->static_numsurfaces;
3442 surfacelist = rtlight->static_surfacelist;
3443 //surfacesides = NULL;
3444 shadowtrispvs = rtlight->static_shadowtrispvs;
3445 lighttrispvs = rtlight->static_lighttrispvs;
3447 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3449 // dynamic light, world available and can receive realtime lighting
3450 // calculate lit surfaces and leafs
3451 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);
3452 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3453 leaflist = r_shadow_buffer_leaflist;
3454 leafpvs = r_shadow_buffer_leafpvs;
3455 surfacelist = r_shadow_buffer_surfacelist;
3456 //surfacesides = r_shadow_buffer_surfacesides;
3457 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3458 lighttrispvs = r_shadow_buffer_lighttrispvs;
3459 // if the reduced leaf bounds are offscreen, skip it
3460 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3471 //surfacesides = NULL;
3472 shadowtrispvs = NULL;
3473 lighttrispvs = NULL;
3475 // check if light is illuminating any visible leafs
3478 for (i = 0;i < numleafs;i++)
3479 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3485 // make a list of lit entities and shadow casting entities
3486 numlightentities = 0;
3487 numlightentities_noselfshadow = 0;
3488 numshadowentities = 0;
3489 numshadowentities_noselfshadow = 0;
3491 // add dynamic entities that are lit by the light
3492 for (i = 0;i < r_refdef.scene.numentities;i++)
3495 entity_render_t *ent = r_refdef.scene.entities[i];
3497 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3499 // skip the object entirely if it is not within the valid
3500 // shadow-casting region (which includes the lit region)
3501 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
3503 if (!(model = ent->model))
3505 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
3507 // this entity wants to receive light, is visible, and is
3508 // inside the light box
3509 // TODO: check if the surfaces in the model can receive light
3510 // so now check if it's in a leaf seen by the light
3511 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))
3513 if (ent->flags & RENDER_NOSELFSHADOW)
3514 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
3516 lightentities[numlightentities++] = ent;
3517 // since it is lit, it probably also casts a shadow...
3518 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3519 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3520 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3522 // note: exterior models without the RENDER_NOSELFSHADOW
3523 // flag still create a RENDER_NOSELFSHADOW shadow but
3524 // are lit normally, this means that they are
3525 // self-shadowing but do not shadow other
3526 // RENDER_NOSELFSHADOW entities such as the gun
3527 // (very weird, but keeps the player shadow off the gun)
3528 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3529 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3531 shadowentities[numshadowentities++] = ent;
3534 else if (ent->flags & RENDER_SHADOW)
3536 // this entity is not receiving light, but may still need to
3538 // TODO: check if the surfaces in the model can cast shadow
3539 // now check if it is in a leaf seen by the light
3540 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))
3542 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3543 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3544 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3546 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3547 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3549 shadowentities[numshadowentities++] = ent;
3554 // return if there's nothing at all to light
3555 if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
3558 // count this light in the r_speeds
3559 r_refdef.stats.lights++;
3561 // flag it as worth drawing later
3562 rtlight->draw = true;
3564 // cache all the animated entities that cast a shadow but are not visible
3565 for (i = 0;i < numshadowentities;i++)
3566 if (!shadowentities[i]->animcache_vertex3f)
3567 R_AnimCache_GetEntity(shadowentities[i], false, false);
3568 for (i = 0;i < numshadowentities_noselfshadow;i++)
3569 if (!shadowentities_noselfshadow[i]->animcache_vertex3f)
3570 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
3572 // allocate some temporary memory for rendering this light later in the frame
3573 // reusable buffers need to be copied, static data can be used as-is
3574 rtlight->cached_numlightentities = numlightentities;
3575 rtlight->cached_numlightentities_noselfshadow = numlightentities_noselfshadow;
3576 rtlight->cached_numshadowentities = numshadowentities;
3577 rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
3578 rtlight->cached_numsurfaces = numsurfaces;
3579 rtlight->cached_lightentities = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
3580 rtlight->cached_lightentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
3581 rtlight->cached_shadowentities = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
3582 rtlight->cached_shadowentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
3583 if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
3585 int numshadowtrispvsbytes = (((r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles) + 7) >> 3);
3586 int numlighttrispvsbytes = ((r_refdef.scene.worldmodel->surfmesh.num_triangles + 7) >> 3);
3587 rtlight->cached_shadowtrispvs = (unsigned char *)R_FrameData_Store(numshadowtrispvsbytes, shadowtrispvs);
3588 rtlight->cached_lighttrispvs = (unsigned char *)R_FrameData_Store(numlighttrispvsbytes, lighttrispvs);
3589 rtlight->cached_surfacelist = (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
3593 // compiled light data
3594 rtlight->cached_shadowtrispvs = shadowtrispvs;
3595 rtlight->cached_lighttrispvs = lighttrispvs;
3596 rtlight->cached_surfacelist = surfacelist;
3600 void R_Shadow_DrawLight(rtlight_t *rtlight)
3604 unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
3605 int numlightentities;
3606 int numlightentities_noselfshadow;
3607 int numshadowentities;
3608 int numshadowentities_noselfshadow;
3609 entity_render_t **lightentities;
3610 entity_render_t **lightentities_noselfshadow;
3611 entity_render_t **shadowentities;
3612 entity_render_t **shadowentities_noselfshadow;
3614 static unsigned char entitysides[MAX_EDICTS];
3615 static unsigned char entitysides_noselfshadow[MAX_EDICTS];
3616 vec3_t nearestpoint;
3618 qboolean castshadows;
3621 // check if we cached this light this frame (meaning it is worth drawing)
3625 // if R_FrameData_Store ran out of space we skip anything dependent on it
3626 if (r_framedata_failed)
3629 numlightentities = rtlight->cached_numlightentities;
3630 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
3631 numshadowentities = rtlight->cached_numshadowentities;
3632 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
3633 numsurfaces = rtlight->cached_numsurfaces;
3634 lightentities = rtlight->cached_lightentities;
3635 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
3636 shadowentities = rtlight->cached_shadowentities;
3637 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
3638 shadowtrispvs = rtlight->cached_shadowtrispvs;
3639 lighttrispvs = rtlight->cached_lighttrispvs;
3640 surfacelist = rtlight->cached_surfacelist;
3642 // set up a scissor rectangle for this light
3643 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3646 // don't let sound skip if going slow
3647 if (r_refdef.scene.extraupdate)
3650 // make this the active rtlight for rendering purposes
3651 R_Shadow_RenderMode_ActiveLight(rtlight);
3653 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
3655 // optionally draw visible shape of the shadow volumes
3656 // for performance analysis by level designers
3657 R_Shadow_RenderMode_VisibleShadowVolumes();
3659 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
3660 for (i = 0;i < numshadowentities;i++)
3661 R_Shadow_DrawEntityShadow(shadowentities[i]);
3662 for (i = 0;i < numshadowentities_noselfshadow;i++)
3663 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3664 R_Shadow_RenderMode_VisibleLighting(false, false);
3667 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
3669 // optionally draw the illuminated areas
3670 // for performance analysis by level designers
3671 R_Shadow_RenderMode_VisibleLighting(false, false);
3673 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3674 for (i = 0;i < numlightentities;i++)
3675 R_Shadow_DrawEntityLight(lightentities[i]);
3676 for (i = 0;i < numlightentities_noselfshadow;i++)
3677 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3680 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
3682 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
3683 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
3684 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
3685 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
3687 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance/rtlight->radius));
3688 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
3689 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
3691 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
3697 int receivermask = 0;
3698 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
3699 Matrix4x4_Abs(&radiustolight);
3701 r_shadow_shadowmaplod = 0;
3702 for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
3703 if ((r_shadow_shadowmapmaxsize >> i) > lodlinear)
3704 r_shadow_shadowmaplod = i;
3706 size = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
3708 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
3710 surfacesides = NULL;
3713 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3715 castermask = rtlight->static_shadowmap_casters;
3716 receivermask = rtlight->static_shadowmap_receivers;
3720 surfacesides = r_shadow_buffer_surfacesides;
3721 for(i = 0;i < numsurfaces;i++)
3723 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
3724 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3725 castermask |= surfacesides[i];
3726 receivermask |= surfacesides[i];
3730 if (receivermask < 0x3F)
3732 for (i = 0;i < numlightentities;i++)
3733 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3734 if (receivermask < 0x3F)
3735 for(i = 0; i < numlightentities_noselfshadow;i++)
3736 receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3739 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
3743 for (i = 0;i < numshadowentities;i++)
3744 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3745 for (i = 0;i < numshadowentities_noselfshadow;i++)
3746 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3749 //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
3751 // render shadow casters into 6 sided depth texture
3752 for (side = 0;side < 6;side++) if (receivermask & (1 << side))
3754 R_Shadow_RenderMode_ShadowMap(side, receivermask, size);
3755 if (! (castermask & (1 << side))) continue;
3757 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
3758 for (i = 0;i < numshadowentities;i++) if (entitysides[i] & (1 << side))
3759 R_Shadow_DrawEntityShadow(shadowentities[i]);
3762 if (numlightentities_noselfshadow)
3764 // render lighting using the depth texture as shadowmap
3765 // draw lighting in the unmasked areas
3766 R_Shadow_RenderMode_Lighting(false, false, true);
3767 for (i = 0;i < numlightentities_noselfshadow;i++)
3768 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3771 // render shadow casters into 6 sided depth texture
3772 if (numshadowentities_noselfshadow)
3774 for (side = 0;side < 6;side++) if ((receivermask & castermask) & (1 << side))
3776 R_Shadow_RenderMode_ShadowMap(side, 0, size);
3777 for (i = 0;i < numshadowentities_noselfshadow;i++) if (entitysides_noselfshadow[i] & (1 << side))
3778 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3782 // render lighting using the depth texture as shadowmap
3783 // draw lighting in the unmasked areas
3784 R_Shadow_RenderMode_Lighting(false, false, true);
3785 // draw lighting in the unmasked areas
3787 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3788 for (i = 0;i < numlightentities;i++)
3789 R_Shadow_DrawEntityLight(lightentities[i]);
3791 else if (castshadows && vid.stencil)
3793 // draw stencil shadow volumes to mask off pixels that are in shadow
3794 // so that they won't receive lighting
3795 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
3796 R_Shadow_ClearStencil();
3799 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
3800 for (i = 0;i < numshadowentities;i++)
3801 R_Shadow_DrawEntityShadow(shadowentities[i]);
3803 // draw lighting in the unmasked areas
3804 R_Shadow_RenderMode_Lighting(true, false, false);
3805 for (i = 0;i < numlightentities_noselfshadow;i++)
3806 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3808 for (i = 0;i < numshadowentities_noselfshadow;i++)
3809 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3811 // draw lighting in the unmasked areas
3812 R_Shadow_RenderMode_Lighting(true, false, false);
3814 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3815 for (i = 0;i < numlightentities;i++)
3816 R_Shadow_DrawEntityLight(lightentities[i]);
3820 // draw lighting in the unmasked areas
3821 R_Shadow_RenderMode_Lighting(false, false, false);
3823 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3824 for (i = 0;i < numlightentities;i++)
3825 R_Shadow_DrawEntityLight(lightentities[i]);
3826 for (i = 0;i < numlightentities_noselfshadow;i++)
3827 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3830 if (r_shadow_usingdeferredprepass)
3832 // when rendering deferred lighting, we simply rasterize the box
3833 if (castshadows && r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
3834 R_Shadow_RenderMode_DrawDeferredLight(false, true);
3835 else if (castshadows && vid.stencil)
3836 R_Shadow_RenderMode_DrawDeferredLight(true, false);
3838 R_Shadow_RenderMode_DrawDeferredLight(false, false);
3842 static void R_Shadow_FreeDeferred(void)
3844 R_Mesh_DestroyFramebufferObject(r_shadow_prepassgeometryfbo);
3845 r_shadow_prepassgeometryfbo = 0;
3847 R_Mesh_DestroyFramebufferObject(r_shadow_prepasslightingfbo);
3848 r_shadow_prepasslightingfbo = 0;
3850 if (r_shadow_prepassgeometrydepthtexture)
3851 R_FreeTexture(r_shadow_prepassgeometrydepthtexture);
3852 r_shadow_prepassgeometrydepthtexture = NULL;
3854 if (r_shadow_prepassgeometrynormalmaptexture)
3855 R_FreeTexture(r_shadow_prepassgeometrynormalmaptexture);
3856 r_shadow_prepassgeometrynormalmaptexture = NULL;
3858 if (r_shadow_prepasslightingdiffusetexture)
3859 R_FreeTexture(r_shadow_prepasslightingdiffusetexture);
3860 r_shadow_prepasslightingdiffusetexture = NULL;
3862 if (r_shadow_prepasslightingspeculartexture)
3863 R_FreeTexture(r_shadow_prepasslightingspeculartexture);
3864 r_shadow_prepasslightingspeculartexture = NULL;
3867 void R_Shadow_DrawPrepass(void)
3875 entity_render_t *ent;
3876 float clearcolor[4];
3878 GL_AlphaTest(false);
3879 R_Mesh_ResetTextureState();
3881 GL_ColorMask(1,1,1,1);
3882 GL_BlendFunc(GL_ONE, GL_ZERO);
3885 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
3886 Vector4Set(clearcolor, 0.5f,0.5f,0.5f,1.0f);
3887 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, clearcolor, 1.0f, 0);
3888 if (r_timereport_active)
3889 R_TimeReport("prepasscleargeom");
3891 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawPrepass)
3892 r_refdef.scene.worldmodel->DrawPrepass(r_refdef.scene.worldentity);
3893 if (r_timereport_active)
3894 R_TimeReport("prepassworld");
3896 for (i = 0;i < r_refdef.scene.numentities;i++)
3898 if (!r_refdef.viewcache.entityvisible[i])
3900 ent = r_refdef.scene.entities[i];
3901 if (ent->model && ent->model->DrawPrepass != NULL)
3902 ent->model->DrawPrepass(ent);
3905 if (r_timereport_active)
3906 R_TimeReport("prepassmodels");
3908 GL_DepthMask(false);
3909 GL_ColorMask(1,1,1,1);
3912 R_Mesh_SetRenderTargets(r_shadow_prepasslightingfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
3913 Vector4Set(clearcolor, 0, 0, 0, 0);
3914 GL_Clear(GL_COLOR_BUFFER_BIT, clearcolor, 1.0f, 0);
3915 if (r_timereport_active)
3916 R_TimeReport("prepassclearlit");
3918 R_Shadow_RenderMode_Begin();
3920 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3921 if (r_shadow_debuglight.integer >= 0)
3923 lightindex = r_shadow_debuglight.integer;
3924 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3925 if (light && (light->flags & flag))
3926 R_Shadow_DrawLight(&light->rtlight);
3930 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3931 for (lightindex = 0;lightindex < range;lightindex++)
3933 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3934 if (light && (light->flags & flag))
3935 R_Shadow_DrawLight(&light->rtlight);
3938 if (r_refdef.scene.rtdlight)
3939 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
3940 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
3942 R_Mesh_ResetRenderTargets();
3944 R_Shadow_RenderMode_End();
3946 if (r_timereport_active)
3947 R_TimeReport("prepasslights");
3950 void R_Shadow_DrawLightSprites(void);
3951 void R_Shadow_PrepareLights(void)
3961 if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4) ||
3962 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != (r_shadow_shadowmapping.integer || r_shadow_deferred.integer) ||
3963 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0 && vid.renderpath == RENDERPATH_GL20) ||
3964 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
3965 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
3966 r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
3967 R_Shadow_FreeShadowMaps();
3969 r_shadow_usingshadowmaportho = false;
3971 switch (vid.renderpath)
3973 case RENDERPATH_GL20:
3974 case RENDERPATH_CGGL:
3975 case RENDERPATH_D3D9:
3976 case RENDERPATH_D3D10:
3977 case RENDERPATH_D3D11:
3978 if (!r_shadow_deferred.integer || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_STENCIL || !vid.support.ext_framebuffer_object || vid.maxdrawbuffers < 2)
3980 r_shadow_usingdeferredprepass = false;
3981 if (r_shadow_prepass_width)
3982 R_Shadow_FreeDeferred();
3983 r_shadow_prepass_width = r_shadow_prepass_height = 0;
3987 if (r_shadow_prepass_width != vid.width || r_shadow_prepass_height != vid.height)
3989 R_Shadow_FreeDeferred();
3991 r_shadow_usingdeferredprepass = true;
3992 r_shadow_prepass_width = vid.width;
3993 r_shadow_prepass_height = vid.height;
3994 r_shadow_prepassgeometrydepthtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "prepassgeometrydepthmap", vid.width, vid.height, 24, false);
3995 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);
3996 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);
3997 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);
3999 // set up the geometry pass fbo (depth + normalmap)
4000 r_shadow_prepassgeometryfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4001 R_Mesh_SetRenderTargets(r_shadow_prepassgeometryfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepassgeometrynormalmaptexture, NULL, NULL, NULL);
4002 // render depth into one texture and normalmap into the other
4003 if (qglDrawBuffersARB)
4005 qglDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);CHECKGLERROR
4006 qglReadBuffer(GL_NONE);CHECKGLERROR
4007 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4008 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4010 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4011 Cvar_SetValueQuick(&r_shadow_deferred, 0);
4012 r_shadow_usingdeferredprepass = false;
4016 // set up the lighting pass fbo (diffuse + specular)
4017 r_shadow_prepasslightingfbo = R_Mesh_CreateFramebufferObject(r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4018 R_Mesh_SetRenderTargets(r_shadow_prepasslightingfbo, r_shadow_prepassgeometrydepthtexture, r_shadow_prepasslightingdiffusetexture, r_shadow_prepasslightingspeculartexture, NULL, NULL);
4019 // render diffuse into one texture and specular into another,
4020 // with depth and normalmap bound as textures,
4021 // with depth bound as attachment as well
4022 if (qglDrawBuffersARB)
4024 qglDrawBuffersARB(2, r_shadow_prepasslightingdrawbuffers);CHECKGLERROR
4025 qglReadBuffer(GL_NONE);CHECKGLERROR
4026 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
4027 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
4029 Con_Printf("R_PrepareRTLights: glCheckFramebufferStatusEXT returned %i\n", status);
4030 Cvar_SetValueQuick(&r_shadow_deferred, 0);
4031 r_shadow_usingdeferredprepass = false;
4036 case RENDERPATH_GL13:
4037 case RENDERPATH_GL11:
4038 r_shadow_usingdeferredprepass = false;
4042 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);
4044 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4045 if (r_shadow_debuglight.integer >= 0)
4047 lightindex = r_shadow_debuglight.integer;
4048 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4049 if (light && (light->flags & flag))
4050 R_Shadow_PrepareLight(&light->rtlight);
4054 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4055 for (lightindex = 0;lightindex < range;lightindex++)
4057 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4058 if (light && (light->flags & flag))
4059 R_Shadow_PrepareLight(&light->rtlight);
4062 if (r_refdef.scene.rtdlight)
4064 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4065 R_Shadow_PrepareLight(r_refdef.scene.lights[lnum]);
4067 else if(gl_flashblend.integer)
4069 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4071 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
4072 f = (rtlight->style >= 0 ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4073 VectorScale(rtlight->color, f, rtlight->currentcolor);
4077 if (r_editlights.integer)
4078 R_Shadow_DrawLightSprites();
4081 void R_Shadow_DrawLights(void)
4089 R_Shadow_RenderMode_Begin();
4091 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4092 if (r_shadow_debuglight.integer >= 0)
4094 lightindex = r_shadow_debuglight.integer;
4095 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4096 if (light && (light->flags & flag))
4097 R_Shadow_DrawLight(&light->rtlight);
4101 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4102 for (lightindex = 0;lightindex < range;lightindex++)
4104 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4105 if (light && (light->flags & flag))
4106 R_Shadow_DrawLight(&light->rtlight);
4109 if (r_refdef.scene.rtdlight)
4110 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4111 R_Shadow_DrawLight(r_refdef.scene.lights[lnum]);
4113 R_Shadow_RenderMode_End();
4116 extern const float r_screenvertex3f[12];
4117 extern void R_SetupView(qboolean allowwaterclippingplane);
4118 extern void R_ResetViewRendering3D(void);
4119 extern void R_ResetViewRendering2D(void);
4120 extern cvar_t r_shadows;
4121 extern cvar_t r_shadows_darken;
4122 extern cvar_t r_shadows_drawafterrtlighting;
4123 extern cvar_t r_shadows_castfrombmodels;
4124 extern cvar_t r_shadows_throwdistance;
4125 extern cvar_t r_shadows_throwdirection;
4126 extern cvar_t r_shadows_focus;
4127 extern cvar_t r_shadows_shadowmapscale;
4129 void R_Shadow_PrepareModelShadows(void)
4132 float scale, size, radius, dot1, dot2;
4133 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus, shadowmins, shadowmaxs;
4134 entity_render_t *ent;
4136 if (!r_refdef.scene.numentities)
4139 switch (r_shadow_shadowmode)
4141 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4142 if (r_shadows.integer >= 2)
4145 case R_SHADOW_SHADOWMODE_STENCIL:
4146 for (i = 0;i < r_refdef.scene.numentities;i++)
4148 ent = r_refdef.scene.entities[i];
4149 if (!ent->animcache_vertex3f && ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4150 R_AnimCache_GetEntity(ent, false, false);
4157 size = 2*r_shadow_shadowmapmaxsize;
4158 scale = r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value;
4159 radius = 0.5f * size / scale;
4161 Math_atov(r_shadows_throwdirection.string, shadowdir);
4162 VectorNormalize(shadowdir);
4163 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4164 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4165 if (fabs(dot1) <= fabs(dot2))
4166 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4168 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4169 VectorNormalize(shadowforward);
4170 CrossProduct(shadowdir, shadowforward, shadowright);
4171 Math_atov(r_shadows_focus.string, shadowfocus);
4172 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4173 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4174 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4175 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4176 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4178 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4180 shadowmins[0] = shadoworigin[0] - r_shadows_throwdistance.value * fabs(shadowdir[0]) - radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4181 shadowmins[1] = shadoworigin[1] - r_shadows_throwdistance.value * fabs(shadowdir[1]) - radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4182 shadowmins[2] = shadoworigin[2] - r_shadows_throwdistance.value * fabs(shadowdir[2]) - radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4183 shadowmaxs[0] = shadoworigin[0] + r_shadows_throwdistance.value * fabs(shadowdir[0]) + radius * (fabs(shadowforward[0]) + fabs(shadowright[0]));
4184 shadowmaxs[1] = shadoworigin[1] + r_shadows_throwdistance.value * fabs(shadowdir[1]) + radius * (fabs(shadowforward[1]) + fabs(shadowright[1]));
4185 shadowmaxs[2] = shadoworigin[2] + r_shadows_throwdistance.value * fabs(shadowdir[2]) + radius * (fabs(shadowforward[2]) + fabs(shadowright[2]));
4187 for (i = 0;i < r_refdef.scene.numentities;i++)
4189 ent = r_refdef.scene.entities[i];
4190 if (!BoxesOverlap(ent->mins, ent->maxs, shadowmins, shadowmaxs))
4192 // cast shadows from anything of the map (submodels are optional)
4193 if (!ent->animcache_vertex3f && ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4194 R_AnimCache_GetEntity(ent, false, false);
4198 void R_DrawModelShadowMaps(void)
4201 float relativethrowdistance, scale, size, radius, nearclip, farclip, bias, dot1, dot2;
4202 entity_render_t *ent;
4203 vec3_t relativelightorigin;
4204 vec3_t relativelightdirection, relativeforward, relativeright;
4205 vec3_t relativeshadowmins, relativeshadowmaxs;
4206 vec3_t shadowdir, shadowforward, shadowright, shadoworigin, shadowfocus;
4208 matrix4x4_t shadowmatrix, cameramatrix, mvpmatrix, invmvpmatrix, scalematrix, texmatrix;
4209 r_viewport_t viewport;
4211 float clearcolor[4];
4213 if (!r_refdef.scene.numentities)
4216 switch (r_shadow_shadowmode)
4218 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4224 R_ResetViewRendering3D();
4225 R_Shadow_RenderMode_Begin();
4226 R_Shadow_RenderMode_ActiveLight(NULL);
4228 switch (r_shadow_shadowmode)
4230 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4231 if (!r_shadow_shadowmap2dtexture)
4232 R_Shadow_MakeShadowMap(0, r_shadow_shadowmapmaxsize);
4233 fbo = r_shadow_fbo2d;
4234 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
4235 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
4236 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
4242 size = 2*r_shadow_shadowmapmaxsize;
4243 scale = (r_shadow_shadowmapping_precision.value * r_shadows_shadowmapscale.value) / size;
4244 radius = 0.5f / scale;
4245 nearclip = -r_shadows_throwdistance.value;
4246 farclip = r_shadows_throwdistance.value;
4247 bias = r_shadow_shadowmapping_bias.value * r_shadow_shadowmapping_nearclip.value / (2 * r_shadows_throwdistance.value) * (1024.0f / size);
4249 r_shadow_shadowmap_parameters[0] = size;
4250 r_shadow_shadowmap_parameters[1] = size;
4251 r_shadow_shadowmap_parameters[2] = 1.0;
4252 r_shadow_shadowmap_parameters[3] = bound(0.0f, 1.0f - r_shadows_darken.value, 1.0f);
4254 Math_atov(r_shadows_throwdirection.string, shadowdir);
4255 VectorNormalize(shadowdir);
4256 Math_atov(r_shadows_focus.string, shadowfocus);
4257 VectorM(shadowfocus[0], r_refdef.view.right, shadoworigin);
4258 VectorMA(shadoworigin, shadowfocus[1], r_refdef.view.up, shadoworigin);
4259 VectorMA(shadoworigin, -shadowfocus[2], r_refdef.view.forward, shadoworigin);
4260 VectorAdd(shadoworigin, r_refdef.view.origin, shadoworigin);
4261 dot1 = DotProduct(r_refdef.view.forward, shadowdir);
4262 dot2 = DotProduct(r_refdef.view.up, shadowdir);
4263 if (fabs(dot1) <= fabs(dot2))
4264 VectorMA(r_refdef.view.forward, -dot1, shadowdir, shadowforward);
4266 VectorMA(r_refdef.view.up, -dot2, shadowdir, shadowforward);
4267 VectorNormalize(shadowforward);
4268 VectorM(scale, shadowforward, &m[0]);
4269 if (shadowfocus[0] || shadowfocus[1] || shadowfocus[2])
4271 m[3] = fabs(dot1) * 0.5f - DotProduct(shadoworigin, &m[0]);
4272 CrossProduct(shadowdir, shadowforward, shadowright);
4273 VectorM(scale, shadowright, &m[4]);
4274 m[7] = 0.5f - DotProduct(shadoworigin, &m[4]);
4275 VectorM(1.0f / (farclip - nearclip), shadowdir, &m[8]);
4276 m[11] = 0.5f - DotProduct(shadoworigin, &m[8]);
4277 Matrix4x4_FromArray12FloatD3D(&shadowmatrix, m);
4278 Matrix4x4_Invert_Full(&cameramatrix, &shadowmatrix);
4279 R_Viewport_InitOrtho(&viewport, &cameramatrix, 0, 0, size, size, 0, 0, 1, 1, 0, -1, NULL);
4281 VectorMA(shadoworigin, (1.0f - fabs(dot1)) * radius, shadowforward, shadoworigin);
4283 R_Mesh_SetRenderTargets(fbo, r_shadow_shadowmap2dtexture, r_shadow_shadowmap2dcolortexture, NULL, NULL, NULL);
4284 R_SetupShader_DepthOrShadow();
4285 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
4288 R_SetViewport(&viewport);
4289 GL_Scissor(viewport.x, viewport.y, min(viewport.width + r_shadow_shadowmapborder, 2*r_shadow_shadowmapmaxsize), viewport.height + r_shadow_shadowmapborder);
4290 Vector4Set(clearcolor, 1,1,1,1);
4291 // in D3D9 we have to render to a color texture shadowmap
4292 // in GL we render directly to a depth texture only
4293 if (r_shadow_shadowmap2dtexture)
4294 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4296 GL_Clear(GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4297 // render into a slightly restricted region so that the borders of the
4298 // shadowmap area fade away, rather than streaking across everything
4299 // outside the usable area
4300 GL_Scissor(viewport.x + r_shadow_shadowmapborder, viewport.y + r_shadow_shadowmapborder, viewport.width - 2*r_shadow_shadowmapborder, viewport.height - 2*r_shadow_shadowmapborder);
4304 R_Mesh_ResetRenderTargets();
4305 R_SetupShader_ShowDepth();
4306 GL_ColorMask(1,1,1,1);
4307 GL_Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, clearcolor, 1.0f, 0);
4310 for (i = 0;i < r_refdef.scene.numentities;i++)
4312 ent = r_refdef.scene.entities[i];
4314 // cast shadows from anything of the map (submodels are optional)
4315 if (ent->model && ent->model->DrawShadowMap != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4317 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4318 Matrix4x4_Transform(&ent->inversematrix, shadoworigin, relativelightorigin);
4319 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4320 Matrix4x4_Transform3x3(&ent->inversematrix, shadowforward, relativeforward);
4321 Matrix4x4_Transform3x3(&ent->inversematrix, shadowright, relativeright);
4322 relativeshadowmins[0] = relativelightorigin[0] - r_shadows_throwdistance.value * fabs(relativelightdirection[0]) - radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4323 relativeshadowmins[1] = relativelightorigin[1] - r_shadows_throwdistance.value * fabs(relativelightdirection[1]) - radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4324 relativeshadowmins[2] = relativelightorigin[2] - r_shadows_throwdistance.value * fabs(relativelightdirection[2]) - radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4325 relativeshadowmaxs[0] = relativelightorigin[0] + r_shadows_throwdistance.value * fabs(relativelightdirection[0]) + radius * (fabs(relativeforward[0]) + fabs(relativeright[0]));
4326 relativeshadowmaxs[1] = relativelightorigin[1] + r_shadows_throwdistance.value * fabs(relativelightdirection[1]) + radius * (fabs(relativeforward[1]) + fabs(relativeright[1]));
4327 relativeshadowmaxs[2] = relativelightorigin[2] + r_shadows_throwdistance.value * fabs(relativelightdirection[2]) + radius * (fabs(relativeforward[2]) + fabs(relativeright[2]));
4328 RSurf_ActiveModelEntity(ent, false, false, false);
4329 ent->model->DrawShadowMap(0, ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
4330 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4337 unsigned char *rawpixels = Z_Malloc(viewport.width*viewport.height*4);
4339 qglReadPixels(viewport.x, viewport.y, viewport.width, viewport.height, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, rawpixels);
4341 Image_WriteTGABGRA("r_shadows_2.tga", viewport.width, viewport.height, rawpixels);
4342 Cvar_SetValueQuick(&r_test, 0);
4347 R_Shadow_RenderMode_End();
4349 Matrix4x4_Concat(&mvpmatrix, &r_refdef.view.viewport.projectmatrix, &r_refdef.view.viewport.viewmatrix);
4350 Matrix4x4_Invert_Full(&invmvpmatrix, &mvpmatrix);
4351 Matrix4x4_CreateScale3(&scalematrix, size, -size, 1);
4352 Matrix4x4_AdjustOrigin(&scalematrix, 0, size, -0.5f * bias);
4353 Matrix4x4_Concat(&texmatrix, &scalematrix, &shadowmatrix);
4354 Matrix4x4_Concat(&r_shadow_shadowmapmatrix, &texmatrix, &invmvpmatrix);
4356 r_shadow_usingshadowmaportho = true;
4357 switch (r_shadow_shadowmode)
4359 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
4360 r_shadow_usingshadowmap2d = true;
4367 void R_DrawModelShadows(void)
4370 float relativethrowdistance;
4371 entity_render_t *ent;
4372 vec3_t relativelightorigin;
4373 vec3_t relativelightdirection;
4374 vec3_t relativeshadowmins, relativeshadowmaxs;
4375 vec3_t tmp, shadowdir;
4377 if (!r_refdef.scene.numentities || !vid.stencil || (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL && r_shadows.integer != 1))
4380 R_ResetViewRendering3D();
4381 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4382 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4383 R_Shadow_RenderMode_Begin();
4384 R_Shadow_RenderMode_ActiveLight(NULL);
4385 r_shadow_lightscissor[0] = r_refdef.view.x;
4386 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
4387 r_shadow_lightscissor[2] = r_refdef.view.width;
4388 r_shadow_lightscissor[3] = r_refdef.view.height;
4389 R_Shadow_RenderMode_StencilShadowVolumes(false);
4392 if (r_shadows.integer == 2)
4394 Math_atov(r_shadows_throwdirection.string, shadowdir);
4395 VectorNormalize(shadowdir);
4398 R_Shadow_ClearStencil();
4400 for (i = 0;i < r_refdef.scene.numentities;i++)
4402 ent = r_refdef.scene.entities[i];
4404 // cast shadows from anything of the map (submodels are optional)
4405 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4407 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4408 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
4409 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
4410 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
4411 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4414 if(ent->entitynumber != 0)
4416 if(ent->entitynumber >= MAX_EDICTS) // csqc entity
4418 // FIXME handle this
4419 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4423 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
4424 int entnum, entnum2, recursion;
4425 entnum = entnum2 = ent->entitynumber;
4426 for(recursion = 32; recursion > 0; --recursion)
4428 entnum2 = cl.entities[entnum].state_current.tagentity;
4429 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
4434 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
4436 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
4437 // transform into modelspace of OUR entity
4438 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
4439 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
4442 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4446 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4449 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
4450 RSurf_ActiveModelEntity(ent, false, false, false);
4451 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4452 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4456 // not really the right mode, but this will disable any silly stencil features
4457 R_Shadow_RenderMode_End();
4459 // set up ortho view for rendering this pass
4460 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4461 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4462 //GL_ScissorTest(true);
4463 //R_EntityMatrix(&identitymatrix);
4464 //R_Mesh_ResetTextureState();
4465 R_ResetViewRendering2D();
4467 // set up a darkening blend on shadowed areas
4468 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4469 //GL_DepthRange(0, 1);
4470 //GL_DepthTest(false);
4471 //GL_DepthMask(false);
4472 //GL_PolygonOffset(0, 0);CHECKGLERROR
4473 GL_Color(0, 0, 0, r_shadows_darken.value);
4474 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4475 //GL_DepthFunc(GL_ALWAYS);
4476 R_SetStencil(true, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_NOTEQUAL, 128, 255);
4478 // apply the blend to the shadowed areas
4479 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, NULL);
4480 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
4481 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4483 // restore the viewport
4484 R_SetViewport(&r_refdef.view.viewport);
4486 // restore other state to normal
4487 //R_Shadow_RenderMode_End();
4490 void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4493 vec3_t centerorigin;
4495 // if it's too close, skip it
4496 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
4498 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4501 if (usequery && r_numqueries + 2 <= r_maxqueries)
4503 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4504 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4505 // 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
4506 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4508 switch(vid.renderpath)
4510 case RENDERPATH_GL20:
4511 case RENDERPATH_GL13:
4512 case RENDERPATH_GL11:
4513 case RENDERPATH_CGGL:
4515 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use GL_DepthFunc instead
4516 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
4517 GL_DepthFunc(GL_ALWAYS);
4518 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4519 R_Mesh_PrepareVertices_Position_Arrays(4, vertex3f);
4520 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4521 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4522 GL_DepthFunc(GL_LEQUAL);
4523 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
4524 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4525 R_Mesh_PrepareVertices_Position_Arrays(4, vertex3f);
4526 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
4527 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4530 case RENDERPATH_D3D9:
4531 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4533 case RENDERPATH_D3D10:
4534 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4536 case RENDERPATH_D3D11:
4537 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4541 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4544 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
4546 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4549 GLint allpixels = 0, visiblepixels = 0;
4550 // now we have to check the query result
4551 if (rtlight->corona_queryindex_visiblepixels)
4553 switch(vid.renderpath)
4555 case RENDERPATH_GL20:
4556 case RENDERPATH_GL13:
4557 case RENDERPATH_GL11:
4558 case RENDERPATH_CGGL:
4560 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
4561 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
4564 case RENDERPATH_D3D9:
4565 Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4567 case RENDERPATH_D3D10:
4568 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4570 case RENDERPATH_D3D11:
4571 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4574 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
4575 if (visiblepixels < 1 || allpixels < 1)
4577 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
4578 cscale *= rtlight->corona_visibility;
4582 // FIXME: these traces should scan all render entities instead of cl.world
4583 if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
4586 VectorScale(rtlight->currentcolor, cscale, color);
4587 if (VectorLength(color) > (1.0f / 256.0f))
4590 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
4593 VectorNegate(color, color);
4594 switch(vid.renderpath)
4596 case RENDERPATH_GL11:
4597 case RENDERPATH_GL13:
4598 case RENDERPATH_GL20:
4599 case RENDERPATH_CGGL:
4600 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
4602 case RENDERPATH_D3D9:
4604 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_SUBTRACT);
4607 case RENDERPATH_D3D10:
4608 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4610 case RENDERPATH_D3D11:
4611 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4615 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4616 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);
4617 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4620 switch(vid.renderpath)
4622 case RENDERPATH_GL11:
4623 case RENDERPATH_GL13:
4624 case RENDERPATH_GL20:
4625 case RENDERPATH_CGGL:
4626 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
4628 case RENDERPATH_D3D9:
4630 IDirect3DDevice9_SetRenderState(vid_d3d9dev, D3DRS_BLENDOP, D3DBLENDOP_ADD);
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__);
4644 void R_Shadow_DrawCoronas(void)
4647 qboolean usequery = false;
4652 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4654 if (r_waterstate.renderingscene)
4656 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4657 R_EntityMatrix(&identitymatrix);
4659 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4661 // check occlusion of coronas
4662 // use GL_ARB_occlusion_query if available
4663 // otherwise use raytraces
4665 switch (vid.renderpath)
4667 case RENDERPATH_GL11:
4668 case RENDERPATH_GL13:
4669 case RENDERPATH_GL20:
4670 case RENDERPATH_CGGL:
4671 usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
4674 GL_ColorMask(0,0,0,0);
4675 if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
4676 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
4679 r_maxqueries = (range + r_refdef.scene.numlights) * 4;
4680 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
4682 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
4685 RSurf_ActiveWorldEntity();
4686 GL_BlendFunc(GL_ONE, GL_ZERO);
4687 GL_CullFace(GL_NONE);
4688 GL_DepthMask(false);
4689 GL_DepthRange(0, 1);
4690 GL_PolygonOffset(0, 0);
4692 R_Mesh_ResetTextureState();
4693 R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1);
4696 case RENDERPATH_D3D9:
4698 //Con_DPrintf("FIXME D3D9 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4700 case RENDERPATH_D3D10:
4701 Con_DPrintf("FIXME D3D10 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4703 case RENDERPATH_D3D11:
4704 Con_DPrintf("FIXME D3D11 %s:%i %s\n", __FILE__, __LINE__, __FUNCTION__);
4707 for (lightindex = 0;lightindex < range;lightindex++)
4709 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4712 rtlight = &light->rtlight;
4713 rtlight->corona_visibility = 0;
4714 rtlight->corona_queryindex_visiblepixels = 0;
4715 rtlight->corona_queryindex_allpixels = 0;
4716 if (!(rtlight->flags & flag))
4718 if (rtlight->corona <= 0)
4720 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4722 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4724 for (i = 0;i < r_refdef.scene.numlights;i++)
4726 rtlight = r_refdef.scene.lights[i];
4727 rtlight->corona_visibility = 0;
4728 rtlight->corona_queryindex_visiblepixels = 0;
4729 rtlight->corona_queryindex_allpixels = 0;
4730 if (!(rtlight->flags & flag))
4732 if (rtlight->corona <= 0)
4734 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4737 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4739 // now draw the coronas using the query data for intensity info
4740 for (lightindex = 0;lightindex < range;lightindex++)
4742 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4745 rtlight = &light->rtlight;
4746 if (rtlight->corona_visibility <= 0)
4748 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4750 for (i = 0;i < r_refdef.scene.numlights;i++)
4752 rtlight = r_refdef.scene.lights[i];
4753 if (rtlight->corona_visibility <= 0)
4755 if (gl_flashblend.integer)
4756 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4758 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4764 dlight_t *R_Shadow_NewWorldLight(void)
4766 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4769 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)
4772 // validate parameters
4773 if (style < 0 || style >= MAX_LIGHTSTYLES)
4775 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
4781 // copy to light properties
4782 VectorCopy(origin, light->origin);
4783 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4784 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4785 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4787 light->color[0] = max(color[0], 0);
4788 light->color[1] = max(color[1], 0);
4789 light->color[2] = max(color[2], 0);
4791 light->color[0] = color[0];
4792 light->color[1] = color[1];
4793 light->color[2] = color[2];
4794 light->radius = max(radius, 0);
4795 light->style = style;
4796 light->shadow = shadowenable;
4797 light->corona = corona;
4798 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4799 light->coronasizescale = coronasizescale;
4800 light->ambientscale = ambientscale;
4801 light->diffusescale = diffusescale;
4802 light->specularscale = specularscale;
4803 light->flags = flags;
4805 // update renderable light data
4806 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4807 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);
4810 void R_Shadow_FreeWorldLight(dlight_t *light)
4812 if (r_shadow_selectedlight == light)
4813 r_shadow_selectedlight = NULL;
4814 R_RTLight_Uncompile(&light->rtlight);
4815 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4818 void R_Shadow_ClearWorldLights(void)
4822 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4823 for (lightindex = 0;lightindex < range;lightindex++)
4825 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4827 R_Shadow_FreeWorldLight(light);
4829 r_shadow_selectedlight = NULL;
4832 void R_Shadow_SelectLight(dlight_t *light)
4834 if (r_shadow_selectedlight)
4835 r_shadow_selectedlight->selected = false;
4836 r_shadow_selectedlight = light;
4837 if (r_shadow_selectedlight)
4838 r_shadow_selectedlight->selected = true;
4841 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4843 // this is never batched (there can be only one)
4845 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
4846 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4847 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4850 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4855 skinframe_t *skinframe;
4858 // this is never batched (due to the ent parameter changing every time)
4859 // so numsurfaces == 1 and surfacelist[0] == lightnumber
4860 const dlight_t *light = (dlight_t *)ent;
4863 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
4866 VectorScale(light->color, intensity, spritecolor);
4867 if (VectorLength(spritecolor) < 0.1732f)
4868 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
4869 if (VectorLength(spritecolor) > 1.0f)
4870 VectorNormalize(spritecolor);
4872 // draw light sprite
4873 if (light->cubemapname[0] && !light->shadow)
4874 skinframe = r_editlights_sprcubemapnoshadowlight;
4875 else if (light->cubemapname[0])
4876 skinframe = r_editlights_sprcubemaplight;
4877 else if (!light->shadow)
4878 skinframe = r_editlights_sprnoshadowlight;
4880 skinframe = r_editlights_sprlight;
4882 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);
4883 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4885 // draw selection sprite if light is selected
4886 if (light->selected)
4888 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4889 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false, false);
4890 // VorteX todo: add normalmode/realtime mode light overlay sprites?
4894 void R_Shadow_DrawLightSprites(void)
4898 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4899 for (lightindex = 0;lightindex < range;lightindex++)
4901 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4903 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
4905 if (!r_editlights_lockcursor)
4906 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
4909 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
4914 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
4915 if (lightindex >= range)
4917 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4920 rtlight = &light->rtlight;
4921 //if (!(rtlight->flags & flag))
4923 VectorCopy(rtlight->shadoworigin, origin);
4924 *radius = rtlight->radius;
4925 VectorCopy(rtlight->color, color);
4929 void R_Shadow_SelectLightInView(void)
4931 float bestrating, rating, temp[3];
4935 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4939 if (r_editlights_lockcursor)
4941 for (lightindex = 0;lightindex < range;lightindex++)
4943 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4946 VectorSubtract(light->origin, r_refdef.view.origin, temp);
4947 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
4950 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
4951 if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1.0f)
4953 bestrating = rating;
4958 R_Shadow_SelectLight(best);
4961 void R_Shadow_LoadWorldLights(void)
4963 int n, a, style, shadow, flags;
4964 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
4965 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
4966 if (cl.worldmodel == NULL)
4968 Con_Print("No map loaded.\n");
4971 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
4972 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4982 for (;COM_Parse(t, true) && strcmp(
4983 if (COM_Parse(t, true))
4985 if (com_token[0] == '!')
4988 origin[0] = atof(com_token+1);
4991 origin[0] = atof(com_token);
4996 while (*s && *s != '\n' && *s != '\r')
5002 // check for modifier flags
5009 #if _MSC_VER >= 1400
5010 #define sscanf sscanf_s
5012 cubemapname[sizeof(cubemapname)-1] = 0;
5013 #if MAX_QPATH != 128
5014 #error update this code if MAX_QPATH changes
5016 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
5017 #if _MSC_VER >= 1400
5018 , sizeof(cubemapname)
5020 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
5023 flags = LIGHTFLAG_REALTIMEMODE;
5031 coronasizescale = 0.25f;
5033 VectorClear(angles);
5036 if (a < 9 || !strcmp(cubemapname, "\"\""))
5038 // remove quotes on cubemapname
5039 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
5042 namelen = strlen(cubemapname) - 2;
5043 memmove(cubemapname, cubemapname + 1, namelen);
5044 cubemapname[namelen] = '\0';
5048 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);
5051 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5059 Con_Printf("invalid rtlights file \"%s\"\n", name);
5060 Mem_Free(lightsstring);
5064 void R_Shadow_SaveWorldLights(void)
5068 size_t bufchars, bufmaxchars;
5070 char name[MAX_QPATH];
5071 char line[MAX_INPUTLINE];
5072 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
5073 // I hate lines which are 3 times my screen size :( --blub
5076 if (cl.worldmodel == NULL)
5078 Con_Print("No map loaded.\n");
5081 dpsnprintf(name, sizeof(name), "%s.rtlights", cl.worldnamenoextension);
5082 bufchars = bufmaxchars = 0;
5084 for (lightindex = 0;lightindex < range;lightindex++)
5086 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5089 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
5090 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);
5091 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
5092 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]);
5094 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);
5095 if (bufchars + strlen(line) > bufmaxchars)
5097 bufmaxchars = bufchars + strlen(line) + 2048;
5099 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
5103 memcpy(buf, oldbuf, bufchars);
5109 memcpy(buf + bufchars, line, strlen(line));
5110 bufchars += strlen(line);
5114 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
5119 void R_Shadow_LoadLightsFile(void)
5122 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
5123 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
5124 if (cl.worldmodel == NULL)
5126 Con_Print("No map loaded.\n");
5129 dpsnprintf(name, sizeof(name), "%s.lights", cl.worldnamenoextension);
5130 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5138 while (*s && *s != '\n' && *s != '\r')
5144 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);
5148 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);
5151 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
5152 radius = bound(15, radius, 4096);
5153 VectorScale(color, (2.0f / (8388608.0f)), color);
5154 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5162 Con_Printf("invalid lights file \"%s\"\n", name);
5163 Mem_Free(lightsstring);
5167 // tyrlite/hmap2 light types in the delay field
5168 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
5170 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
5182 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
5183 char key[256], value[MAX_INPUTLINE];
5185 if (cl.worldmodel == NULL)
5187 Con_Print("No map loaded.\n");
5190 // try to load a .ent file first
5191 dpsnprintf(key, sizeof(key), "%s.ent", cl.worldnamenoextension);
5192 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
5193 // and if that is not found, fall back to the bsp file entity string
5195 data = cl.worldmodel->brush.entities;
5198 for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
5200 type = LIGHTTYPE_MINUSX;
5201 origin[0] = origin[1] = origin[2] = 0;
5202 originhack[0] = originhack[1] = originhack[2] = 0;
5203 angles[0] = angles[1] = angles[2] = 0;
5204 color[0] = color[1] = color[2] = 1;
5205 light[0] = light[1] = light[2] = 1;light[3] = 300;
5206 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
5216 if (!COM_ParseToken_Simple(&data, false, false))
5218 if (com_token[0] == '}')
5219 break; // end of entity
5220 if (com_token[0] == '_')
5221 strlcpy(key, com_token + 1, sizeof(key));
5223 strlcpy(key, com_token, sizeof(key));
5224 while (key[strlen(key)-1] == ' ') // remove trailing spaces
5225 key[strlen(key)-1] = 0;
5226 if (!COM_ParseToken_Simple(&data, false, false))
5228 strlcpy(value, com_token, sizeof(value));
5230 // now that we have the key pair worked out...
5231 if (!strcmp("light", key))
5233 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5237 light[0] = vec[0] * (1.0f / 256.0f);
5238 light[1] = vec[0] * (1.0f / 256.0f);
5239 light[2] = vec[0] * (1.0f / 256.0f);
5245 light[0] = vec[0] * (1.0f / 255.0f);
5246 light[1] = vec[1] * (1.0f / 255.0f);
5247 light[2] = vec[2] * (1.0f / 255.0f);
5251 else if (!strcmp("delay", key))
5253 else if (!strcmp("origin", key))
5254 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5255 else if (!strcmp("angle", key))
5256 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5257 else if (!strcmp("angles", key))
5258 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5259 else if (!strcmp("color", key))
5260 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5261 else if (!strcmp("wait", key))
5262 fadescale = atof(value);
5263 else if (!strcmp("classname", key))
5265 if (!strncmp(value, "light", 5))
5268 if (!strcmp(value, "light_fluoro"))
5273 overridecolor[0] = 1;
5274 overridecolor[1] = 1;
5275 overridecolor[2] = 1;
5277 if (!strcmp(value, "light_fluorospark"))
5282 overridecolor[0] = 1;
5283 overridecolor[1] = 1;
5284 overridecolor[2] = 1;
5286 if (!strcmp(value, "light_globe"))
5291 overridecolor[0] = 1;
5292 overridecolor[1] = 0.8;
5293 overridecolor[2] = 0.4;
5295 if (!strcmp(value, "light_flame_large_yellow"))
5300 overridecolor[0] = 1;
5301 overridecolor[1] = 0.5;
5302 overridecolor[2] = 0.1;
5304 if (!strcmp(value, "light_flame_small_yellow"))
5309 overridecolor[0] = 1;
5310 overridecolor[1] = 0.5;
5311 overridecolor[2] = 0.1;
5313 if (!strcmp(value, "light_torch_small_white"))
5318 overridecolor[0] = 1;
5319 overridecolor[1] = 0.5;
5320 overridecolor[2] = 0.1;
5322 if (!strcmp(value, "light_torch_small_walltorch"))
5327 overridecolor[0] = 1;
5328 overridecolor[1] = 0.5;
5329 overridecolor[2] = 0.1;
5333 else if (!strcmp("style", key))
5334 style = atoi(value);
5335 else if (!strcmp("skin", key))
5336 skin = (int)atof(value);
5337 else if (!strcmp("pflags", key))
5338 pflags = (int)atof(value);
5339 //else if (!strcmp("effects", key))
5340 // effects = (int)atof(value);
5341 else if (cl.worldmodel->type == mod_brushq3)
5343 if (!strcmp("scale", key))
5344 lightscale = atof(value);
5345 if (!strcmp("fade", key))
5346 fadescale = atof(value);
5351 if (lightscale <= 0)
5355 if (color[0] == color[1] && color[0] == color[2])
5357 color[0] *= overridecolor[0];
5358 color[1] *= overridecolor[1];
5359 color[2] *= overridecolor[2];
5361 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5362 color[0] = color[0] * light[0];
5363 color[1] = color[1] * light[1];
5364 color[2] = color[2] * light[2];
5367 case LIGHTTYPE_MINUSX:
5369 case LIGHTTYPE_RECIPX:
5371 VectorScale(color, (1.0f / 16.0f), color);
5373 case LIGHTTYPE_RECIPXX:
5375 VectorScale(color, (1.0f / 16.0f), color);
5378 case LIGHTTYPE_NONE:
5382 case LIGHTTYPE_MINUSXX:
5385 VectorAdd(origin, originhack, origin);
5387 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);
5390 Mem_Free(entfiledata);
5394 void R_Shadow_SetCursorLocationForView(void)
5397 vec3_t dest, endpos;
5399 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5400 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
5401 if (trace.fraction < 1)
5403 dist = trace.fraction * r_editlights_cursordistance.value;
5404 push = r_editlights_cursorpushback.value;
5408 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5409 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5413 VectorClear( endpos );
5415 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5416 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5417 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5420 void R_Shadow_UpdateWorldLightSelection(void)
5422 if (r_editlights.integer)
5424 R_Shadow_SetCursorLocationForView();
5425 R_Shadow_SelectLightInView();
5428 R_Shadow_SelectLight(NULL);
5431 void R_Shadow_EditLights_Clear_f(void)
5433 R_Shadow_ClearWorldLights();
5436 void R_Shadow_EditLights_Reload_f(void)
5440 strlcpy(r_shadow_mapname, cl.worldname, sizeof(r_shadow_mapname));
5441 R_Shadow_ClearWorldLights();
5442 R_Shadow_LoadWorldLights();
5443 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5445 R_Shadow_LoadLightsFile();
5446 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5447 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5451 void R_Shadow_EditLights_Save_f(void)
5455 R_Shadow_SaveWorldLights();
5458 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
5460 R_Shadow_ClearWorldLights();
5461 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5464 void R_Shadow_EditLights_ImportLightsFile_f(void)
5466 R_Shadow_ClearWorldLights();
5467 R_Shadow_LoadLightsFile();
5470 void R_Shadow_EditLights_Spawn_f(void)
5473 if (!r_editlights.integer)
5475 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5478 if (Cmd_Argc() != 1)
5480 Con_Print("r_editlights_spawn does not take parameters\n");
5483 color[0] = color[1] = color[2] = 1;
5484 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5487 void R_Shadow_EditLights_Edit_f(void)
5489 vec3_t origin, angles, color;
5490 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5491 int style, shadows, flags, normalmode, realtimemode;
5492 char cubemapname[MAX_INPUTLINE];
5493 if (!r_editlights.integer)
5495 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5498 if (!r_shadow_selectedlight)
5500 Con_Print("No selected light.\n");
5503 VectorCopy(r_shadow_selectedlight->origin, origin);
5504 VectorCopy(r_shadow_selectedlight->angles, angles);
5505 VectorCopy(r_shadow_selectedlight->color, color);
5506 radius = r_shadow_selectedlight->radius;
5507 style = r_shadow_selectedlight->style;
5508 if (r_shadow_selectedlight->cubemapname)
5509 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5512 shadows = r_shadow_selectedlight->shadow;
5513 corona = r_shadow_selectedlight->corona;
5514 coronasizescale = r_shadow_selectedlight->coronasizescale;
5515 ambientscale = r_shadow_selectedlight->ambientscale;
5516 diffusescale = r_shadow_selectedlight->diffusescale;
5517 specularscale = r_shadow_selectedlight->specularscale;
5518 flags = r_shadow_selectedlight->flags;
5519 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5520 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5521 if (!strcmp(Cmd_Argv(1), "origin"))
5523 if (Cmd_Argc() != 5)
5525 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5528 origin[0] = atof(Cmd_Argv(2));
5529 origin[1] = atof(Cmd_Argv(3));
5530 origin[2] = atof(Cmd_Argv(4));
5532 else if (!strcmp(Cmd_Argv(1), "originx"))
5534 if (Cmd_Argc() != 3)
5536 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5539 origin[0] = atof(Cmd_Argv(2));
5541 else if (!strcmp(Cmd_Argv(1), "originy"))
5543 if (Cmd_Argc() != 3)
5545 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5548 origin[1] = atof(Cmd_Argv(2));
5550 else if (!strcmp(Cmd_Argv(1), "originz"))
5552 if (Cmd_Argc() != 3)
5554 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5557 origin[2] = atof(Cmd_Argv(2));
5559 else if (!strcmp(Cmd_Argv(1), "move"))
5561 if (Cmd_Argc() != 5)
5563 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5566 origin[0] += atof(Cmd_Argv(2));
5567 origin[1] += atof(Cmd_Argv(3));
5568 origin[2] += atof(Cmd_Argv(4));
5570 else if (!strcmp(Cmd_Argv(1), "movex"))
5572 if (Cmd_Argc() != 3)
5574 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5577 origin[0] += atof(Cmd_Argv(2));
5579 else if (!strcmp(Cmd_Argv(1), "movey"))
5581 if (Cmd_Argc() != 3)
5583 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5586 origin[1] += atof(Cmd_Argv(2));
5588 else if (!strcmp(Cmd_Argv(1), "movez"))
5590 if (Cmd_Argc() != 3)
5592 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5595 origin[2] += atof(Cmd_Argv(2));
5597 else if (!strcmp(Cmd_Argv(1), "angles"))
5599 if (Cmd_Argc() != 5)
5601 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5604 angles[0] = atof(Cmd_Argv(2));
5605 angles[1] = atof(Cmd_Argv(3));
5606 angles[2] = atof(Cmd_Argv(4));
5608 else if (!strcmp(Cmd_Argv(1), "anglesx"))
5610 if (Cmd_Argc() != 3)
5612 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5615 angles[0] = atof(Cmd_Argv(2));
5617 else if (!strcmp(Cmd_Argv(1), "anglesy"))
5619 if (Cmd_Argc() != 3)
5621 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5624 angles[1] = atof(Cmd_Argv(2));
5626 else if (!strcmp(Cmd_Argv(1), "anglesz"))
5628 if (Cmd_Argc() != 3)
5630 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5633 angles[2] = atof(Cmd_Argv(2));
5635 else if (!strcmp(Cmd_Argv(1), "color"))
5637 if (Cmd_Argc() != 5)
5639 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
5642 color[0] = atof(Cmd_Argv(2));
5643 color[1] = atof(Cmd_Argv(3));
5644 color[2] = atof(Cmd_Argv(4));
5646 else if (!strcmp(Cmd_Argv(1), "radius"))
5648 if (Cmd_Argc() != 3)
5650 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5653 radius = atof(Cmd_Argv(2));
5655 else if (!strcmp(Cmd_Argv(1), "colorscale"))
5657 if (Cmd_Argc() == 3)
5659 double scale = atof(Cmd_Argv(2));
5666 if (Cmd_Argc() != 5)
5668 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
5671 color[0] *= atof(Cmd_Argv(2));
5672 color[1] *= atof(Cmd_Argv(3));
5673 color[2] *= atof(Cmd_Argv(4));
5676 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
5678 if (Cmd_Argc() != 3)
5680 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5683 radius *= atof(Cmd_Argv(2));
5685 else if (!strcmp(Cmd_Argv(1), "style"))
5687 if (Cmd_Argc() != 3)
5689 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5692 style = atoi(Cmd_Argv(2));
5694 else if (!strcmp(Cmd_Argv(1), "cubemap"))
5698 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5701 if (Cmd_Argc() == 3)
5702 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
5706 else if (!strcmp(Cmd_Argv(1), "shadows"))
5708 if (Cmd_Argc() != 3)
5710 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5713 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5715 else if (!strcmp(Cmd_Argv(1), "corona"))
5717 if (Cmd_Argc() != 3)
5719 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5722 corona = atof(Cmd_Argv(2));
5724 else if (!strcmp(Cmd_Argv(1), "coronasize"))
5726 if (Cmd_Argc() != 3)
5728 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5731 coronasizescale = atof(Cmd_Argv(2));
5733 else if (!strcmp(Cmd_Argv(1), "ambient"))
5735 if (Cmd_Argc() != 3)
5737 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5740 ambientscale = atof(Cmd_Argv(2));
5742 else if (!strcmp(Cmd_Argv(1), "diffuse"))
5744 if (Cmd_Argc() != 3)
5746 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5749 diffusescale = atof(Cmd_Argv(2));
5751 else if (!strcmp(Cmd_Argv(1), "specular"))
5753 if (Cmd_Argc() != 3)
5755 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5758 specularscale = atof(Cmd_Argv(2));
5760 else if (!strcmp(Cmd_Argv(1), "normalmode"))
5762 if (Cmd_Argc() != 3)
5764 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5767 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5769 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
5771 if (Cmd_Argc() != 3)
5773 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5776 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5780 Con_Print("usage: r_editlights_edit [property] [value]\n");
5781 Con_Print("Selected light's properties:\n");
5782 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5783 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5784 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5785 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
5786 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
5787 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
5788 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5789 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
5790 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
5791 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
5792 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
5793 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
5794 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5795 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5798 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5799 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5802 void R_Shadow_EditLights_EditAll_f(void)
5805 dlight_t *light, *oldselected;
5808 if (!r_editlights.integer)
5810 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5814 oldselected = r_shadow_selectedlight;
5815 // EditLights doesn't seem to have a "remove" command or something so:
5816 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5817 for (lightindex = 0;lightindex < range;lightindex++)
5819 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5822 R_Shadow_SelectLight(light);
5823 R_Shadow_EditLights_Edit_f();
5825 // return to old selected (to not mess editing once selection is locked)
5826 R_Shadow_SelectLight(oldselected);
5829 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
5831 int lightnumber, lightcount;
5832 size_t lightindex, range;
5836 if (!r_editlights.integer)
5838 x = vid_conwidth.value - 240;
5840 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
5843 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5844 for (lightindex = 0;lightindex < range;lightindex++)
5846 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5849 if (light == r_shadow_selectedlight)
5850 lightnumber = lightindex;
5853 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;
5854 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;
5856 if (r_shadow_selectedlight == NULL)
5858 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;
5859 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;
5860 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;
5861 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;
5862 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;
5863 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;
5864 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;
5865 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;
5866 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;
5867 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;
5868 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;
5869 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;
5870 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;
5871 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;
5872 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;
5875 void R_Shadow_EditLights_ToggleShadow_f(void)
5877 if (!r_editlights.integer)
5879 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5882 if (!r_shadow_selectedlight)
5884 Con_Print("No selected light.\n");
5887 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);
5890 void R_Shadow_EditLights_ToggleCorona_f(void)
5892 if (!r_editlights.integer)
5894 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5897 if (!r_shadow_selectedlight)
5899 Con_Print("No selected light.\n");
5902 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);
5905 void R_Shadow_EditLights_Remove_f(void)
5907 if (!r_editlights.integer)
5909 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
5912 if (!r_shadow_selectedlight)
5914 Con_Print("No selected light.\n");
5917 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
5918 r_shadow_selectedlight = NULL;
5921 void R_Shadow_EditLights_Help_f(void)
5924 "Documentation on r_editlights system:\n"
5926 "r_editlights : enable/disable editing mode\n"
5927 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
5928 "r_editlights_cursorpushback : push back cursor this far from surface\n"
5929 "r_editlights_cursorpushoff : push cursor off surface this far\n"
5930 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
5931 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
5933 "r_editlights_help : this help\n"
5934 "r_editlights_clear : remove all lights\n"
5935 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
5936 "r_editlights_lock : lock selection to current light, if already locked - unlock\n"
5937 "r_editlights_save : save to .rtlights file\n"
5938 "r_editlights_spawn : create a light with default settings\n"
5939 "r_editlights_edit command : edit selected light - more documentation below\n"
5940 "r_editlights_remove : remove selected light\n"
5941 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
5942 "r_editlights_importlightentitiesfrommap : reload light entities\n"
5943 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
5945 "origin x y z : set light location\n"
5946 "originx x: set x component of light location\n"
5947 "originy y: set y component of light location\n"
5948 "originz z: set z component of light location\n"
5949 "move x y z : adjust light location\n"
5950 "movex x: adjust x component of light location\n"
5951 "movey y: adjust y component of light location\n"
5952 "movez z: adjust z component of light location\n"
5953 "angles x y z : set light angles\n"
5954 "anglesx x: set x component of light angles\n"
5955 "anglesy y: set y component of light angles\n"
5956 "anglesz z: set z component of light angles\n"
5957 "color r g b : set color of light (can be brighter than 1 1 1)\n"
5958 "radius radius : set radius (size) of light\n"
5959 "colorscale grey : multiply color of light (1 does nothing)\n"
5960 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
5961 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
5962 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
5963 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
5964 "cubemap basename : set filter cubemap of light (not yet supported)\n"
5965 "shadows 1/0 : turn on/off shadows\n"
5966 "corona n : set corona intensity\n"
5967 "coronasize n : set corona size (0-1)\n"
5968 "ambient n : set ambient intensity (0-1)\n"
5969 "diffuse n : set diffuse intensity (0-1)\n"
5970 "specular n : set specular intensity (0-1)\n"
5971 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
5972 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
5973 "<nothing> : print light properties to console\n"
5977 void R_Shadow_EditLights_CopyInfo_f(void)
5979 if (!r_editlights.integer)
5981 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
5984 if (!r_shadow_selectedlight)
5986 Con_Print("No selected light.\n");
5989 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
5990 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
5991 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
5992 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
5993 if (r_shadow_selectedlight->cubemapname)
5994 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
5996 r_shadow_bufferlight.cubemapname[0] = 0;
5997 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
5998 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
5999 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
6000 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
6001 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
6002 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
6003 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
6006 void R_Shadow_EditLights_PasteInfo_f(void)
6008 if (!r_editlights.integer)
6010 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
6013 if (!r_shadow_selectedlight)
6015 Con_Print("No selected light.\n");
6018 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);
6021 void R_Shadow_EditLights_Lock_f(void)
6023 if (!r_editlights.integer)
6025 Con_Print("Cannot lock on light when not in editing mode. Set r_editlights to 1.\n");
6028 if (r_editlights_lockcursor)
6030 r_editlights_lockcursor = false;
6033 if (!r_shadow_selectedlight)
6035 Con_Print("No selected light to lock on.\n");
6038 r_editlights_lockcursor = true;
6041 void R_Shadow_EditLights_Init(void)
6043 Cvar_RegisterVariable(&r_editlights);
6044 Cvar_RegisterVariable(&r_editlights_cursordistance);
6045 Cvar_RegisterVariable(&r_editlights_cursorpushback);
6046 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
6047 Cvar_RegisterVariable(&r_editlights_cursorgrid);
6048 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
6049 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
6050 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
6051 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)");
6052 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
6053 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
6054 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
6055 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)");
6056 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
6057 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
6058 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
6059 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
6060 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
6061 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
6062 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)");
6063 Cmd_AddCommand("r_editlights_lock", R_Shadow_EditLights_Lock_f, "lock selection to current light, if already locked - unlock");
6069 =============================================================================
6073 =============================================================================
6076 void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, int dynamic)
6078 VectorClear(diffusecolor);
6079 VectorClear(diffusenormal);
6081 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
6083 ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_refdef.scene.ambient;
6084 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
6087 VectorSet(ambientcolor, 1, 1, 1);
6094 for (i = 0;i < r_refdef.scene.numlights;i++)
6096 light = r_refdef.scene.lights[i];
6097 Matrix4x4_Transform(&light->matrix_worldtolight, p, v);
6098 f = 1 - VectorLength2(v);
6099 if (f > 0 && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
6100 VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);