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"
143 #define R_SHADOW_SHADOWMAP_NUMCUBEMAPS 8
145 extern void R_Shadow_EditLights_Init(void);
147 typedef enum r_shadow_rendermode_e
149 R_SHADOW_RENDERMODE_NONE,
150 R_SHADOW_RENDERMODE_ZPASS_STENCIL,
151 R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL,
152 R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE,
153 R_SHADOW_RENDERMODE_ZFAIL_STENCIL,
154 R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL,
155 R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE,
156 R_SHADOW_RENDERMODE_LIGHT_VERTEX,
157 R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN,
158 R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN,
159 R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN,
160 R_SHADOW_RENDERMODE_LIGHT_GLSL,
161 R_SHADOW_RENDERMODE_VISIBLEVOLUMES,
162 R_SHADOW_RENDERMODE_VISIBLELIGHTING,
163 R_SHADOW_RENDERMODE_SHADOWMAP2D,
164 R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE,
165 R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE,
167 r_shadow_rendermode_t;
169 typedef enum r_shadow_shadowmode_e
171 R_SHADOW_SHADOWMODE_STENCIL,
172 R_SHADOW_SHADOWMODE_SHADOWMAP2D,
173 R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE,
174 R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE
176 r_shadow_shadowmode_t;
178 r_shadow_rendermode_t r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
179 r_shadow_rendermode_t r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_NONE;
180 r_shadow_rendermode_t r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_NONE;
181 r_shadow_rendermode_t r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_NONE;
182 qboolean r_shadow_usingshadowmaprect;
183 qboolean r_shadow_usingshadowmap2d;
184 qboolean r_shadow_usingshadowmapcube;
185 int r_shadow_shadowmapside;
186 float r_shadow_shadowmap_texturescale[2];
187 float r_shadow_shadowmap_parameters[4];
189 int r_shadow_drawbuffer;
190 int r_shadow_readbuffer;
192 int r_shadow_cullface_front, r_shadow_cullface_back;
193 GLuint r_shadow_fborectangle;
194 GLuint r_shadow_fbocubeside[R_SHADOW_SHADOWMAP_NUMCUBEMAPS];
195 GLuint r_shadow_fbo2d;
196 r_shadow_shadowmode_t r_shadow_shadowmode;
197 int r_shadow_shadowmapfilterquality;
198 int r_shadow_shadowmaptexturetype;
199 int r_shadow_shadowmapdepthbits;
200 int r_shadow_shadowmapmaxsize;
201 qboolean r_shadow_shadowmapvsdct;
202 qboolean r_shadow_shadowmapsampler;
203 int r_shadow_shadowmappcf;
204 int r_shadow_shadowmapborder;
205 int r_shadow_lightscissor[4];
207 int maxshadowtriangles;
210 int maxshadowvertices;
211 float *shadowvertex3f;
221 unsigned char *shadowsides;
222 int *shadowsideslist;
229 int r_shadow_buffer_numleafpvsbytes;
230 unsigned char *r_shadow_buffer_visitingleafpvs;
231 unsigned char *r_shadow_buffer_leafpvs;
232 int *r_shadow_buffer_leaflist;
234 int r_shadow_buffer_numsurfacepvsbytes;
235 unsigned char *r_shadow_buffer_surfacepvs;
236 int *r_shadow_buffer_surfacelist;
237 unsigned char *r_shadow_buffer_surfacesides;
239 int r_shadow_buffer_numshadowtrispvsbytes;
240 unsigned char *r_shadow_buffer_shadowtrispvs;
241 int r_shadow_buffer_numlighttrispvsbytes;
242 unsigned char *r_shadow_buffer_lighttrispvs;
244 rtexturepool_t *r_shadow_texturepool;
245 rtexture_t *r_shadow_attenuationgradienttexture;
246 rtexture_t *r_shadow_attenuation2dtexture;
247 rtexture_t *r_shadow_attenuation3dtexture;
248 skinframe_t *r_shadow_lightcorona;
249 rtexture_t *r_shadow_shadowmaprectangletexture;
250 rtexture_t *r_shadow_shadowmap2dtexture;
251 rtexture_t *r_shadow_shadowmapcubetexture[R_SHADOW_SHADOWMAP_NUMCUBEMAPS];
252 rtexture_t *r_shadow_shadowmapvsdcttexture;
253 int r_shadow_shadowmapsize; // changes for each light based on distance
254 int r_shadow_shadowmaplod; // changes for each light based on distance
256 // lights are reloaded when this changes
257 char r_shadow_mapname[MAX_QPATH];
259 // used only for light filters (cubemaps)
260 rtexturepool_t *r_shadow_filters_texturepool;
262 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"};
263 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"};
264 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
265 cvar_t r_shadow_usenormalmap = {CVAR_SAVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"};
266 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)"};
267 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"};
268 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
269 cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
270 cvar_t r_shadow_gloss2exponent = {0, "r_shadow_gloss2exponent", "32", "same as r_shadow_glossexponent but for forced gloss (gloss 2) surfaces"};
271 cvar_t r_shadow_glossexact = {0, "r_shadow_glossexact", "0", "use exact reflection math for gloss (slightly slower, but should look a tad better)"};
272 cvar_t r_shadow_lightattenuationdividebias = {0, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"};
273 cvar_t r_shadow_lightattenuationlinearscale = {0, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"};
274 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
275 cvar_t r_shadow_lightradiusscale = {0, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
276 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1", "use portal culling to exactly determine lit triangles when compiling world lights"};
277 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000", "how far to cast shadows"};
278 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)"};
279 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
280 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
281 cvar_t r_shadow_realtime_dlight_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
282 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
283 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)"};
284 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"};
285 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
286 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
287 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"};
288 cvar_t r_shadow_realtime_world_compilesvbsp = {0, "r_shadow_realtime_world_compilesvbsp", "1", "enables svbsp optimization during compilation"};
289 cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "1", "enables portal-based culling optimization during compilation"};
290 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)"};
291 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"};
292 cvar_t r_shadow_shadowmapping_texturetype = {CVAR_SAVE, "r_shadow_shadowmapping_texturetype", "-1", "shadowmap texture types: -1 = auto-select, 0 = 2D, 1 = rectangle, 2 = cubemap"};
293 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)"};
294 cvar_t r_shadow_shadowmapping_depthbits = {CVAR_SAVE, "r_shadow_shadowmapping_depthbits", "24", "requested minimum shadowmap texture depth bits"};
295 cvar_t r_shadow_shadowmapping_vsdct = {CVAR_SAVE, "r_shadow_shadowmapping_vsdct", "1", "enables use of virtual shadow depth cube texture"};
296 cvar_t r_shadow_shadowmapping_minsize = {CVAR_SAVE, "r_shadow_shadowmapping_minsize", "32", "shadowmap size limit"};
297 cvar_t r_shadow_shadowmapping_maxsize = {CVAR_SAVE, "r_shadow_shadowmapping_maxsize", "512", "shadowmap size limit"};
298 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"};
299 //cvar_t r_shadow_shadowmapping_lod_bias = {CVAR_SAVE, "r_shadow_shadowmapping_lod_bias", "16", "shadowmap size bias"};
300 //cvar_t r_shadow_shadowmapping_lod_scale = {CVAR_SAVE, "r_shadow_shadowmapping_lod_scale", "128", "shadowmap size scaling parameter"};
301 cvar_t r_shadow_shadowmapping_bordersize = {CVAR_SAVE, "r_shadow_shadowmapping_bordersize", "4", "shadowmap size bias for filtering"};
302 cvar_t r_shadow_shadowmapping_nearclip = {CVAR_SAVE, "r_shadow_shadowmapping_nearclip", "1", "shadowmap nearclip in world units"};
303 cvar_t r_shadow_shadowmapping_bias = {CVAR_SAVE, "r_shadow_shadowmapping_bias", "0.03", "shadowmap bias parameter (this is multiplied by nearclip * 1024 / lodsize)"};
304 cvar_t r_shadow_shadowmapping_polygonfactor = {CVAR_SAVE, "r_shadow_shadowmapping_polygonfactor", "2", "slope-dependent shadowmapping bias"};
305 cvar_t r_shadow_shadowmapping_polygonoffset = {CVAR_SAVE, "r_shadow_shadowmapping_polygonoffset", "0", "constant shadowmapping bias"};
306 cvar_t r_shadow_culltriangles = {0, "r_shadow_culltriangles", "1", "performs more expensive tests to remove unnecessary triangles of lit surfaces"};
307 cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
308 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)"};
309 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)"};
310 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "1", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
311 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"};
312 cvar_t r_coronas_occlusionquery = {CVAR_SAVE, "r_coronas_occlusionquery", "1", "use GL_ARB_occlusion_query extension if supported (fades coronas according to visibility)"};
313 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
314 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
315 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
316 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
317 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
318 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
319 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
320 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
321 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
323 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
324 #define ATTENTABLESIZE 256
325 // 1D gradient, 2D circle and 3D sphere attenuation textures
326 #define ATTEN1DSIZE 32
327 #define ATTEN2DSIZE 64
328 #define ATTEN3DSIZE 32
330 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
331 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
332 static float r_shadow_attentable[ATTENTABLESIZE+1];
334 rtlight_t *r_shadow_compilingrtlight;
335 static memexpandablearray_t r_shadow_worldlightsarray;
336 dlight_t *r_shadow_selectedlight;
337 dlight_t r_shadow_bufferlight;
338 vec3_t r_editlights_cursorlocation;
340 extern int con_vislines;
342 typedef struct cubemapinfo_s
349 static int numcubemaps;
350 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
352 void R_Shadow_UncompileWorldLights(void);
353 void R_Shadow_ClearWorldLights(void);
354 void R_Shadow_SaveWorldLights(void);
355 void R_Shadow_LoadWorldLights(void);
356 void R_Shadow_LoadLightsFile(void);
357 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
358 void R_Shadow_EditLights_Reload_f(void);
359 void R_Shadow_ValidateCvars(void);
360 static void R_Shadow_MakeTextures(void);
362 #define EDLIGHTSPRSIZE 8
363 skinframe_t *r_editlights_sprcursor;
364 skinframe_t *r_editlights_sprlight;
365 skinframe_t *r_editlights_sprnoshadowlight;
366 skinframe_t *r_editlights_sprcubemaplight;
367 skinframe_t *r_editlights_sprcubemapnoshadowlight;
368 skinframe_t *r_editlights_sprselection;
370 void R_Shadow_SetShadowMode(void)
372 r_shadow_shadowmapmaxsize = bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4);
373 r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer != 0;
374 r_shadow_shadowmapfilterquality = r_shadow_shadowmapping_filterquality.integer;
375 r_shadow_shadowmaptexturetype = r_shadow_shadowmapping_texturetype.integer;
376 r_shadow_shadowmapdepthbits = r_shadow_shadowmapping_depthbits.integer;
377 r_shadow_shadowmapborder = bound(0, r_shadow_shadowmapping_bordersize.integer, 16);
378 r_shadow_shadowmaplod = -1;
379 r_shadow_shadowmapsize = 0;
380 r_shadow_shadowmapsampler = false;
381 r_shadow_shadowmappcf = 0;
382 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
383 switch(vid.renderpath)
385 case RENDERPATH_GL20:
386 if(r_shadow_shadowmapping.integer && vid.support.ext_framebuffer_object)
388 if(r_shadow_shadowmapfilterquality < 0)
390 if(strstr(gl_vendor, "NVIDIA"))
392 r_shadow_shadowmapsampler = vid.support.arb_shadow;
393 r_shadow_shadowmappcf = 1;
395 else if(vid.support.amd_texture_texture4 || vid.support.arb_texture_gather)
396 r_shadow_shadowmappcf = 1;
397 else if(strstr(gl_vendor, "ATI"))
398 r_shadow_shadowmappcf = 1;
400 r_shadow_shadowmapsampler = vid.support.arb_shadow;
404 switch (r_shadow_shadowmapfilterquality)
407 r_shadow_shadowmapsampler = vid.support.arb_shadow;
410 r_shadow_shadowmapsampler = vid.support.arb_shadow;
411 r_shadow_shadowmappcf = 1;
414 r_shadow_shadowmappcf = 1;
417 r_shadow_shadowmappcf = 2;
421 switch (r_shadow_shadowmaptexturetype)
424 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
427 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE;
430 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE;
433 if((vid.support.amd_texture_texture4 || vid.support.arb_texture_gather) && r_shadow_shadowmappcf && !r_shadow_shadowmapsampler)
434 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
435 else if(vid.support.arb_texture_rectangle)
436 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE;
438 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_SHADOWMAP2D;
443 case RENDERPATH_GL13:
445 case RENDERPATH_GL11:
450 void R_Shadow_FreeShadowMaps(void)
454 R_Shadow_SetShadowMode();
456 if (!vid.support.ext_framebuffer_object || !vid.support.arb_fragment_shader)
461 if (r_shadow_fborectangle)
462 qglDeleteFramebuffersEXT(1, &r_shadow_fborectangle);CHECKGLERROR
463 r_shadow_fborectangle = 0;
466 qglDeleteFramebuffersEXT(1, &r_shadow_fbo2d);CHECKGLERROR
468 for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
469 if (r_shadow_fbocubeside[i])
470 qglDeleteFramebuffersEXT(1, &r_shadow_fbocubeside[i]);CHECKGLERROR
471 memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
473 if (r_shadow_shadowmaprectangletexture)
474 R_FreeTexture(r_shadow_shadowmaprectangletexture);
475 r_shadow_shadowmaprectangletexture = NULL;
477 if (r_shadow_shadowmap2dtexture)
478 R_FreeTexture(r_shadow_shadowmap2dtexture);
479 r_shadow_shadowmap2dtexture = NULL;
481 for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
482 if (r_shadow_shadowmapcubetexture[i])
483 R_FreeTexture(r_shadow_shadowmapcubetexture[i]);
484 memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
486 if (r_shadow_shadowmapvsdcttexture)
487 R_FreeTexture(r_shadow_shadowmapvsdcttexture);
488 r_shadow_shadowmapvsdcttexture = NULL;
493 void r_shadow_start(void)
495 // allocate vertex processing arrays
497 r_shadow_attenuationgradienttexture = NULL;
498 r_shadow_attenuation2dtexture = NULL;
499 r_shadow_attenuation3dtexture = NULL;
500 r_shadow_shadowmode = R_SHADOW_SHADOWMODE_STENCIL;
501 r_shadow_shadowmaprectangletexture = NULL;
502 r_shadow_shadowmap2dtexture = NULL;
503 memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
504 r_shadow_shadowmapvsdcttexture = NULL;
505 r_shadow_shadowmapmaxsize = 0;
506 r_shadow_shadowmapsize = 0;
507 r_shadow_shadowmaplod = 0;
508 r_shadow_shadowmapfilterquality = -1;
509 r_shadow_shadowmaptexturetype = -1;
510 r_shadow_shadowmapdepthbits = 0;
511 r_shadow_shadowmapvsdct = false;
512 r_shadow_shadowmapsampler = false;
513 r_shadow_shadowmappcf = 0;
514 r_shadow_fborectangle = 0;
516 memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
518 R_Shadow_FreeShadowMaps();
520 r_shadow_texturepool = NULL;
521 r_shadow_filters_texturepool = NULL;
522 R_Shadow_ValidateCvars();
523 R_Shadow_MakeTextures();
524 maxshadowtriangles = 0;
525 shadowelements = NULL;
526 maxshadowvertices = 0;
527 shadowvertex3f = NULL;
535 shadowmarklist = NULL;
540 shadowsideslist = NULL;
541 r_shadow_buffer_numleafpvsbytes = 0;
542 r_shadow_buffer_visitingleafpvs = NULL;
543 r_shadow_buffer_leafpvs = NULL;
544 r_shadow_buffer_leaflist = NULL;
545 r_shadow_buffer_numsurfacepvsbytes = 0;
546 r_shadow_buffer_surfacepvs = NULL;
547 r_shadow_buffer_surfacelist = NULL;
548 r_shadow_buffer_surfacesides = NULL;
549 r_shadow_buffer_numshadowtrispvsbytes = 0;
550 r_shadow_buffer_shadowtrispvs = NULL;
551 r_shadow_buffer_numlighttrispvsbytes = 0;
552 r_shadow_buffer_lighttrispvs = NULL;
555 void r_shadow_shutdown(void)
558 R_Shadow_UncompileWorldLights();
560 R_Shadow_FreeShadowMaps();
564 r_shadow_attenuationgradienttexture = NULL;
565 r_shadow_attenuation2dtexture = NULL;
566 r_shadow_attenuation3dtexture = NULL;
567 R_FreeTexturePool(&r_shadow_texturepool);
568 R_FreeTexturePool(&r_shadow_filters_texturepool);
569 maxshadowtriangles = 0;
571 Mem_Free(shadowelements);
572 shadowelements = NULL;
574 Mem_Free(shadowvertex3f);
575 shadowvertex3f = NULL;
578 Mem_Free(vertexupdate);
581 Mem_Free(vertexremap);
587 Mem_Free(shadowmark);
590 Mem_Free(shadowmarklist);
591 shadowmarklist = NULL;
596 Mem_Free(shadowsides);
599 Mem_Free(shadowsideslist);
600 shadowsideslist = NULL;
601 r_shadow_buffer_numleafpvsbytes = 0;
602 if (r_shadow_buffer_visitingleafpvs)
603 Mem_Free(r_shadow_buffer_visitingleafpvs);
604 r_shadow_buffer_visitingleafpvs = NULL;
605 if (r_shadow_buffer_leafpvs)
606 Mem_Free(r_shadow_buffer_leafpvs);
607 r_shadow_buffer_leafpvs = NULL;
608 if (r_shadow_buffer_leaflist)
609 Mem_Free(r_shadow_buffer_leaflist);
610 r_shadow_buffer_leaflist = NULL;
611 r_shadow_buffer_numsurfacepvsbytes = 0;
612 if (r_shadow_buffer_surfacepvs)
613 Mem_Free(r_shadow_buffer_surfacepvs);
614 r_shadow_buffer_surfacepvs = NULL;
615 if (r_shadow_buffer_surfacelist)
616 Mem_Free(r_shadow_buffer_surfacelist);
617 r_shadow_buffer_surfacelist = NULL;
618 if (r_shadow_buffer_surfacesides)
619 Mem_Free(r_shadow_buffer_surfacesides);
620 r_shadow_buffer_surfacesides = NULL;
621 r_shadow_buffer_numshadowtrispvsbytes = 0;
622 if (r_shadow_buffer_shadowtrispvs)
623 Mem_Free(r_shadow_buffer_shadowtrispvs);
624 r_shadow_buffer_numlighttrispvsbytes = 0;
625 if (r_shadow_buffer_lighttrispvs)
626 Mem_Free(r_shadow_buffer_lighttrispvs);
629 void r_shadow_newmap(void)
631 if (r_shadow_lightcorona) R_SkinFrame_MarkUsed(r_shadow_lightcorona);
632 if (r_editlights_sprcursor) R_SkinFrame_MarkUsed(r_editlights_sprcursor);
633 if (r_editlights_sprlight) R_SkinFrame_MarkUsed(r_editlights_sprlight);
634 if (r_editlights_sprnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprnoshadowlight);
635 if (r_editlights_sprcubemaplight) R_SkinFrame_MarkUsed(r_editlights_sprcubemaplight);
636 if (r_editlights_sprcubemapnoshadowlight) R_SkinFrame_MarkUsed(r_editlights_sprcubemapnoshadowlight);
637 if (r_editlights_sprselection) R_SkinFrame_MarkUsed(r_editlights_sprselection);
638 if (cl.worldmodel && strncmp(cl.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
639 R_Shadow_EditLights_Reload_f();
642 void R_Shadow_Init(void)
644 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
645 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
646 Cvar_RegisterVariable(&r_shadow_usenormalmap);
647 Cvar_RegisterVariable(&r_shadow_debuglight);
648 Cvar_RegisterVariable(&r_shadow_gloss);
649 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
650 Cvar_RegisterVariable(&r_shadow_glossintensity);
651 Cvar_RegisterVariable(&r_shadow_glossexponent);
652 Cvar_RegisterVariable(&r_shadow_gloss2exponent);
653 Cvar_RegisterVariable(&r_shadow_glossexact);
654 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
655 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
656 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
657 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
658 Cvar_RegisterVariable(&r_shadow_portallight);
659 Cvar_RegisterVariable(&r_shadow_projectdistance);
660 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
661 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
662 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
663 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
664 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
665 Cvar_RegisterVariable(&r_shadow_realtime_world);
666 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
667 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
668 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
669 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
670 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
671 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
672 Cvar_RegisterVariable(&r_shadow_scissor);
673 Cvar_RegisterVariable(&r_shadow_shadowmapping);
674 Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
675 Cvar_RegisterVariable(&r_shadow_shadowmapping_texturetype);
676 Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
677 Cvar_RegisterVariable(&r_shadow_shadowmapping_depthbits);
678 Cvar_RegisterVariable(&r_shadow_shadowmapping_precision);
679 Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
680 Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
681 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
682 // Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
683 Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
684 Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
685 Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
686 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonfactor);
687 Cvar_RegisterVariable(&r_shadow_shadowmapping_polygonoffset);
688 Cvar_RegisterVariable(&r_shadow_culltriangles);
689 Cvar_RegisterVariable(&r_shadow_polygonfactor);
690 Cvar_RegisterVariable(&r_shadow_polygonoffset);
691 Cvar_RegisterVariable(&r_shadow_texture3d);
692 Cvar_RegisterVariable(&r_coronas);
693 Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
694 Cvar_RegisterVariable(&r_coronas_occlusionquery);
695 Cvar_RegisterVariable(&gl_flashblend);
696 Cvar_RegisterVariable(&gl_ext_separatestencil);
697 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
698 if (gamemode == GAME_TENEBRAE)
700 Cvar_SetValue("r_shadow_gloss", 2);
701 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
703 R_Shadow_EditLights_Init();
704 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
705 maxshadowtriangles = 0;
706 shadowelements = NULL;
707 maxshadowvertices = 0;
708 shadowvertex3f = NULL;
716 shadowmarklist = NULL;
721 shadowsideslist = NULL;
722 r_shadow_buffer_numleafpvsbytes = 0;
723 r_shadow_buffer_visitingleafpvs = NULL;
724 r_shadow_buffer_leafpvs = NULL;
725 r_shadow_buffer_leaflist = NULL;
726 r_shadow_buffer_numsurfacepvsbytes = 0;
727 r_shadow_buffer_surfacepvs = NULL;
728 r_shadow_buffer_surfacelist = NULL;
729 r_shadow_buffer_surfacesides = NULL;
730 r_shadow_buffer_shadowtrispvs = NULL;
731 r_shadow_buffer_lighttrispvs = NULL;
732 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
735 matrix4x4_t matrix_attenuationxyz =
738 {0.5, 0.0, 0.0, 0.5},
739 {0.0, 0.5, 0.0, 0.5},
740 {0.0, 0.0, 0.5, 0.5},
745 matrix4x4_t matrix_attenuationz =
748 {0.0, 0.0, 0.5, 0.5},
749 {0.0, 0.0, 0.0, 0.5},
750 {0.0, 0.0, 0.0, 0.5},
755 void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles, int vertscale, int triscale)
757 numvertices = ((numvertices + 255) & ~255) * vertscale;
758 numtriangles = ((numtriangles + 255) & ~255) * triscale;
759 // make sure shadowelements is big enough for this volume
760 if (maxshadowtriangles < numtriangles)
762 maxshadowtriangles = numtriangles;
764 Mem_Free(shadowelements);
765 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[3]));
767 // make sure shadowvertex3f is big enough for this volume
768 if (maxshadowvertices < numvertices)
770 maxshadowvertices = numvertices;
772 Mem_Free(shadowvertex3f);
773 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[3]));
777 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
779 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
780 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
781 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
782 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
783 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
785 if (r_shadow_buffer_visitingleafpvs)
786 Mem_Free(r_shadow_buffer_visitingleafpvs);
787 if (r_shadow_buffer_leafpvs)
788 Mem_Free(r_shadow_buffer_leafpvs);
789 if (r_shadow_buffer_leaflist)
790 Mem_Free(r_shadow_buffer_leaflist);
791 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
792 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
793 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
794 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
796 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
798 if (r_shadow_buffer_surfacepvs)
799 Mem_Free(r_shadow_buffer_surfacepvs);
800 if (r_shadow_buffer_surfacelist)
801 Mem_Free(r_shadow_buffer_surfacelist);
802 if (r_shadow_buffer_surfacesides)
803 Mem_Free(r_shadow_buffer_surfacesides);
804 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
805 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
806 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
807 r_shadow_buffer_surfacesides = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
809 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
811 if (r_shadow_buffer_shadowtrispvs)
812 Mem_Free(r_shadow_buffer_shadowtrispvs);
813 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
814 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
816 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
818 if (r_shadow_buffer_lighttrispvs)
819 Mem_Free(r_shadow_buffer_lighttrispvs);
820 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
821 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
825 void R_Shadow_PrepareShadowMark(int numtris)
827 // make sure shadowmark is big enough for this volume
828 if (maxshadowmark < numtris)
830 maxshadowmark = numtris;
832 Mem_Free(shadowmark);
834 Mem_Free(shadowmarklist);
835 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
836 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
840 // if shadowmarkcount wrapped we clear the array and adjust accordingly
841 if (shadowmarkcount == 0)
844 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
849 void R_Shadow_PrepareShadowSides(int numtris)
851 if (maxshadowsides < numtris)
853 maxshadowsides = numtris;
855 Mem_Free(shadowsides);
857 Mem_Free(shadowsideslist);
858 shadowsides = (unsigned char *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsides));
859 shadowsideslist = (int *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsideslist));
864 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)
867 int outtriangles = 0, outvertices = 0;
870 float ratio, direction[3], projectvector[3];
872 if (projectdirection)
873 VectorScale(projectdirection, projectdistance, projectvector);
875 VectorClear(projectvector);
877 // create the vertices
878 if (projectdirection)
880 for (i = 0;i < numshadowmarktris;i++)
882 element = inelement3i + shadowmarktris[i] * 3;
883 for (j = 0;j < 3;j++)
885 if (vertexupdate[element[j]] != vertexupdatenum)
887 vertexupdate[element[j]] = vertexupdatenum;
888 vertexremap[element[j]] = outvertices;
889 vertex = invertex3f + element[j] * 3;
890 // project one copy of the vertex according to projectvector
891 VectorCopy(vertex, outvertex3f);
892 VectorAdd(vertex, projectvector, (outvertex3f + 3));
901 for (i = 0;i < numshadowmarktris;i++)
903 element = inelement3i + shadowmarktris[i] * 3;
904 for (j = 0;j < 3;j++)
906 if (vertexupdate[element[j]] != vertexupdatenum)
908 vertexupdate[element[j]] = vertexupdatenum;
909 vertexremap[element[j]] = outvertices;
910 vertex = invertex3f + element[j] * 3;
911 // project one copy of the vertex to the sphere radius of the light
912 // (FIXME: would projecting it to the light box be better?)
913 VectorSubtract(vertex, projectorigin, direction);
914 ratio = projectdistance / VectorLength(direction);
915 VectorCopy(vertex, outvertex3f);
916 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
924 if (r_shadow_frontsidecasting.integer)
926 for (i = 0;i < numshadowmarktris;i++)
928 int remappedelement[3];
930 const int *neighbortriangle;
932 markindex = shadowmarktris[i] * 3;
933 element = inelement3i + markindex;
934 neighbortriangle = inneighbor3i + markindex;
935 // output the front and back triangles
936 outelement3i[0] = vertexremap[element[0]];
937 outelement3i[1] = vertexremap[element[1]];
938 outelement3i[2] = vertexremap[element[2]];
939 outelement3i[3] = vertexremap[element[2]] + 1;
940 outelement3i[4] = vertexremap[element[1]] + 1;
941 outelement3i[5] = vertexremap[element[0]] + 1;
945 // output the sides (facing outward from this triangle)
946 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
948 remappedelement[0] = vertexremap[element[0]];
949 remappedelement[1] = vertexremap[element[1]];
950 outelement3i[0] = remappedelement[1];
951 outelement3i[1] = remappedelement[0];
952 outelement3i[2] = remappedelement[0] + 1;
953 outelement3i[3] = remappedelement[1];
954 outelement3i[4] = remappedelement[0] + 1;
955 outelement3i[5] = remappedelement[1] + 1;
960 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
962 remappedelement[1] = vertexremap[element[1]];
963 remappedelement[2] = vertexremap[element[2]];
964 outelement3i[0] = remappedelement[2];
965 outelement3i[1] = remappedelement[1];
966 outelement3i[2] = remappedelement[1] + 1;
967 outelement3i[3] = remappedelement[2];
968 outelement3i[4] = remappedelement[1] + 1;
969 outelement3i[5] = remappedelement[2] + 1;
974 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
976 remappedelement[0] = vertexremap[element[0]];
977 remappedelement[2] = vertexremap[element[2]];
978 outelement3i[0] = remappedelement[0];
979 outelement3i[1] = remappedelement[2];
980 outelement3i[2] = remappedelement[2] + 1;
981 outelement3i[3] = remappedelement[0];
982 outelement3i[4] = remappedelement[2] + 1;
983 outelement3i[5] = remappedelement[0] + 1;
992 for (i = 0;i < numshadowmarktris;i++)
994 int remappedelement[3];
996 const int *neighbortriangle;
998 markindex = shadowmarktris[i] * 3;
999 element = inelement3i + markindex;
1000 neighbortriangle = inneighbor3i + markindex;
1001 // output the front and back triangles
1002 outelement3i[0] = vertexremap[element[2]];
1003 outelement3i[1] = vertexremap[element[1]];
1004 outelement3i[2] = vertexremap[element[0]];
1005 outelement3i[3] = vertexremap[element[0]] + 1;
1006 outelement3i[4] = vertexremap[element[1]] + 1;
1007 outelement3i[5] = vertexremap[element[2]] + 1;
1011 // output the sides (facing outward from this triangle)
1012 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
1014 remappedelement[0] = vertexremap[element[0]];
1015 remappedelement[1] = vertexremap[element[1]];
1016 outelement3i[0] = remappedelement[0];
1017 outelement3i[1] = remappedelement[1];
1018 outelement3i[2] = remappedelement[1] + 1;
1019 outelement3i[3] = remappedelement[0];
1020 outelement3i[4] = remappedelement[1] + 1;
1021 outelement3i[5] = remappedelement[0] + 1;
1026 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1028 remappedelement[1] = vertexremap[element[1]];
1029 remappedelement[2] = vertexremap[element[2]];
1030 outelement3i[0] = remappedelement[1];
1031 outelement3i[1] = remappedelement[2];
1032 outelement3i[2] = remappedelement[2] + 1;
1033 outelement3i[3] = remappedelement[1];
1034 outelement3i[4] = remappedelement[2] + 1;
1035 outelement3i[5] = remappedelement[1] + 1;
1040 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1042 remappedelement[0] = vertexremap[element[0]];
1043 remappedelement[2] = vertexremap[element[2]];
1044 outelement3i[0] = remappedelement[2];
1045 outelement3i[1] = remappedelement[0];
1046 outelement3i[2] = remappedelement[0] + 1;
1047 outelement3i[3] = remappedelement[2];
1048 outelement3i[4] = remappedelement[0] + 1;
1049 outelement3i[5] = remappedelement[2] + 1;
1057 *outnumvertices = outvertices;
1058 return outtriangles;
1061 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)
1064 int outtriangles = 0, outvertices = 0;
1066 const float *vertex;
1067 float ratio, direction[3], projectvector[3];
1070 if (projectdirection)
1071 VectorScale(projectdirection, projectdistance, projectvector);
1073 VectorClear(projectvector);
1075 for (i = 0;i < numshadowmarktris;i++)
1077 int remappedelement[3];
1079 const int *neighbortriangle;
1081 markindex = shadowmarktris[i] * 3;
1082 neighbortriangle = inneighbor3i + markindex;
1083 side[0] = shadowmark[neighbortriangle[0]] == shadowmarkcount;
1084 side[1] = shadowmark[neighbortriangle[1]] == shadowmarkcount;
1085 side[2] = shadowmark[neighbortriangle[2]] == shadowmarkcount;
1086 if (side[0] + side[1] + side[2] == 0)
1090 element = inelement3i + markindex;
1092 // create the vertices
1093 for (j = 0;j < 3;j++)
1095 if (side[j] + side[j+1] == 0)
1098 if (vertexupdate[k] != vertexupdatenum)
1100 vertexupdate[k] = vertexupdatenum;
1101 vertexremap[k] = outvertices;
1102 vertex = invertex3f + k * 3;
1103 VectorCopy(vertex, outvertex3f);
1104 if (projectdirection)
1106 // project one copy of the vertex according to projectvector
1107 VectorAdd(vertex, projectvector, (outvertex3f + 3));
1111 // project one copy of the vertex to the sphere radius of the light
1112 // (FIXME: would projecting it to the light box be better?)
1113 VectorSubtract(vertex, projectorigin, direction);
1114 ratio = projectdistance / VectorLength(direction);
1115 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1122 // output the sides (facing outward from this triangle)
1125 remappedelement[0] = vertexremap[element[0]];
1126 remappedelement[1] = vertexremap[element[1]];
1127 outelement3i[0] = remappedelement[1];
1128 outelement3i[1] = remappedelement[0];
1129 outelement3i[2] = remappedelement[0] + 1;
1130 outelement3i[3] = remappedelement[1];
1131 outelement3i[4] = remappedelement[0] + 1;
1132 outelement3i[5] = remappedelement[1] + 1;
1139 remappedelement[1] = vertexremap[element[1]];
1140 remappedelement[2] = vertexremap[element[2]];
1141 outelement3i[0] = remappedelement[2];
1142 outelement3i[1] = remappedelement[1];
1143 outelement3i[2] = remappedelement[1] + 1;
1144 outelement3i[3] = remappedelement[2];
1145 outelement3i[4] = remappedelement[1] + 1;
1146 outelement3i[5] = remappedelement[2] + 1;
1153 remappedelement[0] = vertexremap[element[0]];
1154 remappedelement[2] = vertexremap[element[2]];
1155 outelement3i[0] = remappedelement[0];
1156 outelement3i[1] = remappedelement[2];
1157 outelement3i[2] = remappedelement[2] + 1;
1158 outelement3i[3] = remappedelement[0];
1159 outelement3i[4] = remappedelement[2] + 1;
1160 outelement3i[5] = remappedelement[0] + 1;
1167 *outnumvertices = outvertices;
1168 return outtriangles;
1171 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)
1177 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1179 tend = firsttriangle + numtris;
1180 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1182 // surface box entirely inside light box, no box cull
1183 if (projectdirection)
1185 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1187 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
1188 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1189 shadowmarklist[numshadowmark++] = t;
1194 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1195 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
1196 shadowmarklist[numshadowmark++] = t;
1201 // surface box not entirely inside light box, cull each triangle
1202 if (projectdirection)
1204 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1206 v[0] = invertex3f + e[0] * 3;
1207 v[1] = invertex3f + e[1] * 3;
1208 v[2] = invertex3f + e[2] * 3;
1209 TriangleNormal(v[0], v[1], v[2], normal);
1210 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1211 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1212 shadowmarklist[numshadowmark++] = t;
1217 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1219 v[0] = invertex3f + e[0] * 3;
1220 v[1] = invertex3f + e[1] * 3;
1221 v[2] = invertex3f + e[2] * 3;
1222 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1223 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1224 shadowmarklist[numshadowmark++] = t;
1230 qboolean R_Shadow_UseZPass(vec3_t mins, vec3_t maxs)
1235 if (r_shadow_compilingrtlight || !r_shadow_frontsidecasting.integer || !r_shadow_usezpassifpossible.integer)
1237 // check if the shadow volume intersects the near plane
1239 // a ray between the eye and light origin may intersect the caster,
1240 // indicating that the shadow may touch the eye location, however we must
1241 // test the near plane (a polygon), not merely the eye location, so it is
1242 // easiest to enlarge the caster bounding shape slightly for this.
1248 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)
1250 int i, tris, outverts;
1251 if (projectdistance < 0.1)
1253 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
1256 if (!numverts || !nummarktris)
1258 // make sure shadowelements is big enough for this volume
1259 if (maxshadowtriangles < nummarktris*8 || maxshadowvertices < numverts*2)
1260 R_Shadow_ResizeShadowArrays(numverts, nummarktris, 2, 8);
1262 if (maxvertexupdate < numverts)
1264 maxvertexupdate = numverts;
1266 Mem_Free(vertexupdate);
1268 Mem_Free(vertexremap);
1269 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1270 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1271 vertexupdatenum = 0;
1274 if (vertexupdatenum == 0)
1276 vertexupdatenum = 1;
1277 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
1278 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
1281 for (i = 0;i < nummarktris;i++)
1282 shadowmark[marktris[i]] = shadowmarkcount;
1284 if (r_shadow_compilingrtlight)
1286 // if we're compiling an rtlight, capture the mesh
1287 //tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1288 //Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zpass, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1289 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1290 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zfail, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1292 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
1294 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1295 R_Mesh_VertexPointer(shadowvertex3f, 0, 0);
1296 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1300 // decide which type of shadow to generate and set stencil mode
1301 R_Shadow_RenderMode_StencilShadowVolumes(R_Shadow_UseZPass(trismins, trismaxs));
1302 // generate the sides or a solid volume, depending on type
1303 if (r_shadow_rendermode >= R_SHADOW_RENDERMODE_ZPASS_STENCIL && r_shadow_rendermode <= R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE)
1304 tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1306 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1307 r_refdef.stats.lights_dynamicshadowtriangles += tris;
1308 r_refdef.stats.lights_shadowtriangles += tris;
1310 R_Mesh_VertexPointer(shadowvertex3f, 0, 0);
1311 GL_LockArrays(0, outverts);
1312 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
1314 // increment stencil if frontface is infront of depthbuffer
1315 GL_CullFace(r_refdef.view.cullface_front);
1316 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1317 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1318 // decrement stencil if backface is infront of depthbuffer
1319 GL_CullFace(r_refdef.view.cullface_back);
1320 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1322 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
1324 // decrement stencil if backface is behind depthbuffer
1325 GL_CullFace(r_refdef.view.cullface_front);
1326 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1327 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1328 // increment stencil if frontface is behind depthbuffer
1329 GL_CullFace(r_refdef.view.cullface_back);
1330 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1332 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1333 GL_LockArrays(0, 0);
1338 int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias)
1340 // p1, p2, p3 are in the cubemap's local coordinate system
1341 // bias = border/(size - border)
1344 float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1345 dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2),
1346 dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3);
1347 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1349 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1350 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1351 | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1352 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1354 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1355 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1356 | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1358 dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1359 dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2),
1360 dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3);
1361 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1363 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1364 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1365 | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1366 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1368 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1369 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1370 | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1372 dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1373 dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2),
1374 dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3);
1375 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1377 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1378 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1379 | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1380 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1382 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1383 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1384 | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1389 int R_Shadow_CalcBBoxSideMask(const vec3_t mins, const vec3_t maxs, const matrix4x4_t *worldtolight, const matrix4x4_t *radiustolight, float bias)
1391 vec3_t center, radius, lightcenter, lightradius, pmin, pmax;
1392 float dp1, dn1, ap1, an1, dp2, dn2, ap2, an2;
1395 VectorSubtract(maxs, mins, radius);
1396 VectorScale(radius, 0.5f, radius);
1397 VectorAdd(mins, radius, center);
1398 Matrix4x4_Transform(worldtolight, center, lightcenter);
1399 Matrix4x4_Transform3x3(radiustolight, radius, lightradius);
1400 VectorSubtract(lightcenter, lightradius, pmin);
1401 VectorAdd(lightcenter, lightradius, pmax);
1403 dp1 = pmax[0] + pmax[1], dn1 = pmax[0] - pmin[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1404 dp2 = pmin[0] + pmin[1], dn2 = pmin[0] - pmax[1], ap2 = fabs(dp2), an2 = fabs(dn2);
1405 if(ap1 > bias*an1 && ap2 > bias*an2)
1407 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1408 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1409 if(an1 > bias*ap1 && an2 > bias*ap2)
1411 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1412 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1414 dp1 = pmax[1] + pmax[2], dn1 = pmax[1] - pmin[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1415 dp2 = pmin[1] + pmin[2], dn2 = pmin[1] - pmax[2], ap2 = fabs(dp2), an2 = fabs(dn2);
1416 if(ap1 > bias*an1 && ap2 > bias*an2)
1418 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1419 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1420 if(an1 > bias*ap1 && an2 > bias*ap2)
1422 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1423 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1425 dp1 = pmax[2] + pmax[0], dn1 = pmax[2] - pmin[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1426 dp2 = pmin[2] + pmin[0], dn2 = pmin[2] - pmax[0], ap2 = fabs(dp2), an2 = fabs(dn2);
1427 if(ap1 > bias*an1 && ap2 > bias*an2)
1429 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1430 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1431 if(an1 > bias*ap1 && an2 > bias*ap2)
1433 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1434 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1439 #define R_Shadow_CalcEntitySideMask(ent, worldtolight, radiustolight, bias) R_Shadow_CalcBBoxSideMask((ent)->mins, (ent)->maxs, worldtolight, radiustolight, bias)
1441 int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
1443 // p is in the cubemap's local coordinate system
1444 // bias = border/(size - border)
1445 float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn);
1446 float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn);
1447 float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn);
1449 if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
1450 if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
1451 if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
1452 if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
1453 if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
1454 if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
1458 int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
1462 int sides = 0x3F, masks[6] = { 3<<4, 3<<4, 3<<0, 3<<0, 3<<2, 3<<2 };
1463 float scale = (size - 2*border)/size, len;
1464 float bias = border / (float)(size - border), dp, dn, ap, an;
1465 // check if cone enclosing side would cross frustum plane
1466 scale = 2 / (scale*scale + 2);
1467 for (i = 0;i < 5;i++)
1469 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) > -0.03125)
1471 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[i].normal, n);
1472 len = scale*VectorLength2(n);
1473 if(n[0]*n[0] > len) sides &= n[0] < 0 ? ~(1<<0) : ~(2 << 0);
1474 if(n[1]*n[1] > len) sides &= n[1] < 0 ? ~(1<<2) : ~(2 << 2);
1475 if(n[2]*n[2] > len) sides &= n[2] < 0 ? ~(1<<4) : ~(2 << 4);
1477 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[4]) >= r_refdef.farclip - r_refdef.nearclip + 0.03125)
1479 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[4].normal, n);
1480 len = scale*VectorLength(n);
1481 if(n[0]*n[0] > len) sides &= n[0] >= 0 ? ~(1<<0) : ~(2 << 0);
1482 if(n[1]*n[1] > len) sides &= n[1] >= 0 ? ~(1<<2) : ~(2 << 2);
1483 if(n[2]*n[2] > len) sides &= n[2] >= 0 ? ~(1<<4) : ~(2 << 4);
1485 // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results
1486 // check if frustum corners/origin cross plane sides
1487 for (i = 0;i < 5;i++)
1489 Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p);
1490 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn),
1491 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1492 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1493 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn),
1494 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1495 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1496 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn),
1497 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1498 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1500 return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5];
1503 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)
1511 int mask, surfacemask = 0;
1512 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1514 bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
1515 tend = firsttriangle + numtris;
1516 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1518 // surface box entirely inside light box, no box cull
1519 if (projectdirection)
1521 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1523 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1524 TriangleNormal(v[0], v[1], v[2], normal);
1525 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1527 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1528 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1529 surfacemask |= mask;
1532 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;
1533 shadowsides[numshadowsides] = mask;
1534 shadowsideslist[numshadowsides++] = t;
1541 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1543 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1544 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]))
1546 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1547 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1548 surfacemask |= mask;
1551 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;
1552 shadowsides[numshadowsides] = mask;
1553 shadowsideslist[numshadowsides++] = t;
1561 // surface box not entirely inside light box, cull each triangle
1562 if (projectdirection)
1564 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1566 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1567 TriangleNormal(v[0], v[1], v[2], normal);
1568 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1569 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1571 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1572 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1573 surfacemask |= mask;
1576 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;
1577 shadowsides[numshadowsides] = mask;
1578 shadowsideslist[numshadowsides++] = t;
1585 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1587 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1588 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1589 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1591 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1592 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1593 surfacemask |= mask;
1596 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;
1597 shadowsides[numshadowsides] = mask;
1598 shadowsideslist[numshadowsides++] = t;
1607 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)
1609 int i, j, outtriangles = 0;
1610 int *outelement3i[6];
1611 if (!numverts || !numsidetris || !r_shadow_compilingrtlight)
1613 outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5];
1614 // make sure shadowelements is big enough for this mesh
1615 if (maxshadowtriangles < outtriangles)
1616 R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1);
1618 // compute the offset and size of the separate index lists for each cubemap side
1620 for (i = 0;i < 6;i++)
1622 outelement3i[i] = shadowelements + outtriangles * 3;
1623 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles;
1624 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i];
1625 outtriangles += sidetotals[i];
1628 // gather up the (sparse) triangles into separate index lists for each cubemap side
1629 for (i = 0;i < numsidetris;i++)
1631 const int *element = elements + sidetris[i] * 3;
1632 for (j = 0;j < 6;j++)
1634 if (sides[i] & (1 << j))
1636 outelement3i[j][0] = element[0];
1637 outelement3i[j][1] = element[1];
1638 outelement3i[j][2] = element[2];
1639 outelement3i[j] += 3;
1644 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, outtriangles, shadowelements);
1647 static void R_Shadow_MakeTextures_MakeCorona(void)
1651 unsigned char pixels[32][32][4];
1652 for (y = 0;y < 32;y++)
1654 dy = (y - 15.5f) * (1.0f / 16.0f);
1655 for (x = 0;x < 32;x++)
1657 dx = (x - 15.5f) * (1.0f / 16.0f);
1658 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1659 a = bound(0, a, 255);
1660 pixels[y][x][0] = a;
1661 pixels[y][x][1] = a;
1662 pixels[y][x][2] = a;
1663 pixels[y][x][3] = 255;
1666 r_shadow_lightcorona = R_SkinFrame_LoadInternalBGRA("lightcorona", TEXF_PRECACHE | TEXF_FORCELINEAR, &pixels[0][0][0], 32, 32);
1669 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1671 float dist = sqrt(x*x+y*y+z*z);
1672 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1673 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1674 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1677 static void R_Shadow_MakeTextures(void)
1680 float intensity, dist;
1682 R_Shadow_FreeShadowMaps();
1683 R_FreeTexturePool(&r_shadow_texturepool);
1684 r_shadow_texturepool = R_AllocTexturePool();
1685 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1686 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1687 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1688 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1689 for (x = 0;x <= ATTENTABLESIZE;x++)
1691 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1692 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1693 r_shadow_attentable[x] = bound(0, intensity, 1);
1695 // 1D gradient texture
1696 for (x = 0;x < ATTEN1DSIZE;x++)
1697 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1698 r_shadow_attenuationgradienttexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation1d", ATTEN1DSIZE, 1, (unsigned char *)data, TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, NULL);
1699 // 2D circle texture
1700 for (y = 0;y < ATTEN2DSIZE;y++)
1701 for (x = 0;x < ATTEN2DSIZE;x++)
1702 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);
1703 r_shadow_attenuation2dtexture = R_LoadTexture2D(r_shadow_texturepool, "attenuation2d", ATTEN2DSIZE, ATTEN2DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, NULL);
1704 // 3D sphere texture
1705 if (r_shadow_texture3d.integer && vid.support.ext_texture_3d)
1707 for (z = 0;z < ATTEN3DSIZE;z++)
1708 for (y = 0;y < ATTEN3DSIZE;y++)
1709 for (x = 0;x < ATTEN3DSIZE;x++)
1710 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));
1711 r_shadow_attenuation3dtexture = R_LoadTexture3D(r_shadow_texturepool, "attenuation3d", ATTEN3DSIZE, ATTEN3DSIZE, ATTEN3DSIZE, (unsigned char *)data, TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_ALPHA | TEXF_FORCELINEAR, NULL);
1714 r_shadow_attenuation3dtexture = NULL;
1717 R_Shadow_MakeTextures_MakeCorona();
1719 // Editor light sprites
1720 r_editlights_sprcursor = R_SkinFrame_LoadInternal8bit("gfx/editlights/cursor", TEXF_PRECACHE | TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1737 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1738 r_editlights_sprlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/light", TEXF_PRECACHE | TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1755 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1756 r_editlights_sprnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/noshadow", TEXF_PRECACHE | TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1773 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1774 r_editlights_sprcubemaplight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemaplight", TEXF_PRECACHE | TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1791 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1792 r_editlights_sprcubemapnoshadowlight = R_SkinFrame_LoadInternal8bit("gfx/editlights/cubemapnoshadowlight", TEXF_PRECACHE | TEXF_ALPHA | TEXF_CLAMP, (const unsigned char *)
1809 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1810 r_editlights_sprselection = R_SkinFrame_LoadInternal8bit("gfx/editlights/selection", TEXF_PRECACHE | TEXF_ALPHA | TEXF_CLAMP, (unsigned char *)
1827 , 16, 16, palette_bgra_embeddedpic, palette_bgra_embeddedpic);
1830 void R_Shadow_ValidateCvars(void)
1832 if (r_shadow_texture3d.integer && !vid.support.ext_texture_3d)
1833 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1834 if (gl_ext_separatestencil.integer && !vid.support.ati_separate_stencil)
1835 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
1836 if (gl_ext_stenciltwoside.integer && !vid.support.ext_stencil_two_side)
1837 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1840 void R_Shadow_RenderMode_Begin(void)
1846 R_Shadow_ValidateCvars();
1848 if (!r_shadow_attenuation2dtexture
1849 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1850 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1851 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1852 R_Shadow_MakeTextures();
1855 R_Mesh_ColorPointer(NULL, 0, 0);
1856 R_Mesh_ResetTextureState();
1857 GL_BlendFunc(GL_ONE, GL_ZERO);
1858 GL_DepthRange(0, 1);
1859 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1861 GL_DepthMask(false);
1862 GL_Color(0, 0, 0, 1);
1863 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1865 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1867 if (gl_ext_separatestencil.integer && vid.support.ati_separate_stencil)
1869 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
1870 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
1872 else if (gl_ext_stenciltwoside.integer && vid.support.ext_stencil_two_side)
1874 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
1875 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
1879 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
1880 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
1883 switch(vid.renderpath)
1885 case RENDERPATH_GL20:
1886 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1888 case RENDERPATH_GL13:
1889 case RENDERPATH_GL11:
1890 if (r_textureunits.integer >= 2 && vid.texunits >= 2 && r_shadow_texture3d.integer && r_shadow_attenuation3dtexture)
1891 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN;
1892 else if (r_textureunits.integer >= 3 && vid.texunits >= 3)
1893 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN;
1894 else if (r_textureunits.integer >= 2 && vid.texunits >= 2)
1895 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN;
1897 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1903 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
1904 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
1905 r_shadow_drawbuffer = drawbuffer;
1906 r_shadow_readbuffer = readbuffer;
1908 r_shadow_cullface_front = r_refdef.view.cullface_front;
1909 r_shadow_cullface_back = r_refdef.view.cullface_back;
1912 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
1914 rsurface.rtlight = rtlight;
1917 void R_Shadow_RenderMode_Reset(void)
1920 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE)
1922 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1924 if (vid.support.ext_framebuffer_object)
1926 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);CHECKGLERROR
1929 qglDrawBuffer(r_shadow_drawbuffer);CHECKGLERROR
1930 qglReadBuffer(r_shadow_readbuffer);CHECKGLERROR
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_ColorPointer(NULL, 0, 0);
1935 R_Mesh_ResetTextureState();
1936 GL_DepthRange(0, 1);
1938 GL_DepthMask(false);
1939 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1940 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1941 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
1942 qglStencilMask(~0);CHECKGLERROR
1943 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
1944 qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
1945 r_refdef.view.cullface_front = r_shadow_cullface_front;
1946 r_refdef.view.cullface_back = r_shadow_cullface_back;
1947 GL_CullFace(r_refdef.view.cullface_back);
1948 GL_Color(1, 1, 1, 1);
1949 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
1950 GL_BlendFunc(GL_ONE, GL_ZERO);
1951 R_SetupGenericShader(false);
1952 r_shadow_usingshadowmaprect = false;
1953 r_shadow_usingshadowmapcube = false;
1954 r_shadow_usingshadowmap2d = false;
1958 void R_Shadow_ClearStencil(void)
1961 GL_Clear(GL_STENCIL_BUFFER_BIT);
1962 r_refdef.stats.lights_clears++;
1965 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
1967 r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
1968 if (r_shadow_rendermode == mode)
1971 R_Shadow_RenderMode_Reset();
1972 GL_ColorMask(0, 0, 0, 0);
1973 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1974 R_SetupDepthOrShadowShader();
1975 qglDepthFunc(GL_LESS);CHECKGLERROR
1976 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1977 r_shadow_rendermode = mode;
1982 case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
1983 GL_CullFace(GL_NONE);
1984 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1985 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1987 case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
1988 GL_CullFace(GL_NONE);
1989 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1990 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1992 case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
1993 GL_CullFace(GL_NONE);
1994 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1995 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
1996 qglStencilMask(~0);CHECKGLERROR
1997 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1998 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
1999 qglStencilMask(~0);CHECKGLERROR
2000 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
2002 case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
2003 GL_CullFace(GL_NONE);
2004 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
2005 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
2006 qglStencilMask(~0);CHECKGLERROR
2007 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
2008 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
2009 qglStencilMask(~0);CHECKGLERROR
2010 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
2015 static void R_Shadow_MakeVSDCT(void)
2017 // maps to a 2x3 texture rectangle with normalized coordinates
2022 // stores abs(dir.xy), offset.xy/2.5
2023 unsigned char data[4*6] =
2025 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
2026 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
2027 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
2028 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
2029 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
2030 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
2032 r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_ALWAYSPRECACHE | TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, NULL);
2035 void R_Shadow_RenderMode_ShadowMap(int side, qboolean clear, int size)
2039 float nearclip, farclip, bias;
2040 r_viewport_t viewport;
2043 maxsize = r_shadow_shadowmapmaxsize;
2044 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
2046 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
2047 r_shadow_shadowmap_parameters[2] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
2048 r_shadow_shadowmap_parameters[3] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
2049 r_shadow_shadowmapside = side;
2050 r_shadow_shadowmapsize = size;
2051 if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
2053 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2054 r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2055 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
2056 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D) goto init_done;
2058 // complex unrolled cube approach (more flexible)
2059 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2060 R_Shadow_MakeVSDCT();
2061 if (!r_shadow_shadowmap2dtexture)
2064 int w = maxsize*2, h = vid.support.arb_texture_non_power_of_two ? maxsize*3 : maxsize*4;
2065 r_shadow_shadowmap2dtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "shadowmap", w, h, r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
2066 qglGenFramebuffersEXT(1, &r_shadow_fbo2d);CHECKGLERROR
2067 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbo2d);CHECKGLERROR
2068 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_shadowmap2dtexture), 0);CHECKGLERROR
2069 // render depth into the fbo, do not render color at all
2070 qglDrawBuffer(GL_NONE);CHECKGLERROR
2071 qglReadBuffer(GL_NONE);CHECKGLERROR
2072 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2073 if (status != GL_FRAMEBUFFER_COMPLETE_EXT && r_shadow_shadowmapping.integer)
2075 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2076 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2081 if (r_shadow_shadowmap2dtexture) fbo = r_shadow_fbo2d;
2082 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
2083 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
2084 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
2086 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE)
2088 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
2089 r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
2090 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
2091 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE) goto init_done;
2093 // complex unrolled cube approach (more flexible)
2094 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
2095 R_Shadow_MakeVSDCT();
2096 if (!r_shadow_shadowmaprectangletexture)
2099 r_shadow_shadowmaprectangletexture = R_LoadTextureShadowMapRectangle(r_shadow_texturepool, "shadowmap", maxsize*2, maxsize*3, r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
2100 qglGenFramebuffersEXT(1, &r_shadow_fborectangle);CHECKGLERROR
2101 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fborectangle);CHECKGLERROR
2102 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, R_GetTexture(r_shadow_shadowmaprectangletexture), 0);CHECKGLERROR
2103 // render depth into the fbo, do not render color at all
2104 qglDrawBuffer(GL_NONE);CHECKGLERROR
2105 qglReadBuffer(GL_NONE);CHECKGLERROR
2106 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2107 if (status != GL_FRAMEBUFFER_COMPLETE_EXT && r_shadow_shadowmapping.integer)
2109 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2110 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2115 if(r_shadow_shadowmaprectangletexture) fbo = r_shadow_fborectangle;
2116 r_shadow_shadowmap_texturescale[0] = 1.0f;
2117 r_shadow_shadowmap_texturescale[1] = 1.0f;
2118 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE;
2120 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
2122 r_shadow_shadowmap_parameters[0] = 1.0f;
2123 r_shadow_shadowmap_parameters[1] = 1.0f;
2124 R_Viewport_InitCubeSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, nearclip, farclip, NULL);
2125 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE) goto init_done;
2127 // simple cube approach
2128 if (!r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod])
2131 r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod] = R_LoadTextureShadowMapCube(r_shadow_texturepool, "shadowmapcube", size, r_shadow_shadowmapdepthbits, r_shadow_shadowmapsampler);
2132 qglGenFramebuffersEXT(1, &r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR
2133 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR
2134 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + side, R_GetTexture(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]), 0);CHECKGLERROR
2135 // render depth into the fbo, do not render color at all
2136 qglDrawBuffer(GL_NONE);CHECKGLERROR
2137 qglReadBuffer(GL_NONE);CHECKGLERROR
2138 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2139 if (status != GL_FRAMEBUFFER_COMPLETE_EXT && r_shadow_shadowmapping.integer)
2141 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2142 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2147 if (r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]) fbo = r_shadow_fbocubeside[r_shadow_shadowmaplod];
2148 r_shadow_shadowmap_texturescale[0] = 0.0f;
2149 r_shadow_shadowmap_texturescale[1] = 0.0f;
2150 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE;
2153 R_Shadow_RenderMode_Reset();
2156 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);CHECKGLERROR
2157 R_SetupDepthOrShadowShader();
2161 R_SetupShowDepthShader();
2162 qglClearColor(1,1,1,1);CHECKGLERROR
2165 GL_PolygonOffset(r_shadow_shadowmapping_polygonfactor.value, r_shadow_shadowmapping_polygonoffset.value);
2172 R_SetViewport(&viewport);
2173 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2174 if(r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE)
2176 int flipped = (side&1)^(side>>2);
2177 r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
2178 r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
2179 GL_CullFace(r_refdef.view.cullface_back);
2181 else if(r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE)
2183 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + side, R_GetTexture(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]), 0);CHECKGLERROR
2186 qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
2190 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
2194 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2195 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2196 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2197 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2200 R_Shadow_RenderMode_Reset();
2201 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2204 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2208 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2209 // only draw light where this geometry was already rendered AND the
2210 // stencil is 128 (values other than this mean shadow)
2211 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
2213 r_shadow_rendermode = r_shadow_lightingrendermode;
2214 // do global setup needed for the chosen lighting mode
2215 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2217 R_Mesh_TexBindAll(GL20TU_CUBE, 0, 0, R_GetTexture(rsurface.rtlight->currentcubemap), 0); // light filter
2218 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2222 if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D)
2224 r_shadow_usingshadowmap2d = true;
2225 R_Mesh_TexBind(GL20TU_SHADOWMAP2D, R_GetTexture(r_shadow_shadowmap2dtexture));
2228 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE)
2230 r_shadow_usingshadowmaprect = true;
2231 R_Mesh_TexBindAll(GL20TU_SHADOWMAPRECT, 0, 0, 0, R_GetTexture(r_shadow_shadowmaprectangletexture));
2234 else if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
2236 r_shadow_usingshadowmapcube = true;
2237 R_Mesh_TexBindAll(GL20TU_SHADOWMAPCUBE, 0, 0, R_GetTexture(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]), 0);
2241 if (r_shadow_shadowmapvsdct && (r_shadow_usingshadowmap2d || r_shadow_usingshadowmaprect))
2243 R_Mesh_TexBindAll(GL20TU_CUBEPROJECTION, 0, 0, R_GetTexture(r_shadow_shadowmapvsdcttexture), 0);
2248 R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
2249 //GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2253 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
2256 R_Shadow_RenderMode_Reset();
2257 GL_BlendFunc(GL_ONE, GL_ONE);
2258 GL_DepthRange(0, 1);
2259 GL_DepthTest(r_showshadowvolumes.integer < 2);
2260 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
2261 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2262 GL_CullFace(GL_NONE);
2263 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
2266 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
2269 R_Shadow_RenderMode_Reset();
2270 GL_BlendFunc(GL_ONE, GL_ONE);
2271 GL_DepthRange(0, 1);
2272 GL_DepthTest(r_showlighting.integer < 2);
2273 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2276 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2280 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2281 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
2283 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2286 void R_Shadow_RenderMode_End(void)
2289 R_Shadow_RenderMode_Reset();
2290 R_Shadow_RenderMode_ActiveLight(NULL);
2292 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2293 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2296 int bboxedges[12][2] =
2315 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2317 int i, ix1, iy1, ix2, iy2;
2318 float x1, y1, x2, y2;
2320 float vertex[20][3];
2329 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2330 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2331 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2332 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2334 if (!r_shadow_scissor.integer)
2337 // if view is inside the light box, just say yes it's visible
2338 if (BoxesOverlap(r_refdef.view.origin, r_refdef.view.origin, mins, maxs))
2341 x1 = y1 = x2 = y2 = 0;
2343 // transform all corners that are infront of the nearclip plane
2344 VectorNegate(r_refdef.view.frustum[4].normal, plane4f);
2345 plane4f[3] = r_refdef.view.frustum[4].dist;
2347 for (i = 0;i < 8;i++)
2349 Vector4Set(corner[i], (i & 1) ? maxs[0] : mins[0], (i & 2) ? maxs[1] : mins[1], (i & 4) ? maxs[2] : mins[2], 1);
2350 dist[i] = DotProduct4(corner[i], plane4f);
2351 sign[i] = dist[i] > 0;
2354 VectorCopy(corner[i], vertex[numvertices]);
2358 // if some points are behind the nearclip, add clipped edge points to make
2359 // sure that the scissor boundary is complete
2360 if (numvertices > 0 && numvertices < 8)
2362 // add clipped edge points
2363 for (i = 0;i < 12;i++)
2365 j = bboxedges[i][0];
2366 k = bboxedges[i][1];
2367 if (sign[j] != sign[k])
2369 f = dist[j] / (dist[j] - dist[k]);
2370 VectorLerp(corner[j], f, corner[k], vertex[numvertices]);
2376 // if we have no points to check, the light is behind the view plane
2380 // if we have some points to transform, check what screen area is covered
2381 x1 = y1 = x2 = y2 = 0;
2383 //Con_Printf("%i vertices to transform...\n", numvertices);
2384 for (i = 0;i < numvertices;i++)
2386 VectorCopy(vertex[i], v);
2387 R_Viewport_TransformToScreen(&r_refdef.view.viewport, v, v2);
2388 //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]);
2391 if (x1 > v2[0]) x1 = v2[0];
2392 if (x2 < v2[0]) x2 = v2[0];
2393 if (y1 > v2[1]) y1 = v2[1];
2394 if (y2 < v2[1]) y2 = v2[1];
2403 // now convert the scissor rectangle to integer screen coordinates
2404 ix1 = (int)(x1 - 1.0f);
2405 iy1 = vid.height - (int)(y2 - 1.0f);
2406 ix2 = (int)(x2 + 1.0f);
2407 iy2 = vid.height - (int)(y1 + 1.0f);
2408 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
2410 // clamp it to the screen
2411 if (ix1 < r_refdef.view.viewport.x) ix1 = r_refdef.view.viewport.x;
2412 if (iy1 < r_refdef.view.viewport.y) iy1 = r_refdef.view.viewport.y;
2413 if (ix2 > r_refdef.view.viewport.x + r_refdef.view.viewport.width) ix2 = r_refdef.view.viewport.x + r_refdef.view.viewport.width;
2414 if (iy2 > r_refdef.view.viewport.y + r_refdef.view.viewport.height) iy2 = r_refdef.view.viewport.y + r_refdef.view.viewport.height;
2416 // if it is inside out, it's not visible
2417 if (ix2 <= ix1 || iy2 <= iy1)
2420 // the light area is visible, set up the scissor rectangle
2421 r_shadow_lightscissor[0] = ix1;
2422 r_shadow_lightscissor[1] = iy1;
2423 r_shadow_lightscissor[2] = ix2 - ix1;
2424 r_shadow_lightscissor[3] = iy2 - iy1;
2426 r_refdef.stats.lights_scissored++;
2430 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, int numtriangles, const int *element3i, const float *diffusecolor, const float *ambientcolor)
2432 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
2433 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
2434 float *color4f = rsurface.array_color4f + 4 * firstvertex;
2435 float dist, dot, distintensity, shadeintensity, v[3], n[3];
2436 switch (r_shadow_rendermode)
2438 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2439 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2440 if (VectorLength2(diffusecolor) > 0)
2442 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2444 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2445 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2446 if ((dot = DotProduct(n, v)) < 0)
2448 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2449 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
2452 VectorCopy(ambientcolor, color4f);
2453 if (r_refdef.fogenabled)
2456 f = RSurf_FogVertex(vertex3f);
2457 VectorScale(color4f, f, color4f);
2464 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2466 VectorCopy(ambientcolor, color4f);
2467 if (r_refdef.fogenabled)
2470 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2471 f = RSurf_FogVertex(vertex3f);
2472 VectorScale(color4f, f, color4f);
2478 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2479 if (VectorLength2(diffusecolor) > 0)
2481 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2483 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2484 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2486 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2487 if ((dot = DotProduct(n, v)) < 0)
2489 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2490 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2491 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2492 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2496 color4f[0] = ambientcolor[0] * distintensity;
2497 color4f[1] = ambientcolor[1] * distintensity;
2498 color4f[2] = ambientcolor[2] * distintensity;
2500 if (r_refdef.fogenabled)
2503 f = RSurf_FogVertex(vertex3f);
2504 VectorScale(color4f, f, color4f);
2508 VectorClear(color4f);
2514 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2516 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2517 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2519 color4f[0] = ambientcolor[0] * distintensity;
2520 color4f[1] = ambientcolor[1] * distintensity;
2521 color4f[2] = ambientcolor[2] * distintensity;
2522 if (r_refdef.fogenabled)
2525 f = RSurf_FogVertex(vertex3f);
2526 VectorScale(color4f, f, color4f);
2530 VectorClear(color4f);
2535 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2536 if (VectorLength2(diffusecolor) > 0)
2538 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2540 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2541 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2543 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2544 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2545 if ((dot = DotProduct(n, v)) < 0)
2547 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2548 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2549 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2550 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2554 color4f[0] = ambientcolor[0] * distintensity;
2555 color4f[1] = ambientcolor[1] * distintensity;
2556 color4f[2] = ambientcolor[2] * distintensity;
2558 if (r_refdef.fogenabled)
2561 f = RSurf_FogVertex(vertex3f);
2562 VectorScale(color4f, f, color4f);
2566 VectorClear(color4f);
2572 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2574 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2575 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2577 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2578 color4f[0] = ambientcolor[0] * distintensity;
2579 color4f[1] = ambientcolor[1] * distintensity;
2580 color4f[2] = ambientcolor[2] * distintensity;
2581 if (r_refdef.fogenabled)
2584 f = RSurf_FogVertex(vertex3f);
2585 VectorScale(color4f, f, color4f);
2589 VectorClear(color4f);
2599 static void R_Shadow_RenderLighting_VisibleLighting(int firstvertex, int numvertices, int firsttriangle, int numtriangles, const int *element3i, const unsigned short *element3s, int element3i_bufferobject, int element3s_bufferobject, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float ambientscale, float diffusescale, float specularscale, qboolean dopants, qboolean doshirt)
2601 // used to display how many times a surface is lit for level design purposes
2602 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2605 static void R_Shadow_RenderLighting_Light_GLSL(int firstvertex, int numvertices, int firsttriangle, int numtriangles, const int *element3i, const unsigned short *element3s, int element3i_bufferobject, int element3s_bufferobject, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float ambientscale, float diffusescale, float specularscale, qboolean dopants, qboolean doshirt)
2607 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2608 R_SetupSurfaceShader(lightcolorbase, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT);
2609 if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND))
2610 R_Mesh_ColorPointer(rsurface.modellightmapcolor4f, rsurface.modellightmapcolor4f_bufferobject, rsurface.modellightmapcolor4f_bufferoffset);
2612 R_Mesh_ColorPointer(NULL, 0, 0);
2613 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
2614 R_Mesh_TexMatrix(1, &rsurface.texture->currentbackgroundtexmatrix);
2615 R_Mesh_TexBind(GL20TU_NORMAL, R_GetTexture(rsurface.texture->currentskinframe->nmap));
2616 R_Mesh_TexBind(GL20TU_COLOR, R_GetTexture(rsurface.texture->basetexture));
2617 R_Mesh_TexBind(GL20TU_GLOSS, R_GetTexture(rsurface.texture->glosstexture));
2618 if (rsurface.texture->backgroundcurrentskinframe)
2620 R_Mesh_TexBind(GL20TU_SECONDARY_NORMAL, R_GetTexture(rsurface.texture->backgroundcurrentskinframe->nmap));
2621 R_Mesh_TexBind(GL20TU_SECONDARY_COLOR, R_GetTexture(rsurface.texture->backgroundbasetexture));
2622 R_Mesh_TexBind(GL20TU_SECONDARY_GLOSS, R_GetTexture(rsurface.texture->backgroundglosstexture));
2623 R_Mesh_TexBind(GL20TU_SECONDARY_GLOW, R_GetTexture(rsurface.texture->backgroundcurrentskinframe->glow));
2625 //R_Mesh_TexBindAll(GL20TU_CUBE, 0, 0, R_GetTexture(rsurface.rtlight->currentcubemap), 0);
2626 R_Mesh_TexBind(GL20TU_FOGMASK, R_GetTexture(r_texture_fogattenuation));
2627 if(rsurface.texture->colormapping)
2629 R_Mesh_TexBind(GL20TU_PANTS, R_GetTexture(rsurface.texture->currentskinframe->pants));
2630 R_Mesh_TexBind(GL20TU_SHIRT, R_GetTexture(rsurface.texture->currentskinframe->shirt));
2632 R_Mesh_TexBind(GL20TU_ATTENUATION, R_GetTexture(r_shadow_attenuationgradienttexture));
2633 R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
2634 R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset);
2635 R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset);
2636 R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset);
2637 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2639 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2641 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2642 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2644 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
2648 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
2655 int newnumtriangles;
2659 int maxtriangles = 4096;
2660 int newelements[4096*3];
2661 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, numtriangles, element3i, diffusecolor2, ambientcolor2);
2662 for (renders = 0;renders < 64;renders++)
2667 newnumtriangles = 0;
2669 // due to low fillrate on the cards this vertex lighting path is
2670 // designed for, we manually cull all triangles that do not
2671 // contain a lit vertex
2672 // this builds batches of triangles from multiple surfaces and
2673 // renders them at once
2674 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
2676 if (VectorLength2(rsurface.array_color4f + e[0] * 4) + VectorLength2(rsurface.array_color4f + e[1] * 4) + VectorLength2(rsurface.array_color4f + e[2] * 4) >= 0.01)
2678 if (newnumtriangles)
2680 newfirstvertex = min(newfirstvertex, e[0]);
2681 newlastvertex = max(newlastvertex, e[0]);
2685 newfirstvertex = e[0];
2686 newlastvertex = e[0];
2688 newfirstvertex = min(newfirstvertex, e[1]);
2689 newlastvertex = max(newlastvertex, e[1]);
2690 newfirstvertex = min(newfirstvertex, e[2]);
2691 newlastvertex = max(newlastvertex, e[2]);
2697 if (newnumtriangles >= maxtriangles)
2699 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
2700 newnumtriangles = 0;
2706 if (newnumtriangles >= 1)
2708 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
2711 // if we couldn't find any lit triangles, exit early
2714 // now reduce the intensity for the next overbright pass
2715 // we have to clamp to 0 here incase the drivers have improper
2716 // handling of negative colors
2717 // (some old drivers even have improper handling of >1 color)
2719 for (i = 0, c = rsurface.array_color4f + 4 * firstvertex;i < numvertices;i++, c += 4)
2721 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
2723 c[0] = max(0, c[0] - 1);
2724 c[1] = max(0, c[1] - 1);
2725 c[2] = max(0, c[2] - 1);
2737 static void R_Shadow_RenderLighting_Light_Vertex(int firstvertex, int numvertices, int numtriangles, const int *element3i, const vec3_t lightcolorbase, const vec3_t lightcolorpants, const vec3_t lightcolorshirt, rtexture_t *basetexture, rtexture_t *pantstexture, rtexture_t *shirttexture, rtexture_t *normalmaptexture, rtexture_t *glosstexture, float ambientscale, float diffusescale, float specularscale, qboolean dopants, qboolean doshirt)
2739 // OpenGL 1.1 path (anything)
2740 float ambientcolorbase[3], diffusecolorbase[3];
2741 float ambientcolorpants[3], diffusecolorpants[3];
2742 float ambientcolorshirt[3], diffusecolorshirt[3];
2744 VectorScale(lightcolorbase, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorbase);
2745 VectorScale(lightcolorbase, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorbase);
2746 VectorScale(lightcolorpants, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorpants);
2747 VectorScale(lightcolorpants, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorpants);
2748 VectorScale(lightcolorshirt, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorshirt);
2749 VectorScale(lightcolorshirt, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorshirt);
2750 switch(r_shadow_rendermode)
2752 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2753 memset(&m, 0, sizeof(m));
2754 m.tex[0] = R_GetTexture(basetexture);
2755 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2756 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2757 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2758 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2759 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2760 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2761 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2762 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2763 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2764 R_Mesh_TextureState(&m);
2766 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2767 memset(&m, 0, sizeof(m));
2768 m.tex[0] = R_GetTexture(basetexture);
2769 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2770 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2771 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2772 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2773 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2774 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2775 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2776 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2777 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2778 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2779 m.texmatrix[2] = rsurface.entitytoattenuationz;
2780 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2781 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2782 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2783 R_Mesh_TextureState(&m);
2785 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2786 memset(&m, 0, sizeof(m));
2787 m.tex[0] = R_GetTexture(basetexture);
2788 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2789 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2790 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2791 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2792 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2793 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2794 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2795 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2796 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2797 R_Mesh_TextureState(&m);
2799 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2800 memset(&m, 0, sizeof(m));
2801 m.tex[0] = R_GetTexture(basetexture);
2802 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2803 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2804 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2805 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2806 R_Mesh_TextureState(&m);
2811 //R_Mesh_TexBind(0, R_GetTexture(basetexture));
2812 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorbase, ambientcolorbase);
2815 R_Mesh_TexBind(0, R_GetTexture(pantstexture));
2816 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorpants, ambientcolorpants);
2820 R_Mesh_TexBind(0, R_GetTexture(shirttexture));
2821 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorshirt, ambientcolorshirt);
2825 extern cvar_t gl_lightmaps;
2826 void R_Shadow_RenderLighting(int firstvertex, int numvertices, int firsttriangle, int numtriangles, const int *element3i, const unsigned short *element3s, int element3i_bufferobject, int element3s_bufferobject)
2828 float ambientscale, diffusescale, specularscale;
2830 vec3_t lightcolorbase, lightcolorpants, lightcolorshirt;
2832 // calculate colors to render this texture with
2833 lightcolorbase[0] = rsurface.rtlight->currentcolor[0] * rsurface.texture->dlightcolor[0];
2834 lightcolorbase[1] = rsurface.rtlight->currentcolor[1] * rsurface.texture->dlightcolor[1];
2835 lightcolorbase[2] = rsurface.rtlight->currentcolor[2] * rsurface.texture->dlightcolor[2];
2836 ambientscale = rsurface.rtlight->ambientscale;
2837 diffusescale = rsurface.rtlight->diffusescale;
2838 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
2839 if (!r_shadow_usenormalmap.integer)
2841 ambientscale += 1.0f * diffusescale;
2845 if ((ambientscale + diffusescale) * VectorLength2(lightcolorbase) + specularscale * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
2847 negated = (lightcolorbase[0] + lightcolorbase[1] + lightcolorbase[2] < 0) && vid.support.ext_blend_subtract;
2850 VectorNegate(lightcolorbase, lightcolorbase);
2851 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
2853 RSurf_SetupDepthAndCulling();
2854 nmap = rsurface.texture->currentskinframe->nmap;
2855 if (gl_lightmaps.integer)
2856 nmap = r_texture_blanknormalmap;
2857 if (rsurface.texture->colormapping && !gl_lightmaps.integer)
2859 qboolean dopants = rsurface.texture->currentskinframe->pants != NULL && VectorLength2(rsurface.colormap_pantscolor) >= (1.0f / 1048576.0f);
2860 qboolean doshirt = rsurface.texture->currentskinframe->shirt != NULL && VectorLength2(rsurface.colormap_shirtcolor) >= (1.0f / 1048576.0f);
2863 lightcolorpants[0] = lightcolorbase[0] * rsurface.colormap_pantscolor[0];
2864 lightcolorpants[1] = lightcolorbase[1] * rsurface.colormap_pantscolor[1];
2865 lightcolorpants[2] = lightcolorbase[2] * rsurface.colormap_pantscolor[2];
2868 VectorClear(lightcolorpants);
2871 lightcolorshirt[0] = lightcolorbase[0] * rsurface.colormap_shirtcolor[0];
2872 lightcolorshirt[1] = lightcolorbase[1] * rsurface.colormap_shirtcolor[1];
2873 lightcolorshirt[2] = lightcolorbase[2] * rsurface.colormap_shirtcolor[2];
2876 VectorClear(lightcolorshirt);
2877 switch (r_shadow_rendermode)
2879 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2880 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2881 R_Shadow_RenderLighting_VisibleLighting(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface.texture->basetexture, rsurface.texture->currentskinframe->pants, rsurface.texture->currentskinframe->shirt, nmap, rsurface.texture->glosstexture, ambientscale, diffusescale, specularscale, dopants, doshirt);
2883 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2884 R_Shadow_RenderLighting_Light_GLSL(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface.texture->basetexture, rsurface.texture->currentskinframe->pants, rsurface.texture->currentskinframe->shirt, nmap, rsurface.texture->glosstexture, ambientscale, diffusescale, specularscale, dopants, doshirt);
2886 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2887 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2888 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2889 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2890 R_Shadow_RenderLighting_Light_Vertex(firstvertex, numvertices, numtriangles, element3i + firsttriangle * 3, lightcolorbase, lightcolorpants, lightcolorshirt, rsurface.texture->basetexture, rsurface.texture->currentskinframe->pants, rsurface.texture->currentskinframe->shirt, nmap, rsurface.texture->glosstexture, ambientscale, diffusescale, specularscale, dopants, doshirt);
2893 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2899 switch (r_shadow_rendermode)
2901 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
2902 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
2903 R_Shadow_RenderLighting_VisibleLighting(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, vec3_origin, vec3_origin, rsurface.texture->basetexture, r_texture_black, r_texture_black, nmap, rsurface.texture->glosstexture, ambientscale, diffusescale, specularscale, false, false);
2905 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
2906 R_Shadow_RenderLighting_Light_GLSL(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, vec3_origin, vec3_origin, rsurface.texture->basetexture, r_texture_black, r_texture_black, nmap, rsurface.texture->glosstexture, ambientscale, diffusescale, specularscale, false, false);
2908 case R_SHADOW_RENDERMODE_LIGHT_VERTEX3DATTEN:
2909 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2D1DATTEN:
2910 case R_SHADOW_RENDERMODE_LIGHT_VERTEX2DATTEN:
2911 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
2912 R_Shadow_RenderLighting_Light_Vertex(firstvertex, numvertices, numtriangles, element3i + firsttriangle * 3, lightcolorbase, vec3_origin, vec3_origin, rsurface.texture->basetexture, r_texture_black, r_texture_black, nmap, rsurface.texture->glosstexture, ambientscale, diffusescale, specularscale, false, false);
2915 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
2920 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
2923 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)
2925 matrix4x4_t tempmatrix = *matrix;
2926 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
2928 // if this light has been compiled before, free the associated data
2929 R_RTLight_Uncompile(rtlight);
2931 // clear it completely to avoid any lingering data
2932 memset(rtlight, 0, sizeof(*rtlight));
2934 // copy the properties
2935 rtlight->matrix_lighttoworld = tempmatrix;
2936 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
2937 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
2938 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
2939 VectorCopy(color, rtlight->color);
2940 rtlight->cubemapname[0] = 0;
2941 if (cubemapname && cubemapname[0])
2942 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
2943 rtlight->shadow = shadow;
2944 rtlight->corona = corona;
2945 rtlight->style = style;
2946 rtlight->isstatic = isstatic;
2947 rtlight->coronasizescale = coronasizescale;
2948 rtlight->ambientscale = ambientscale;
2949 rtlight->diffusescale = diffusescale;
2950 rtlight->specularscale = specularscale;
2951 rtlight->flags = flags;
2953 // compute derived data
2954 //rtlight->cullradius = rtlight->radius;
2955 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
2956 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2957 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2958 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2959 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2960 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2961 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2964 // compiles rtlight geometry
2965 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
2966 void R_RTLight_Compile(rtlight_t *rtlight)
2969 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
2970 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
2971 entity_render_t *ent = r_refdef.scene.worldentity;
2972 dp_model_t *model = r_refdef.scene.worldmodel;
2973 unsigned char *data;
2976 // compile the light
2977 rtlight->compiled = true;
2978 rtlight->shadowmode = rtlight->shadow ? (int)r_shadow_shadowmode : -1;
2979 rtlight->static_numleafs = 0;
2980 rtlight->static_numleafpvsbytes = 0;
2981 rtlight->static_leaflist = NULL;
2982 rtlight->static_leafpvs = NULL;
2983 rtlight->static_numsurfaces = 0;
2984 rtlight->static_surfacelist = NULL;
2985 rtlight->static_shadowmap_receivers = 0x3F;
2986 rtlight->static_shadowmap_casters = 0x3F;
2987 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
2988 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
2989 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
2990 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
2991 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
2992 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
2994 if (model && model->GetLightInfo)
2996 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
2997 r_shadow_compilingrtlight = rtlight;
2998 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);
2999 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
3000 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
3001 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3002 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
3003 rtlight->static_numsurfaces = numsurfaces;
3004 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
3005 rtlight->static_numleafs = numleafs;
3006 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
3007 rtlight->static_numleafpvsbytes = numleafpvsbytes;
3008 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
3009 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
3010 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
3011 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
3012 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3013 if (rtlight->static_numsurfaces)
3014 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3015 if (rtlight->static_numleafs)
3016 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3017 if (rtlight->static_numleafpvsbytes)
3018 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3019 if (rtlight->static_numshadowtrispvsbytes)
3020 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3021 if (rtlight->static_numlighttrispvsbytes)
3022 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3023 switch (rtlight->shadowmode)
3025 case R_SHADOW_SHADOWMODE_SHADOWMAP2D:
3026 case R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE:
3027 case R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE:
3028 if (model->CompileShadowMap && rtlight->shadow)
3029 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3032 if (model->CompileShadowVolume && rtlight->shadow)
3033 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3036 // now we're done compiling the rtlight
3037 r_shadow_compilingrtlight = NULL;
3041 // use smallest available cullradius - box radius or light radius
3042 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3043 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3045 shadowzpasstris = 0;
3046 if (rtlight->static_meshchain_shadow_zpass)
3047 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
3048 shadowzpasstris += mesh->numtriangles;
3050 shadowzfailtris = 0;
3051 if (rtlight->static_meshchain_shadow_zfail)
3052 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
3053 shadowzfailtris += mesh->numtriangles;
3056 if (rtlight->static_numlighttrispvsbytes)
3057 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3058 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3062 if (rtlight->static_numlighttrispvsbytes)
3063 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3064 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3067 if (developer.integer >= 10)
3068 Con_Printf("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);
3071 void R_RTLight_Uncompile(rtlight_t *rtlight)
3073 if (rtlight->compiled)
3075 if (rtlight->static_meshchain_shadow_zpass)
3076 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
3077 rtlight->static_meshchain_shadow_zpass = NULL;
3078 if (rtlight->static_meshchain_shadow_zfail)
3079 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
3080 rtlight->static_meshchain_shadow_zfail = NULL;
3081 if (rtlight->static_meshchain_shadow_shadowmap)
3082 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
3083 rtlight->static_meshchain_shadow_shadowmap = NULL;
3084 // these allocations are grouped
3085 if (rtlight->static_surfacelist)
3086 Mem_Free(rtlight->static_surfacelist);
3087 rtlight->static_numleafs = 0;
3088 rtlight->static_numleafpvsbytes = 0;
3089 rtlight->static_leaflist = NULL;
3090 rtlight->static_leafpvs = NULL;
3091 rtlight->static_numsurfaces = 0;
3092 rtlight->static_surfacelist = NULL;
3093 rtlight->static_numshadowtrispvsbytes = 0;
3094 rtlight->static_shadowtrispvs = NULL;
3095 rtlight->static_numlighttrispvsbytes = 0;
3096 rtlight->static_lighttrispvs = NULL;
3097 rtlight->compiled = false;
3101 void R_Shadow_UncompileWorldLights(void)
3105 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3106 for (lightindex = 0;lightindex < range;lightindex++)
3108 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3111 R_RTLight_Uncompile(&light->rtlight);
3115 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3119 // reset the count of frustum planes
3120 // see rtlight->cached_frustumplanes definition for how much this array
3122 rtlight->cached_numfrustumplanes = 0;
3124 // haven't implemented a culling path for ortho rendering
3125 if (!r_refdef.view.useperspective)
3127 // check if the light is on screen and copy the 4 planes if it is
3128 for (i = 0;i < 4;i++)
3129 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3132 for (i = 0;i < 4;i++)
3133 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3138 // generate a deformed frustum that includes the light origin, this is
3139 // used to cull shadow casting surfaces that can not possibly cast a
3140 // shadow onto the visible light-receiving surfaces, which can be a
3143 // if the light origin is onscreen the result will be 4 planes exactly
3144 // if the light origin is offscreen on only one axis the result will
3145 // be exactly 5 planes (split-side case)
3146 // if the light origin is offscreen on two axes the result will be
3147 // exactly 4 planes (stretched corner case)
3148 for (i = 0;i < 4;i++)
3150 // quickly reject standard frustum planes that put the light
3151 // origin outside the frustum
3152 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3155 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = r_refdef.view.frustum[i];
3157 // if all the standard frustum planes were accepted, the light is onscreen
3158 // otherwise we need to generate some more planes below...
3159 if (rtlight->cached_numfrustumplanes < 4)
3161 // at least one of the stock frustum planes failed, so we need to
3162 // create one or two custom planes to enclose the light origin
3163 for (i = 0;i < 4;i++)
3165 // create a plane using the view origin and light origin, and a
3166 // single point from the frustum corner set
3167 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3168 VectorNormalize(plane.normal);
3169 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3170 // see if this plane is backwards and flip it if so
3171 for (j = 0;j < 4;j++)
3172 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3176 VectorNegate(plane.normal, plane.normal);
3178 // flipped plane, test again to see if it is now valid
3179 for (j = 0;j < 4;j++)
3180 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3182 // if the plane is still not valid, then it is dividing the
3183 // frustum and has to be rejected
3187 // we have created a valid plane, compute extra info
3188 PlaneClassify(&plane);
3190 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3192 // if we've found 5 frustum planes then we have constructed a
3193 // proper split-side case and do not need to keep searching for
3194 // planes to enclose the light origin
3195 if (rtlight->cached_numfrustumplanes == 5)
3203 for (i = 0;i < rtlight->cached_numfrustumplanes;i++)
3205 plane = rtlight->cached_frustumplanes[i];
3206 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));
3211 // now add the light-space box planes if the light box is rotated, as any
3212 // caster outside the oriented light box is irrelevant (even if it passed
3213 // the worldspace light box, which is axial)
3214 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3216 for (i = 0;i < 6;i++)
3220 v[i >> 1] = (i & 1) ? -1 : 1;
3221 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3222 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3223 plane.dist = VectorNormalizeLength(plane.normal);
3224 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3225 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3231 // add the world-space reduced box planes
3232 for (i = 0;i < 6;i++)
3234 VectorClear(plane.normal);
3235 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3236 plane.dist = (i & 1) ? -rtlight->cached_cullmaxs[i >> 1] : rtlight->cached_cullmins[i >> 1];
3237 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = plane;
3246 // reduce all plane distances to tightly fit the rtlight cull box, which
3248 VectorSet(points[0], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3249 VectorSet(points[1], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmins[2]);
3250 VectorSet(points[2], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3251 VectorSet(points[3], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmins[2]);
3252 VectorSet(points[4], rtlight->cached_cullmins[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3253 VectorSet(points[5], rtlight->cached_cullmaxs[0], rtlight->cached_cullmins[1], rtlight->cached_cullmaxs[2]);
3254 VectorSet(points[6], rtlight->cached_cullmins[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3255 VectorSet(points[7], rtlight->cached_cullmaxs[0], rtlight->cached_cullmaxs[1], rtlight->cached_cullmaxs[2]);
3256 oldnum = rtlight->cached_numfrustumplanes;
3257 rtlight->cached_numfrustumplanes = 0;
3258 for (j = 0;j < oldnum;j++)
3260 // find the nearest point on the box to this plane
3261 bestdist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[0]);
3262 for (i = 1;i < 8;i++)
3264 dist = DotProduct(rtlight->cached_frustumplanes[j].normal, points[i]);
3265 if (bestdist > dist)
3268 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);
3269 // if the nearest point is near or behind the plane, we want this
3270 // plane, otherwise the plane is useless as it won't cull anything
3271 if (rtlight->cached_frustumplanes[j].dist < bestdist + 0.03125)
3273 PlaneClassify(&rtlight->cached_frustumplanes[j]);
3274 rtlight->cached_frustumplanes[rtlight->cached_numfrustumplanes++] = rtlight->cached_frustumplanes[j];
3281 void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
3285 RSurf_ActiveWorldEntity();
3287 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3290 GL_CullFace(GL_NONE);
3291 mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3292 for (;mesh;mesh = mesh->next)
3294 if (!mesh->sidetotals[r_shadow_shadowmapside])
3296 r_refdef.stats.lights_shadowtriangles += mesh->sidetotals[r_shadow_shadowmapside];
3297 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
3298 R_Mesh_Draw(0, mesh->numverts, mesh->sideoffsets[r_shadow_shadowmapside], mesh->sidetotals[r_shadow_shadowmapside], mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3302 else if (r_refdef.scene.worldentity->model)
3303 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);
3305 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3308 void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3310 qboolean zpass = false;
3313 int surfacelistindex;
3314 msurface_t *surface;
3316 RSurf_ActiveWorldEntity();
3318 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3321 if (r_shadow_rendermode != R_SHADOW_RENDERMODE_VISIBLEVOLUMES)
3323 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
3324 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
3326 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
3327 for (;mesh;mesh = mesh->next)
3329 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
3330 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
3331 GL_LockArrays(0, mesh->numverts);
3332 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
3334 // increment stencil if frontface is infront of depthbuffer
3335 GL_CullFace(r_refdef.view.cullface_back);
3336 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
3337 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3338 // decrement stencil if backface is infront of depthbuffer
3339 GL_CullFace(r_refdef.view.cullface_front);
3340 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
3342 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
3344 // decrement stencil if backface is behind depthbuffer
3345 GL_CullFace(r_refdef.view.cullface_front);
3346 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
3347 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3348 // increment stencil if frontface is behind depthbuffer
3349 GL_CullFace(r_refdef.view.cullface_back);
3350 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
3352 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3353 GL_LockArrays(0, 0);
3357 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh && r_shadow_culltriangles.integer)
3359 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
3360 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
3362 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
3363 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
3364 if (CHECKPVSBIT(trispvs, t))
3365 shadowmarklist[numshadowmark++] = t;
3367 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);
3369 else if (numsurfaces)
3370 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);
3372 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3375 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3377 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3378 vec_t relativeshadowradius;
3379 RSurf_ActiveModelEntity(ent, false, false);
3380 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3381 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3382 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3383 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3384 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3385 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3386 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3387 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3388 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D)
3390 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
3393 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3394 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3397 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3399 // set up properties for rendering light onto this entity
3400 RSurf_ActiveModelEntity(ent, true, true);
3401 GL_AlphaTest(false);
3402 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3403 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3404 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3405 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3406 switch(r_shadow_lightingrendermode)
3408 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
3409 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
3416 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3418 if (!r_refdef.scene.worldmodel->DrawLight)
3421 // set up properties for rendering light onto this entity
3422 RSurf_ActiveWorldEntity();
3423 GL_AlphaTest(false);
3424 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3425 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3426 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3427 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3428 switch(r_shadow_lightingrendermode)
3430 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
3431 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
3437 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, trispvs);
3439 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3442 void R_Shadow_DrawEntityLight(entity_render_t *ent)
3444 dp_model_t *model = ent->model;
3445 if (!model->DrawLight)
3448 R_Shadow_SetupEntityLight(ent);
3450 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3452 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3455 void R_CacheRTLight(rtlight_t *rtlight)
3459 int numleafs, numsurfaces;
3460 int *leaflist, *surfacelist;
3461 unsigned char *leafpvs, *shadowtrispvs, *lighttrispvs, *surfacesides;
3462 int numlightentities;
3463 int numlightentities_noselfshadow;
3464 int numshadowentities;
3465 int numshadowentities_noselfshadow;
3466 static entity_render_t *lightentities[MAX_EDICTS];
3467 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3468 static entity_render_t *shadowentities[MAX_EDICTS];
3469 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3471 rtlight->draw = false;
3473 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3474 // skip lights that are basically invisible (color 0 0 0)
3475 if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
3478 // loading is done before visibility checks because loading should happen
3479 // all at once at the start of a level, not when it stalls gameplay.
3480 // (especially important to benchmarks)
3482 if (rtlight->isstatic && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != (int)r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
3484 if (rtlight->compiled)
3485 R_RTLight_Uncompile(rtlight);
3486 R_RTLight_Compile(rtlight);
3490 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
3492 // look up the light style value at this time
3493 f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3494 VectorScale(rtlight->color, f, rtlight->currentcolor);
3496 if (rtlight->selected)
3498 f = 2 + sin(realtime * M_PI * 4.0);
3499 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3503 // if lightstyle is currently off, don't draw the light
3504 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3507 // if the light box is offscreen, skip it
3508 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3511 VectorCopy(rtlight->cullmins, rtlight->cached_cullmins);
3512 VectorCopy(rtlight->cullmaxs, rtlight->cached_cullmaxs);
3514 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3516 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3518 // compiled light, world available and can receive realtime lighting
3519 // retrieve leaf information
3520 numleafs = rtlight->static_numleafs;
3521 leaflist = rtlight->static_leaflist;
3522 leafpvs = rtlight->static_leafpvs;
3523 numsurfaces = rtlight->static_numsurfaces;
3524 surfacelist = rtlight->static_surfacelist;
3525 surfacesides = NULL;
3526 shadowtrispvs = rtlight->static_shadowtrispvs;
3527 lighttrispvs = rtlight->static_lighttrispvs;
3529 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3531 // dynamic light, world available and can receive realtime lighting
3532 // calculate lit surfaces and leafs
3533 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);
3534 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3535 leaflist = r_shadow_buffer_leaflist;
3536 leafpvs = r_shadow_buffer_leafpvs;
3537 surfacelist = r_shadow_buffer_surfacelist;
3538 surfacesides = r_shadow_buffer_surfacesides;
3539 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3540 lighttrispvs = r_shadow_buffer_lighttrispvs;
3541 // if the reduced leaf bounds are offscreen, skip it
3542 if (R_CullBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3553 surfacesides = NULL;
3554 shadowtrispvs = NULL;
3555 lighttrispvs = NULL;
3557 // check if light is illuminating any visible leafs
3560 for (i = 0;i < numleafs;i++)
3561 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3567 // make a list of lit entities and shadow casting entities
3568 numlightentities = 0;
3569 numlightentities_noselfshadow = 0;
3570 numshadowentities = 0;
3571 numshadowentities_noselfshadow = 0;
3573 // add dynamic entities that are lit by the light
3574 if (r_drawentities.integer)
3576 for (i = 0;i < r_refdef.scene.numentities;i++)
3579 entity_render_t *ent = r_refdef.scene.entities[i];
3581 if (!BoxesOverlap(ent->mins, ent->maxs, rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3583 // skip the object entirely if it is not within the valid
3584 // shadow-casting region (which includes the lit region)
3585 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rtlight->cached_numfrustumplanes, rtlight->cached_frustumplanes))
3587 if (!(model = ent->model))
3589 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
3591 // this entity wants to receive light, is visible, and is
3592 // inside the light box
3593 // TODO: check if the surfaces in the model can receive light
3594 // so now check if it's in a leaf seen by the light
3595 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))
3597 if (ent->flags & RENDER_NOSELFSHADOW)
3598 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
3600 lightentities[numlightentities++] = ent;
3601 // since it is lit, it probably also casts a shadow...
3602 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3603 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3604 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3606 // note: exterior models without the RENDER_NOSELFSHADOW
3607 // flag still create a RENDER_NOSELFSHADOW shadow but
3608 // are lit normally, this means that they are
3609 // self-shadowing but do not shadow other
3610 // RENDER_NOSELFSHADOW entities such as the gun
3611 // (very weird, but keeps the player shadow off the gun)
3612 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3613 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3615 shadowentities[numshadowentities++] = ent;
3618 else if (ent->flags & RENDER_SHADOW)
3620 // this entity is not receiving light, but may still need to
3622 // TODO: check if the surfaces in the model can cast shadow
3623 // now check if it is in a leaf seen by the light
3624 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))
3626 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3627 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3628 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3630 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3631 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3633 shadowentities[numshadowentities++] = ent;
3639 // return if there's nothing at all to light
3640 if (numsurfaces + numlightentities + numlightentities_noselfshadow == 0)
3643 // count this light in the r_speeds
3644 r_refdef.stats.lights++;
3646 // flag it as worth drawing later
3647 rtlight->draw = true;
3649 // cache all the animated entities that cast a shadow but are not visible
3650 for (i = 0;i < numshadowentities;i++)
3651 if (shadowentities[i]->animcacheindex < 0)
3652 R_AnimCache_GetEntity(shadowentities[i], false, false);
3653 for (i = 0;i < numshadowentities_noselfshadow;i++)
3654 if (shadowentities_noselfshadow[i]->animcacheindex < 0)
3655 R_AnimCache_GetEntity(shadowentities_noselfshadow[i], false, false);
3657 // allocate some temporary memory for rendering this light later in the frame
3658 // reusable buffers need to be copied, static data can be used as-is
3659 rtlight->cached_numlightentities = numlightentities;
3660 rtlight->cached_numlightentities_noselfshadow = numlightentities_noselfshadow;
3661 rtlight->cached_numshadowentities = numshadowentities;
3662 rtlight->cached_numshadowentities_noselfshadow = numshadowentities_noselfshadow;
3663 rtlight->cached_numsurfaces = numsurfaces;
3664 rtlight->cached_lightentities = (entity_render_t**)R_FrameData_Store(numlightentities*sizeof(entity_render_t*), (void*)lightentities);
3665 rtlight->cached_lightentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numlightentities_noselfshadow*sizeof(entity_render_t*), (void*)lightentities_noselfshadow);
3666 rtlight->cached_shadowentities = (entity_render_t**)R_FrameData_Store(numshadowentities*sizeof(entity_render_t*), (void*)shadowentities);
3667 rtlight->cached_shadowentities_noselfshadow = (entity_render_t**)R_FrameData_Store(numshadowentities_noselfshadow*sizeof(entity_render_t *), (void*)shadowentities_noselfshadow);
3668 if (shadowtrispvs == r_shadow_buffer_shadowtrispvs)
3670 rtlight->cached_shadowtrispvs = (unsigned char *)R_FrameData_Store(r_refdef.scene.worldmodel->brush.shadowmesh ? r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles : r_refdef.scene.worldmodel->surfmesh.num_triangles, shadowtrispvs);
3671 rtlight->cached_lighttrispvs = (unsigned char *)R_FrameData_Store(r_refdef.scene.worldmodel->surfmesh.num_triangles, lighttrispvs);
3672 rtlight->cached_surfacelist = (int*)R_FrameData_Store(numsurfaces*sizeof(int), (void*)surfacelist);
3676 // compiled light data
3677 rtlight->cached_shadowtrispvs = shadowtrispvs;
3678 rtlight->cached_lighttrispvs = lighttrispvs;
3679 rtlight->cached_surfacelist = surfacelist;
3683 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
3687 unsigned char *shadowtrispvs, *lighttrispvs, *surfacesides;
3688 int numlightentities;
3689 int numlightentities_noselfshadow;
3690 int numshadowentities;
3691 int numshadowentities_noselfshadow;
3692 entity_render_t **lightentities;
3693 entity_render_t **lightentities_noselfshadow;
3694 entity_render_t **shadowentities;
3695 entity_render_t **shadowentities_noselfshadow;
3697 static unsigned char entitysides[MAX_EDICTS];
3698 static unsigned char entitysides_noselfshadow[MAX_EDICTS];
3699 vec3_t nearestpoint;
3701 qboolean castshadows;
3704 // check if we cached this light this frame (meaning it is worth drawing)
3708 // if R_FrameData_Store ran out of space we skip anything dependent on it
3709 if (r_framedata_failed)
3712 numlightentities = rtlight->cached_numlightentities;
3713 numlightentities_noselfshadow = rtlight->cached_numlightentities_noselfshadow;
3714 numshadowentities = rtlight->cached_numshadowentities;
3715 numshadowentities_noselfshadow = rtlight->cached_numshadowentities_noselfshadow;
3716 numsurfaces = rtlight->cached_numsurfaces;
3717 lightentities = rtlight->cached_lightentities;
3718 lightentities_noselfshadow = rtlight->cached_lightentities_noselfshadow;
3719 shadowentities = rtlight->cached_shadowentities;
3720 shadowentities_noselfshadow = rtlight->cached_shadowentities_noselfshadow;
3721 shadowtrispvs = rtlight->cached_shadowtrispvs;
3722 lighttrispvs = rtlight->cached_lighttrispvs;
3723 surfacelist = rtlight->cached_surfacelist;
3725 // set up a scissor rectangle for this light
3726 if (R_Shadow_ScissorForBBox(rtlight->cached_cullmins, rtlight->cached_cullmaxs))
3729 // don't let sound skip if going slow
3730 if (r_refdef.scene.extraupdate)
3733 // make this the active rtlight for rendering purposes
3734 R_Shadow_RenderMode_ActiveLight(rtlight);
3736 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
3738 // optionally draw visible shape of the shadow volumes
3739 // for performance analysis by level designers
3740 R_Shadow_RenderMode_VisibleShadowVolumes();
3742 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
3743 for (i = 0;i < numshadowentities;i++)
3744 R_Shadow_DrawEntityShadow(shadowentities[i]);
3745 for (i = 0;i < numshadowentities_noselfshadow;i++)
3746 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3747 R_Shadow_RenderMode_VisibleLighting(false, false);
3750 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
3752 // optionally draw the illuminated areas
3753 // for performance analysis by level designers
3754 R_Shadow_RenderMode_VisibleLighting(false, false);
3756 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3757 for (i = 0;i < numlightentities;i++)
3758 R_Shadow_DrawEntityLight(lightentities[i]);
3759 for (i = 0;i < numlightentities_noselfshadow;i++)
3760 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3763 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
3765 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
3766 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
3767 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
3768 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
3770 lodlinear = (rtlight->radius * r_shadow_shadowmapping_precision.value) / sqrt(max(1.0f, distance/rtlight->radius));
3771 //lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
3772 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapmaxsize);
3774 if (castshadows && (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAP2D || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPRECTANGLE || r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE))
3780 int receivermask = 0;
3781 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
3782 Matrix4x4_Abs(&radiustolight);
3784 r_shadow_shadowmaplod = 0;
3785 for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
3786 if ((r_shadow_shadowmapmaxsize >> i) > lodlinear)
3787 r_shadow_shadowmaplod = i;
3789 if (r_shadow_shadowmode == R_SHADOW_SHADOWMODE_SHADOWMAPCUBESIDE)
3790 size = max(1, r_shadow_shadowmapmaxsize >> r_shadow_shadowmaplod);
3792 size = bound(r_shadow_shadowmapborder, lodlinear, r_shadow_shadowmapmaxsize);
3794 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
3796 surfacesides = NULL;
3799 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3801 castermask = rtlight->static_shadowmap_casters;
3802 receivermask = rtlight->static_shadowmap_receivers;
3806 surfacesides = r_shadow_buffer_surfacesides;
3807 for(i = 0;i < numsurfaces;i++)
3809 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
3810 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3811 castermask |= surfacesides[i];
3812 receivermask |= surfacesides[i];
3816 if (receivermask < 0x3F)
3818 for (i = 0;i < numlightentities;i++)
3819 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3820 if (receivermask < 0x3F)
3821 for(i = 0; i < numlightentities_noselfshadow;i++)
3822 receivermask |= R_Shadow_CalcEntitySideMask(lightentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
3825 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
3829 for (i = 0;i < numshadowentities;i++)
3830 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3831 for (i = 0;i < numshadowentities_noselfshadow;i++)
3832 castermask |= (entitysides_noselfshadow[i] = R_Shadow_CalcEntitySideMask(shadowentities_noselfshadow[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
3835 //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
3837 // render shadow casters into 6 sided depth texture
3838 for (side = 0;side < 6;side++) if (receivermask & (1 << side))
3840 R_Shadow_RenderMode_ShadowMap(side, true, size);
3841 if (! (castermask & (1 << side))) continue;
3843 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
3844 for (i = 0;i < numshadowentities;i++) if (entitysides[i] & (1 << side))
3845 R_Shadow_DrawEntityShadow(shadowentities[i]);
3848 if (numlightentities_noselfshadow)
3850 // render lighting using the depth texture as shadowmap
3851 // draw lighting in the unmasked areas
3852 R_Shadow_RenderMode_Lighting(false, false, true);
3853 for (i = 0;i < numlightentities_noselfshadow;i++)
3854 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3857 // render shadow casters into 6 sided depth texture
3858 if (numshadowentities_noselfshadow)
3860 for (side = 0;side < 6;side++) if ((receivermask & castermask) & (1 << side))
3862 R_Shadow_RenderMode_ShadowMap(side, false, size);
3863 for (i = 0;i < numshadowentities_noselfshadow;i++) if (entitysides_noselfshadow[i] & (1 << side))
3864 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3868 // render lighting using the depth texture as shadowmap
3869 // draw lighting in the unmasked areas
3870 R_Shadow_RenderMode_Lighting(false, false, true);
3871 // draw lighting in the unmasked areas
3873 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3874 for (i = 0;i < numlightentities;i++)
3875 R_Shadow_DrawEntityLight(lightentities[i]);
3877 else if (castshadows && vid.stencil)
3879 // draw stencil shadow volumes to mask off pixels that are in shadow
3880 // so that they won't receive lighting
3881 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
3882 R_Shadow_ClearStencil();
3885 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
3886 for (i = 0;i < numshadowentities;i++)
3887 R_Shadow_DrawEntityShadow(shadowentities[i]);
3889 // draw lighting in the unmasked areas
3890 R_Shadow_RenderMode_Lighting(true, false, false);
3891 for (i = 0;i < numlightentities_noselfshadow;i++)
3892 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3894 for (i = 0;i < numshadowentities_noselfshadow;i++)
3895 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3897 // draw lighting in the unmasked areas
3898 R_Shadow_RenderMode_Lighting(true, false, false);
3900 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3901 for (i = 0;i < numlightentities;i++)
3902 R_Shadow_DrawEntityLight(lightentities[i]);
3906 // draw lighting in the unmasked areas
3907 R_Shadow_RenderMode_Lighting(false, false, false);
3909 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3910 for (i = 0;i < numlightentities;i++)
3911 R_Shadow_DrawEntityLight(lightentities[i]);
3912 for (i = 0;i < numlightentities_noselfshadow;i++)
3913 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3917 void R_PrepareRTLights(void)
3926 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);
3928 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3929 if (r_shadow_debuglight.integer >= 0)
3931 lightindex = r_shadow_debuglight.integer;
3932 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3933 if (light && (light->flags & flag))
3934 R_CacheRTLight(&light->rtlight);
3938 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3939 for (lightindex = 0;lightindex < range;lightindex++)
3941 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3942 if (light && (light->flags & flag))
3943 R_CacheRTLight(&light->rtlight);
3946 if (r_refdef.scene.rtdlight)
3948 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
3949 R_CacheRTLight(r_refdef.scene.lights[lnum]);
3951 else if(gl_flashblend.integer)
3953 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
3955 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
3956 f = (rtlight->style >= 0 ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3957 VectorScale(rtlight->color, f, rtlight->currentcolor);
3962 void R_Shadow_DrawLightSprites(void);
3963 void R_ShadowVolumeLighting(qboolean visible)
3972 if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, (int)vid.maxtexturesize_2d / 4) ||
3973 (r_shadow_shadowmode != R_SHADOW_SHADOWMODE_STENCIL) != r_shadow_shadowmapping.integer ||
3974 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0) ||
3975 r_shadow_shadowmaptexturetype != r_shadow_shadowmapping_texturetype.integer ||
3976 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
3977 r_shadow_shadowmapdepthbits != r_shadow_shadowmapping_depthbits.integer ||
3978 r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
3979 R_Shadow_FreeShadowMaps();
3981 if (r_editlights.integer)
3982 R_Shadow_DrawLightSprites();
3984 R_Shadow_RenderMode_Begin();
3986 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3987 if (r_shadow_debuglight.integer >= 0)
3989 lightindex = r_shadow_debuglight.integer;
3990 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3991 if (light && (light->flags & flag))
3992 R_DrawRTLight(&light->rtlight, visible);
3996 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3997 for (lightindex = 0;lightindex < range;lightindex++)
3999 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4000 if (light && (light->flags & flag))
4001 R_DrawRTLight(&light->rtlight, visible);
4004 if (r_refdef.scene.rtdlight)
4006 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4007 R_DrawRTLight(r_refdef.scene.lights[lnum], visible);
4009 else if(gl_flashblend.integer)
4011 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4013 rtlight_t *rtlight = r_refdef.scene.lights[lnum];
4014 f = (rtlight->style >= 0 ? r_refdef.scene.lightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
4015 VectorScale(rtlight->color, f, rtlight->currentcolor);
4019 R_Shadow_RenderMode_End();
4022 extern const float r_screenvertex3f[12];
4023 extern void R_SetupView(qboolean allowwaterclippingplane);
4024 extern void R_ResetViewRendering3D(void);
4025 extern void R_ResetViewRendering2D(void);
4026 extern cvar_t r_shadows;
4027 extern cvar_t r_shadows_darken;
4028 extern cvar_t r_shadows_drawafterrtlighting;
4029 extern cvar_t r_shadows_castfrombmodels;
4030 extern cvar_t r_shadows_throwdistance;
4031 extern cvar_t r_shadows_throwdirection;
4032 void R_DrawModelShadows(void)
4035 float relativethrowdistance;
4036 entity_render_t *ent;
4037 vec3_t relativelightorigin;
4038 vec3_t relativelightdirection;
4039 vec3_t relativeshadowmins, relativeshadowmaxs;
4040 vec3_t tmp, shadowdir;
4042 if (!r_drawentities.integer || !vid.stencil)
4046 R_ResetViewRendering3D();
4047 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4048 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4049 R_Shadow_RenderMode_Begin();
4050 R_Shadow_RenderMode_ActiveLight(NULL);
4051 r_shadow_lightscissor[0] = r_refdef.view.x;
4052 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
4053 r_shadow_lightscissor[2] = r_refdef.view.width;
4054 r_shadow_lightscissor[3] = r_refdef.view.height;
4055 R_Shadow_RenderMode_StencilShadowVolumes(false);
4058 if (r_shadows.integer == 2)
4060 Math_atov(r_shadows_throwdirection.string, shadowdir);
4061 VectorNormalize(shadowdir);
4064 R_Shadow_ClearStencil();
4066 for (i = 0;i < r_refdef.scene.numentities;i++)
4068 ent = r_refdef.scene.entities[i];
4070 // cast shadows from anything of the map (submodels are optional)
4071 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4073 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4074 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
4075 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
4076 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
4077 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4080 if(ent->entitynumber != 0)
4082 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
4083 int entnum, entnum2, recursion;
4084 entnum = entnum2 = ent->entitynumber;
4085 for(recursion = 32; recursion > 0; --recursion)
4087 entnum2 = cl.entities[entnum].state_current.tagentity;
4088 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
4093 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
4095 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
4096 // transform into modelspace of OUR entity
4097 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
4098 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
4101 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4104 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4107 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
4108 RSurf_ActiveModelEntity(ent, false, false);
4109 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4110 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4114 // not really the right mode, but this will disable any silly stencil features
4115 R_Shadow_RenderMode_End();
4117 // set up ortho view for rendering this pass
4118 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4119 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4120 //GL_ScissorTest(true);
4121 //R_Mesh_Matrix(&identitymatrix);
4122 //R_Mesh_ResetTextureState();
4123 R_ResetViewRendering2D();
4124 R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
4125 R_Mesh_ColorPointer(NULL, 0, 0);
4126 R_SetupGenericShader(false);
4128 // set up a darkening blend on shadowed areas
4129 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4130 //GL_DepthRange(0, 1);
4131 //GL_DepthTest(false);
4132 //GL_DepthMask(false);
4133 //GL_PolygonOffset(0, 0);CHECKGLERROR
4134 GL_Color(0, 0, 0, r_shadows_darken.value);
4135 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4136 //qglDepthFunc(GL_ALWAYS);CHECKGLERROR
4137 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
4138 qglStencilMask(~0);CHECKGLERROR
4139 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
4140 qglStencilFunc(GL_NOTEQUAL, 128, ~0);CHECKGLERROR
4142 // apply the blend to the shadowed areas
4143 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
4145 // restore the viewport
4146 R_SetViewport(&r_refdef.view.viewport);
4148 // restore other state to normal
4149 //R_Shadow_RenderMode_End();
4152 void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4155 vec3_t centerorigin;
4157 // if it's too close, skip it
4158 if (VectorLength(rtlight->currentcolor) < (1.0f / 256.0f))
4160 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4163 if (usequery && r_numqueries + 2 <= r_maxqueries)
4165 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4166 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4167 // 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
4168 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4171 // NOTE: GL_DEPTH_TEST must be enabled or ATI won't count samples, so use qglDepthFunc instead
4172 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
4173 qglDepthFunc(GL_ALWAYS);
4174 R_CalcSprite_Vertex3f(vertex3f, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4175 R_Mesh_VertexPointer(vertex3f, 0, 0);
4176 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
4177 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4178 qglDepthFunc(GL_LEQUAL);
4179 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
4180 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4181 R_Mesh_VertexPointer(vertex3f, 0, 0);
4182 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, polygonelement3s, 0, 0);
4183 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4186 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4189 static float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
4191 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4194 GLint allpixels = 0, visiblepixels = 0;
4195 // now we have to check the query result
4196 if (rtlight->corona_queryindex_visiblepixels)
4199 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
4200 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
4202 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
4203 if (visiblepixels < 1 || allpixels < 1)
4205 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
4206 cscale *= rtlight->corona_visibility;
4210 // FIXME: these traces should scan all render entities instead of cl.world
4211 if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
4214 VectorScale(rtlight->currentcolor, cscale, color);
4215 if (VectorLength(color) > (1.0f / 256.0f))
4218 qboolean negated = (color[0] + color[1] + color[2] < 0) && vid.support.ext_blend_subtract;
4221 VectorNegate(color, color);
4222 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
4224 R_CalcSprite_Vertex3f(vertex3f, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale);
4225 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);
4226 R_DrawCustomSurface(r_shadow_lightcorona, &identitymatrix, MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false);
4228 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
4232 void R_DrawCoronas(void)
4240 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4242 if (r_waterstate.renderingscene)
4244 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4245 R_Mesh_Matrix(&identitymatrix);
4247 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4249 // check occlusion of coronas
4250 // use GL_ARB_occlusion_query if available
4251 // otherwise use raytraces
4253 usequery = vid.support.arb_occlusion_query && r_coronas_occlusionquery.integer;
4256 GL_ColorMask(0,0,0,0);
4257 if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
4258 if (r_maxqueries < MAX_OCCLUSION_QUERIES)
4261 r_maxqueries = (range + r_refdef.scene.numlights) * 4;
4262 r_maxqueries = min(r_maxqueries, MAX_OCCLUSION_QUERIES);
4264 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
4267 RSurf_ActiveWorldEntity();
4268 GL_BlendFunc(GL_ONE, GL_ZERO);
4269 GL_CullFace(GL_NONE);
4270 GL_DepthMask(false);
4271 GL_DepthRange(0, 1);
4272 GL_PolygonOffset(0, 0);
4274 R_Mesh_ColorPointer(NULL, 0, 0);
4275 R_Mesh_ResetTextureState();
4276 R_SetupGenericShader(false);
4278 for (lightindex = 0;lightindex < range;lightindex++)
4280 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4283 rtlight = &light->rtlight;
4284 rtlight->corona_visibility = 0;
4285 rtlight->corona_queryindex_visiblepixels = 0;
4286 rtlight->corona_queryindex_allpixels = 0;
4287 if (!(rtlight->flags & flag))
4289 if (rtlight->corona <= 0)
4291 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4293 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4295 for (i = 0;i < r_refdef.scene.numlights;i++)
4297 rtlight = r_refdef.scene.lights[i];
4298 rtlight->corona_visibility = 0;
4299 rtlight->corona_queryindex_visiblepixels = 0;
4300 rtlight->corona_queryindex_allpixels = 0;
4301 if (!(rtlight->flags & flag))
4303 if (rtlight->corona <= 0)
4305 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4308 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4310 // now draw the coronas using the query data for intensity info
4311 for (lightindex = 0;lightindex < range;lightindex++)
4313 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4316 rtlight = &light->rtlight;
4317 if (rtlight->corona_visibility <= 0)
4319 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4321 for (i = 0;i < r_refdef.scene.numlights;i++)
4323 rtlight = r_refdef.scene.lights[i];
4324 if (rtlight->corona_visibility <= 0)
4326 if (gl_flashblend.integer)
4327 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4329 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4335 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
4336 typedef struct suffixinfo_s
4339 qboolean flipx, flipy, flipdiagonal;
4342 static suffixinfo_t suffix[3][6] =
4345 {"px", false, false, false},
4346 {"nx", false, false, false},
4347 {"py", false, false, false},
4348 {"ny", false, false, false},
4349 {"pz", false, false, false},
4350 {"nz", false, false, false}
4353 {"posx", false, false, false},
4354 {"negx", false, false, false},
4355 {"posy", false, false, false},
4356 {"negy", false, false, false},
4357 {"posz", false, false, false},
4358 {"negz", false, false, false}
4361 {"rt", true, false, true},
4362 {"lf", false, true, true},
4363 {"ft", true, true, false},
4364 {"bk", false, false, false},
4365 {"up", true, false, true},
4366 {"dn", true, false, true}
4370 static int componentorder[4] = {0, 1, 2, 3};
4372 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
4374 int i, j, cubemapsize;
4375 unsigned char *cubemappixels, *image_buffer;
4376 rtexture_t *cubemaptexture;
4378 // must start 0 so the first loadimagepixels has no requested width/height
4380 cubemappixels = NULL;
4381 cubemaptexture = NULL;
4382 // keep trying different suffix groups (posx, px, rt) until one loads
4383 for (j = 0;j < 3 && !cubemappixels;j++)
4385 // load the 6 images in the suffix group
4386 for (i = 0;i < 6;i++)
4388 // generate an image name based on the base and and suffix
4389 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
4391 if ((image_buffer = loadimagepixelsbgra(name, false, false)))
4393 // an image loaded, make sure width and height are equal
4394 if (image_width == image_height && (!cubemappixels || image_width == cubemapsize))
4396 // if this is the first image to load successfully, allocate the cubemap memory
4397 if (!cubemappixels && image_width >= 1)
4399 cubemapsize = image_width;
4400 // note this clears to black, so unavailable sides are black
4401 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
4403 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
4405 Image_CopyMux(cubemappixels+i*cubemapsize*cubemapsize*4, image_buffer, cubemapsize, cubemapsize, suffix[j][i].flipx, suffix[j][i].flipy, suffix[j][i].flipdiagonal, 4, 4, componentorder);
4408 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
4410 Mem_Free(image_buffer);
4414 // if a cubemap loaded, upload it
4417 if (developer_loading.integer)
4418 Con_Printf("loading cubemap \"%s\"\n", basename);
4420 if (!r_shadow_filters_texturepool)
4421 r_shadow_filters_texturepool = R_AllocTexturePool();
4422 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_BGRA, TEXF_PRECACHE | (gl_texturecompression_lightcubemaps.integer ? TEXF_COMPRESS : 0) | TEXF_FORCELINEAR, NULL);
4423 Mem_Free(cubemappixels);
4427 Con_DPrintf("failed to load cubemap \"%s\"\n", basename);
4428 if (developer_loading.integer)
4430 Con_Printf("(tried tried images ");
4431 for (j = 0;j < 3;j++)
4432 for (i = 0;i < 6;i++)
4433 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
4434 Con_Print(" and was unable to find any of them).\n");
4437 return cubemaptexture;
4440 rtexture_t *R_Shadow_Cubemap(const char *basename)
4443 for (i = 0;i < numcubemaps;i++)
4444 if (!strcasecmp(cubemaps[i].basename, basename))
4445 return cubemaps[i].texture ? cubemaps[i].texture : r_texture_whitecube;
4446 if (i >= MAX_CUBEMAPS)
4447 return r_texture_whitecube;
4449 strlcpy(cubemaps[i].basename, basename, sizeof(cubemaps[i].basename));
4450 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
4451 return cubemaps[i].texture;
4454 void R_Shadow_FreeCubemaps(void)
4457 for (i = 0;i < numcubemaps;i++)
4459 if (developer_loading.integer)
4460 Con_Printf("unloading cubemap \"%s\"\n", cubemaps[i].basename);
4461 if (cubemaps[i].texture)
4462 R_FreeTexture(cubemaps[i].texture);
4466 R_FreeTexturePool(&r_shadow_filters_texturepool);
4469 dlight_t *R_Shadow_NewWorldLight(void)
4471 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4474 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)
4477 // validate parameters
4478 if (style < 0 || style >= MAX_LIGHTSTYLES)
4480 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
4486 // copy to light properties
4487 VectorCopy(origin, light->origin);
4488 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4489 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4490 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4492 light->color[0] = max(color[0], 0);
4493 light->color[1] = max(color[1], 0);
4494 light->color[2] = max(color[2], 0);
4496 light->color[0] = color[0];
4497 light->color[1] = color[1];
4498 light->color[2] = color[2];
4499 light->radius = max(radius, 0);
4500 light->style = style;
4501 light->shadow = shadowenable;
4502 light->corona = corona;
4503 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4504 light->coronasizescale = coronasizescale;
4505 light->ambientscale = ambientscale;
4506 light->diffusescale = diffusescale;
4507 light->specularscale = specularscale;
4508 light->flags = flags;
4510 // update renderable light data
4511 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4512 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);
4515 void R_Shadow_FreeWorldLight(dlight_t *light)
4517 if (r_shadow_selectedlight == light)
4518 r_shadow_selectedlight = NULL;
4519 R_RTLight_Uncompile(&light->rtlight);
4520 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4523 void R_Shadow_ClearWorldLights(void)
4527 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4528 for (lightindex = 0;lightindex < range;lightindex++)
4530 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4532 R_Shadow_FreeWorldLight(light);
4534 r_shadow_selectedlight = NULL;
4535 R_Shadow_FreeCubemaps();
4538 void R_Shadow_SelectLight(dlight_t *light)
4540 if (r_shadow_selectedlight)
4541 r_shadow_selectedlight->selected = false;
4542 r_shadow_selectedlight = light;
4543 if (r_shadow_selectedlight)
4544 r_shadow_selectedlight->selected = true;
4547 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4549 // this is never batched (there can be only one)
4551 R_CalcSprite_Vertex3f(vertex3f, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE);
4552 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4553 R_DrawCustomSurface(r_editlights_sprcursor, &identitymatrix, MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false);
4556 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4561 skinframe_t *skinframe;
4564 // this is never batched (due to the ent parameter changing every time)
4565 // so numsurfaces == 1 and surfacelist[0] == lightnumber
4566 const dlight_t *light = (dlight_t *)ent;
4569 R_CalcSprite_Vertex3f(vertex3f, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s);
4572 VectorScale(light->color, intensity, spritecolor);
4573 if (VectorLength(spritecolor) < 0.1732f)
4574 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
4575 if (VectorLength(spritecolor) > 1.0f)
4576 VectorNormalize(spritecolor);
4578 // draw light sprite
4579 if (light->cubemapname[0] && !light->shadow)
4580 skinframe = r_editlights_sprcubemapnoshadowlight;
4581 else if (light->cubemapname[0])
4582 skinframe = r_editlights_sprcubemaplight;
4583 else if (!light->shadow)
4584 skinframe = r_editlights_sprnoshadowlight;
4586 skinframe = r_editlights_sprlight;
4588 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);
4589 R_DrawCustomSurface(skinframe, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false);
4591 // draw selection sprite if light is selected
4592 if (light->selected)
4594 RSurf_ActiveCustomEntity(&identitymatrix, &identitymatrix, 0, 0, 1, 1, 1, 1, 4, vertex3f, spritetexcoord2f, NULL, NULL, NULL, NULL, 2, polygonelement3i, polygonelement3s, false, false);
4595 R_DrawCustomSurface(r_editlights_sprselection, &identitymatrix, MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOCULLFACE, 0, 4, 0, 2, false);
4596 // VorteX todo: add normalmode/realtime mode light overlay sprites?
4600 void R_Shadow_DrawLightSprites(void)
4604 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4605 for (lightindex = 0;lightindex < range;lightindex++)
4607 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4609 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
4611 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
4614 int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
4619 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray);
4620 if (lightindex >= range)
4622 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4625 rtlight = &light->rtlight;
4626 //if (!(rtlight->flags & flag))
4628 VectorCopy(rtlight->shadoworigin, origin);
4629 *radius = rtlight->radius;
4630 VectorCopy(rtlight->color, color);
4634 void R_Shadow_SelectLightInView(void)
4636 float bestrating, rating, temp[3];
4640 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4643 for (lightindex = 0;lightindex < range;lightindex++)
4645 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4648 VectorSubtract(light->origin, r_refdef.view.origin, temp);
4649 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
4652 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
4653 if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1.0f)
4655 bestrating = rating;
4660 R_Shadow_SelectLight(best);
4663 void R_Shadow_LoadWorldLights(void)
4665 int n, a, style, shadow, flags;
4666 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
4667 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
4668 if (cl.worldmodel == NULL)
4670 Con_Print("No map loaded.\n");
4673 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4674 strlcat (name, ".rtlights", sizeof (name));
4675 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4685 for (;COM_Parse(t, true) && strcmp(
4686 if (COM_Parse(t, true))
4688 if (com_token[0] == '!')
4691 origin[0] = atof(com_token+1);
4694 origin[0] = atof(com_token);
4699 while (*s && *s != '\n' && *s != '\r')
4705 // check for modifier flags
4712 #if _MSC_VER >= 1400
4713 #define sscanf sscanf_s
4715 cubemapname[sizeof(cubemapname)-1] = 0;
4716 #if MAX_QPATH != 128
4717 #error update this code if MAX_QPATH changes
4719 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
4720 #if _MSC_VER >= 1400
4721 , sizeof(cubemapname)
4723 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
4726 flags = LIGHTFLAG_REALTIMEMODE;
4734 coronasizescale = 0.25f;
4736 VectorClear(angles);
4739 if (a < 9 || !strcmp(cubemapname, "\"\""))
4741 // remove quotes on cubemapname
4742 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
4745 namelen = strlen(cubemapname) - 2;
4746 memmove(cubemapname, cubemapname + 1, namelen);
4747 cubemapname[namelen] = '\0';
4751 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);
4754 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4762 Con_Printf("invalid rtlights file \"%s\"\n", name);
4763 Mem_Free(lightsstring);
4767 void R_Shadow_SaveWorldLights(void)
4771 size_t bufchars, bufmaxchars;
4773 char name[MAX_QPATH];
4774 char line[MAX_INPUTLINE];
4775 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
4776 // I hate lines which are 3 times my screen size :( --blub
4779 if (cl.worldmodel == NULL)
4781 Con_Print("No map loaded.\n");
4784 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4785 strlcat (name, ".rtlights", sizeof (name));
4786 bufchars = bufmaxchars = 0;
4788 for (lightindex = 0;lightindex < range;lightindex++)
4790 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4793 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
4794 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);
4795 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
4796 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]);
4798 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);
4799 if (bufchars + strlen(line) > bufmaxchars)
4801 bufmaxchars = bufchars + strlen(line) + 2048;
4803 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
4807 memcpy(buf, oldbuf, bufchars);
4813 memcpy(buf + bufchars, line, strlen(line));
4814 bufchars += strlen(line);
4818 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
4823 void R_Shadow_LoadLightsFile(void)
4826 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
4827 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
4828 if (cl.worldmodel == NULL)
4830 Con_Print("No map loaded.\n");
4833 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4834 strlcat (name, ".lights", sizeof (name));
4835 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4843 while (*s && *s != '\n' && *s != '\r')
4849 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);
4853 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);
4856 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
4857 radius = bound(15, radius, 4096);
4858 VectorScale(color, (2.0f / (8388608.0f)), color);
4859 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
4867 Con_Printf("invalid lights file \"%s\"\n", name);
4868 Mem_Free(lightsstring);
4872 // tyrlite/hmap2 light types in the delay field
4873 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
4875 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
4877 int entnum, style, islight, skin, pflags, effects, type, n;
4880 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
4881 char key[256], value[MAX_INPUTLINE];
4883 if (cl.worldmodel == NULL)
4885 Con_Print("No map loaded.\n");
4888 // try to load a .ent file first
4889 FS_StripExtension (cl.worldmodel->name, key, sizeof (key));
4890 strlcat (key, ".ent", sizeof (key));
4891 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
4892 // and if that is not found, fall back to the bsp file entity string
4894 data = cl.worldmodel->brush.entities;
4897 for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
4899 type = LIGHTTYPE_MINUSX;
4900 origin[0] = origin[1] = origin[2] = 0;
4901 originhack[0] = originhack[1] = originhack[2] = 0;
4902 angles[0] = angles[1] = angles[2] = 0;
4903 color[0] = color[1] = color[2] = 1;
4904 light[0] = light[1] = light[2] = 1;light[3] = 300;
4905 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
4915 if (!COM_ParseToken_Simple(&data, false, false))
4917 if (com_token[0] == '}')
4918 break; // end of entity
4919 if (com_token[0] == '_')
4920 strlcpy(key, com_token + 1, sizeof(key));
4922 strlcpy(key, com_token, sizeof(key));
4923 while (key[strlen(key)-1] == ' ') // remove trailing spaces
4924 key[strlen(key)-1] = 0;
4925 if (!COM_ParseToken_Simple(&data, false, false))
4927 strlcpy(value, com_token, sizeof(value));
4929 // now that we have the key pair worked out...
4930 if (!strcmp("light", key))
4932 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
4936 light[0] = vec[0] * (1.0f / 256.0f);
4937 light[1] = vec[0] * (1.0f / 256.0f);
4938 light[2] = vec[0] * (1.0f / 256.0f);
4944 light[0] = vec[0] * (1.0f / 255.0f);
4945 light[1] = vec[1] * (1.0f / 255.0f);
4946 light[2] = vec[2] * (1.0f / 255.0f);
4950 else if (!strcmp("delay", key))
4952 else if (!strcmp("origin", key))
4953 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
4954 else if (!strcmp("angle", key))
4955 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
4956 else if (!strcmp("angles", key))
4957 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
4958 else if (!strcmp("color", key))
4959 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
4960 else if (!strcmp("wait", key))
4961 fadescale = atof(value);
4962 else if (!strcmp("classname", key))
4964 if (!strncmp(value, "light", 5))
4967 if (!strcmp(value, "light_fluoro"))
4972 overridecolor[0] = 1;
4973 overridecolor[1] = 1;
4974 overridecolor[2] = 1;
4976 if (!strcmp(value, "light_fluorospark"))
4981 overridecolor[0] = 1;
4982 overridecolor[1] = 1;
4983 overridecolor[2] = 1;
4985 if (!strcmp(value, "light_globe"))
4990 overridecolor[0] = 1;
4991 overridecolor[1] = 0.8;
4992 overridecolor[2] = 0.4;
4994 if (!strcmp(value, "light_flame_large_yellow"))
4999 overridecolor[0] = 1;
5000 overridecolor[1] = 0.5;
5001 overridecolor[2] = 0.1;
5003 if (!strcmp(value, "light_flame_small_yellow"))
5008 overridecolor[0] = 1;
5009 overridecolor[1] = 0.5;
5010 overridecolor[2] = 0.1;
5012 if (!strcmp(value, "light_torch_small_white"))
5017 overridecolor[0] = 1;
5018 overridecolor[1] = 0.5;
5019 overridecolor[2] = 0.1;
5021 if (!strcmp(value, "light_torch_small_walltorch"))
5026 overridecolor[0] = 1;
5027 overridecolor[1] = 0.5;
5028 overridecolor[2] = 0.1;
5032 else if (!strcmp("style", key))
5033 style = atoi(value);
5034 else if (!strcmp("skin", key))
5035 skin = (int)atof(value);
5036 else if (!strcmp("pflags", key))
5037 pflags = (int)atof(value);
5038 else if (!strcmp("effects", key))
5039 effects = (int)atof(value);
5040 else if (cl.worldmodel->type == mod_brushq3)
5042 if (!strcmp("scale", key))
5043 lightscale = atof(value);
5044 if (!strcmp("fade", key))
5045 fadescale = atof(value);
5050 if (lightscale <= 0)
5054 if (color[0] == color[1] && color[0] == color[2])
5056 color[0] *= overridecolor[0];
5057 color[1] *= overridecolor[1];
5058 color[2] *= overridecolor[2];
5060 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5061 color[0] = color[0] * light[0];
5062 color[1] = color[1] * light[1];
5063 color[2] = color[2] * light[2];
5066 case LIGHTTYPE_MINUSX:
5068 case LIGHTTYPE_RECIPX:
5070 VectorScale(color, (1.0f / 16.0f), color);
5072 case LIGHTTYPE_RECIPXX:
5074 VectorScale(color, (1.0f / 16.0f), color);
5077 case LIGHTTYPE_NONE:
5081 case LIGHTTYPE_MINUSXX:
5084 VectorAdd(origin, originhack, origin);
5086 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);
5089 Mem_Free(entfiledata);
5093 void R_Shadow_SetCursorLocationForView(void)
5096 vec3_t dest, endpos;
5098 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5099 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
5100 if (trace.fraction < 1)
5102 dist = trace.fraction * r_editlights_cursordistance.value;
5103 push = r_editlights_cursorpushback.value;
5107 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5108 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5112 VectorClear( endpos );
5114 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5115 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5116 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5119 void R_Shadow_UpdateWorldLightSelection(void)
5121 if (r_editlights.integer)
5123 R_Shadow_SetCursorLocationForView();
5124 R_Shadow_SelectLightInView();
5127 R_Shadow_SelectLight(NULL);
5130 void R_Shadow_EditLights_Clear_f(void)
5132 R_Shadow_ClearWorldLights();
5135 void R_Shadow_EditLights_Reload_f(void)
5139 strlcpy(r_shadow_mapname, cl.worldmodel->name, sizeof(r_shadow_mapname));
5140 R_Shadow_ClearWorldLights();
5141 R_Shadow_LoadWorldLights();
5142 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5144 R_Shadow_LoadLightsFile();
5145 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5146 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5150 void R_Shadow_EditLights_Save_f(void)
5154 R_Shadow_SaveWorldLights();
5157 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
5159 R_Shadow_ClearWorldLights();
5160 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5163 void R_Shadow_EditLights_ImportLightsFile_f(void)
5165 R_Shadow_ClearWorldLights();
5166 R_Shadow_LoadLightsFile();
5169 void R_Shadow_EditLights_Spawn_f(void)
5172 if (!r_editlights.integer)
5174 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5177 if (Cmd_Argc() != 1)
5179 Con_Print("r_editlights_spawn does not take parameters\n");
5182 color[0] = color[1] = color[2] = 1;
5183 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5186 void R_Shadow_EditLights_Edit_f(void)
5188 vec3_t origin, angles, color;
5189 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5190 int style, shadows, flags, normalmode, realtimemode;
5191 char cubemapname[MAX_INPUTLINE];
5192 if (!r_editlights.integer)
5194 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5197 if (!r_shadow_selectedlight)
5199 Con_Print("No selected light.\n");
5202 VectorCopy(r_shadow_selectedlight->origin, origin);
5203 VectorCopy(r_shadow_selectedlight->angles, angles);
5204 VectorCopy(r_shadow_selectedlight->color, color);
5205 radius = r_shadow_selectedlight->radius;
5206 style = r_shadow_selectedlight->style;
5207 if (r_shadow_selectedlight->cubemapname)
5208 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5211 shadows = r_shadow_selectedlight->shadow;
5212 corona = r_shadow_selectedlight->corona;
5213 coronasizescale = r_shadow_selectedlight->coronasizescale;
5214 ambientscale = r_shadow_selectedlight->ambientscale;
5215 diffusescale = r_shadow_selectedlight->diffusescale;
5216 specularscale = r_shadow_selectedlight->specularscale;
5217 flags = r_shadow_selectedlight->flags;
5218 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5219 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5220 if (!strcmp(Cmd_Argv(1), "origin"))
5222 if (Cmd_Argc() != 5)
5224 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5227 origin[0] = atof(Cmd_Argv(2));
5228 origin[1] = atof(Cmd_Argv(3));
5229 origin[2] = atof(Cmd_Argv(4));
5231 else if (!strcmp(Cmd_Argv(1), "originx"))
5233 if (Cmd_Argc() != 3)
5235 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5238 origin[0] = atof(Cmd_Argv(2));
5240 else if (!strcmp(Cmd_Argv(1), "originy"))
5242 if (Cmd_Argc() != 3)
5244 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5247 origin[1] = atof(Cmd_Argv(2));
5249 else if (!strcmp(Cmd_Argv(1), "originz"))
5251 if (Cmd_Argc() != 3)
5253 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5256 origin[2] = atof(Cmd_Argv(2));
5258 else if (!strcmp(Cmd_Argv(1), "move"))
5260 if (Cmd_Argc() != 5)
5262 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5265 origin[0] += atof(Cmd_Argv(2));
5266 origin[1] += atof(Cmd_Argv(3));
5267 origin[2] += atof(Cmd_Argv(4));
5269 else if (!strcmp(Cmd_Argv(1), "movex"))
5271 if (Cmd_Argc() != 3)
5273 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5276 origin[0] += atof(Cmd_Argv(2));
5278 else if (!strcmp(Cmd_Argv(1), "movey"))
5280 if (Cmd_Argc() != 3)
5282 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5285 origin[1] += atof(Cmd_Argv(2));
5287 else if (!strcmp(Cmd_Argv(1), "movez"))
5289 if (Cmd_Argc() != 3)
5291 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5294 origin[2] += atof(Cmd_Argv(2));
5296 else if (!strcmp(Cmd_Argv(1), "angles"))
5298 if (Cmd_Argc() != 5)
5300 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5303 angles[0] = atof(Cmd_Argv(2));
5304 angles[1] = atof(Cmd_Argv(3));
5305 angles[2] = atof(Cmd_Argv(4));
5307 else if (!strcmp(Cmd_Argv(1), "anglesx"))
5309 if (Cmd_Argc() != 3)
5311 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5314 angles[0] = atof(Cmd_Argv(2));
5316 else if (!strcmp(Cmd_Argv(1), "anglesy"))
5318 if (Cmd_Argc() != 3)
5320 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5323 angles[1] = atof(Cmd_Argv(2));
5325 else if (!strcmp(Cmd_Argv(1), "anglesz"))
5327 if (Cmd_Argc() != 3)
5329 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5332 angles[2] = atof(Cmd_Argv(2));
5334 else if (!strcmp(Cmd_Argv(1), "color"))
5336 if (Cmd_Argc() != 5)
5338 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
5341 color[0] = atof(Cmd_Argv(2));
5342 color[1] = atof(Cmd_Argv(3));
5343 color[2] = atof(Cmd_Argv(4));
5345 else if (!strcmp(Cmd_Argv(1), "radius"))
5347 if (Cmd_Argc() != 3)
5349 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5352 radius = atof(Cmd_Argv(2));
5354 else if (!strcmp(Cmd_Argv(1), "colorscale"))
5356 if (Cmd_Argc() == 3)
5358 double scale = atof(Cmd_Argv(2));
5365 if (Cmd_Argc() != 5)
5367 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
5370 color[0] *= atof(Cmd_Argv(2));
5371 color[1] *= atof(Cmd_Argv(3));
5372 color[2] *= atof(Cmd_Argv(4));
5375 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
5377 if (Cmd_Argc() != 3)
5379 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5382 radius *= atof(Cmd_Argv(2));
5384 else if (!strcmp(Cmd_Argv(1), "style"))
5386 if (Cmd_Argc() != 3)
5388 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5391 style = atoi(Cmd_Argv(2));
5393 else if (!strcmp(Cmd_Argv(1), "cubemap"))
5397 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5400 if (Cmd_Argc() == 3)
5401 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
5405 else if (!strcmp(Cmd_Argv(1), "shadows"))
5407 if (Cmd_Argc() != 3)
5409 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5412 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5414 else if (!strcmp(Cmd_Argv(1), "corona"))
5416 if (Cmd_Argc() != 3)
5418 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5421 corona = atof(Cmd_Argv(2));
5423 else if (!strcmp(Cmd_Argv(1), "coronasize"))
5425 if (Cmd_Argc() != 3)
5427 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5430 coronasizescale = atof(Cmd_Argv(2));
5432 else if (!strcmp(Cmd_Argv(1), "ambient"))
5434 if (Cmd_Argc() != 3)
5436 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5439 ambientscale = atof(Cmd_Argv(2));
5441 else if (!strcmp(Cmd_Argv(1), "diffuse"))
5443 if (Cmd_Argc() != 3)
5445 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5448 diffusescale = atof(Cmd_Argv(2));
5450 else if (!strcmp(Cmd_Argv(1), "specular"))
5452 if (Cmd_Argc() != 3)
5454 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5457 specularscale = atof(Cmd_Argv(2));
5459 else if (!strcmp(Cmd_Argv(1), "normalmode"))
5461 if (Cmd_Argc() != 3)
5463 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5466 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5468 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
5470 if (Cmd_Argc() != 3)
5472 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5475 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5479 Con_Print("usage: r_editlights_edit [property] [value]\n");
5480 Con_Print("Selected light's properties:\n");
5481 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5482 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5483 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5484 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
5485 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
5486 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
5487 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5488 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
5489 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
5490 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
5491 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
5492 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
5493 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5494 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5497 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5498 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5501 void R_Shadow_EditLights_EditAll_f(void)
5507 if (!r_editlights.integer)
5509 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5513 // EditLights doesn't seem to have a "remove" command or something so:
5514 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5515 for (lightindex = 0;lightindex < range;lightindex++)
5517 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5520 R_Shadow_SelectLight(light);
5521 R_Shadow_EditLights_Edit_f();
5525 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
5527 int lightnumber, lightcount;
5528 size_t lightindex, range;
5532 if (!r_editlights.integer)
5534 x = vid_conwidth.value - 240;
5536 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
5539 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5540 for (lightindex = 0;lightindex < range;lightindex++)
5542 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5545 if (light == r_shadow_selectedlight)
5546 lightnumber = lightindex;
5549 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);y += 8;
5550 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);y += 8;
5552 if (r_shadow_selectedlight == NULL)
5554 dpsnprintf(temp, sizeof(temp), "Light #%i properties:", lightnumber);DrawQ_String(x, y, temp, 0, 8, 8, 1, 1, 1, 1, 0, NULL, true);y += 8;
5555 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);y += 8;
5556 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);y += 8;
5557 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);y += 8;
5558 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);y += 8;
5559 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);y += 8;
5560 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);y += 8;
5561 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);y += 8;
5562 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);y += 8;
5563 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);y += 8;
5564 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);y += 8;
5565 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);y += 8;
5566 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);y += 8;
5567 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);y += 8;
5568 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);y += 8;
5571 void R_Shadow_EditLights_ToggleShadow_f(void)
5573 if (!r_editlights.integer)
5575 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5578 if (!r_shadow_selectedlight)
5580 Con_Print("No selected light.\n");
5583 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);
5586 void R_Shadow_EditLights_ToggleCorona_f(void)
5588 if (!r_editlights.integer)
5590 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5593 if (!r_shadow_selectedlight)
5595 Con_Print("No selected light.\n");
5598 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);
5601 void R_Shadow_EditLights_Remove_f(void)
5603 if (!r_editlights.integer)
5605 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
5608 if (!r_shadow_selectedlight)
5610 Con_Print("No selected light.\n");
5613 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
5614 r_shadow_selectedlight = NULL;
5617 void R_Shadow_EditLights_Help_f(void)
5620 "Documentation on r_editlights system:\n"
5622 "r_editlights : enable/disable editing mode\n"
5623 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
5624 "r_editlights_cursorpushback : push back cursor this far from surface\n"
5625 "r_editlights_cursorpushoff : push cursor off surface this far\n"
5626 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
5627 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
5629 "r_editlights_help : this help\n"
5630 "r_editlights_clear : remove all lights\n"
5631 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
5632 "r_editlights_save : save to .rtlights file\n"
5633 "r_editlights_spawn : create a light with default settings\n"
5634 "r_editlights_edit command : edit selected light - more documentation below\n"
5635 "r_editlights_remove : remove selected light\n"
5636 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
5637 "r_editlights_importlightentitiesfrommap : reload light entities\n"
5638 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
5640 "origin x y z : set light location\n"
5641 "originx x: set x component of light location\n"
5642 "originy y: set y component of light location\n"
5643 "originz z: set z component of light location\n"
5644 "move x y z : adjust light location\n"
5645 "movex x: adjust x component of light location\n"
5646 "movey y: adjust y component of light location\n"
5647 "movez z: adjust z component of light location\n"
5648 "angles x y z : set light angles\n"
5649 "anglesx x: set x component of light angles\n"
5650 "anglesy y: set y component of light angles\n"
5651 "anglesz z: set z component of light angles\n"
5652 "color r g b : set color of light (can be brighter than 1 1 1)\n"
5653 "radius radius : set radius (size) of light\n"
5654 "colorscale grey : multiply color of light (1 does nothing)\n"
5655 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
5656 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
5657 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
5658 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
5659 "cubemap basename : set filter cubemap of light (not yet supported)\n"
5660 "shadows 1/0 : turn on/off shadows\n"
5661 "corona n : set corona intensity\n"
5662 "coronasize n : set corona size (0-1)\n"
5663 "ambient n : set ambient intensity (0-1)\n"
5664 "diffuse n : set diffuse intensity (0-1)\n"
5665 "specular n : set specular intensity (0-1)\n"
5666 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
5667 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
5668 "<nothing> : print light properties to console\n"
5672 void R_Shadow_EditLights_CopyInfo_f(void)
5674 if (!r_editlights.integer)
5676 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
5679 if (!r_shadow_selectedlight)
5681 Con_Print("No selected light.\n");
5684 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
5685 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
5686 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
5687 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
5688 if (r_shadow_selectedlight->cubemapname)
5689 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
5691 r_shadow_bufferlight.cubemapname[0] = 0;
5692 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
5693 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
5694 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
5695 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
5696 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
5697 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
5698 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
5701 void R_Shadow_EditLights_PasteInfo_f(void)
5703 if (!r_editlights.integer)
5705 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
5708 if (!r_shadow_selectedlight)
5710 Con_Print("No selected light.\n");
5713 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);
5716 void R_Shadow_EditLights_Init(void)
5718 Cvar_RegisterVariable(&r_editlights);
5719 Cvar_RegisterVariable(&r_editlights_cursordistance);
5720 Cvar_RegisterVariable(&r_editlights_cursorpushback);
5721 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
5722 Cvar_RegisterVariable(&r_editlights_cursorgrid);
5723 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
5724 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
5725 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
5726 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)");
5727 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
5728 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
5729 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
5730 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)");
5731 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
5732 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
5733 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
5734 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
5735 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
5736 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
5737 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)");
5743 =============================================================================
5747 =============================================================================
5750 void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, int dynamic)
5752 VectorClear(diffusecolor);
5753 VectorClear(diffusenormal);
5755 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
5757 ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_refdef.scene.ambient * (2.0f / 128.0f);
5758 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
5761 VectorSet(ambientcolor, 1, 1, 1);
5768 for (i = 0;i < r_refdef.scene.numlights;i++)
5770 light = r_refdef.scene.lights[i];
5771 Matrix4x4_Transform(&light->matrix_worldtolight, p, v);
5772 f = 1 - VectorLength2(v);
5773 if (f > 0 && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
5774 VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);