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_DOT3,
158 R_SHADOW_RENDERMODE_LIGHT_GLSL,
159 R_SHADOW_RENDERMODE_VISIBLEVOLUMES,
160 R_SHADOW_RENDERMODE_VISIBLELIGHTING,
161 R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE,
162 R_SHADOW_RENDERMODE_SHADOWMAP2D,
163 R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE,
165 r_shadow_rendermode_t;
167 r_shadow_rendermode_t r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
168 r_shadow_rendermode_t r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_NONE;
169 r_shadow_rendermode_t r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_NONE;
170 r_shadow_rendermode_t r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_NONE;
171 qboolean r_shadow_usingshadowmaprect;
172 qboolean r_shadow_usingshadowmap2d;
173 qboolean r_shadow_usingshadowmapcube;
174 int r_shadow_shadowmapside;
175 float r_shadow_shadowmap_texturescale[2];
176 float r_shadow_shadowmap_parameters[4];
178 int r_shadow_drawbuffer;
179 int r_shadow_readbuffer;
181 int r_shadow_cullface_front, r_shadow_cullface_back;
182 GLuint r_shadow_fborectangle;
183 GLuint r_shadow_fbocubeside[R_SHADOW_SHADOWMAP_NUMCUBEMAPS][6];
184 GLuint r_shadow_fbo2d;
185 int r_shadow_shadowmode;
186 int r_shadow_shadowmapfilterquality;
187 int r_shadow_shadowmaptexturetype;
188 int r_shadow_shadowmapprecision;
189 int r_shadow_shadowmapmaxsize;
190 qboolean r_shadow_shadowmapvsdct;
191 qboolean r_shadow_shadowmapsampler;
192 int r_shadow_shadowmappcf;
193 int r_shadow_shadowmapborder;
194 int r_shadow_lightscissor[4];
196 int maxshadowtriangles;
199 int maxshadowvertices;
200 float *shadowvertex3f;
210 unsigned char *shadowsides;
211 int *shadowsideslist;
218 int r_shadow_buffer_numleafpvsbytes;
219 unsigned char *r_shadow_buffer_visitingleafpvs;
220 unsigned char *r_shadow_buffer_leafpvs;
221 int *r_shadow_buffer_leaflist;
223 int r_shadow_buffer_numsurfacepvsbytes;
224 unsigned char *r_shadow_buffer_surfacepvs;
225 int *r_shadow_buffer_surfacelist;
226 unsigned char *r_shadow_buffer_surfacesides;
228 int r_shadow_buffer_numshadowtrispvsbytes;
229 unsigned char *r_shadow_buffer_shadowtrispvs;
230 int r_shadow_buffer_numlighttrispvsbytes;
231 unsigned char *r_shadow_buffer_lighttrispvs;
233 rtexturepool_t *r_shadow_texturepool;
234 rtexture_t *r_shadow_attenuationgradienttexture;
235 rtexture_t *r_shadow_attenuation2dtexture;
236 rtexture_t *r_shadow_attenuation3dtexture;
237 rtexture_t *r_shadow_lightcorona;
238 rtexture_t *r_shadow_shadowmaprectangletexture;
239 rtexture_t *r_shadow_shadowmap2dtexture;
240 rtexture_t *r_shadow_shadowmapcubetexture[R_SHADOW_SHADOWMAP_NUMCUBEMAPS];
241 rtexture_t *r_shadow_shadowmapvsdcttexture;
242 int r_shadow_shadowmapsize; // changes for each light based on distance
243 int r_shadow_shadowmaplod; // changes for each light based on distance
245 // lights are reloaded when this changes
246 char r_shadow_mapname[MAX_QPATH];
248 // used only for light filters (cubemaps)
249 rtexturepool_t *r_shadow_filters_texturepool;
251 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"};
252 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"};
253 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
254 cvar_t r_shadow_usenormalmap = {CVAR_SAVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"};
255 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)"};
256 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"};
257 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
258 cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
259 cvar_t r_shadow_gloss2exponent = {0, "r_shadow_gloss2exponent", "32", "same as r_shadow_glossexponent but for forced gloss (gloss 2) surfaces"};
260 cvar_t r_shadow_glossexact = {0, "r_shadow_glossexact", "0", "use exact reflection math for gloss (slightly slower, but should look a tad better)"};
261 cvar_t r_shadow_lightattenuationdividebias = {0, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"};
262 cvar_t r_shadow_lightattenuationlinearscale = {0, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"};
263 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
264 cvar_t r_shadow_lightradiusscale = {0, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
265 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1", "use portal culling to exactly determine lit triangles when compiling world lights"};
266 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000", "how far to cast shadows"};
267 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)"};
268 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
269 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
270 cvar_t r_shadow_realtime_dlight_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
271 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
272 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)"};
273 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"};
274 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
275 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
276 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"};
277 cvar_t r_shadow_realtime_world_compilesvbsp = {0, "r_shadow_realtime_world_compilesvbsp", "1", "enables svbsp optimization during compilation"};
278 cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "1", "enables portal-based culling optimization during compilation"};
279 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)"};
280 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"};
281 cvar_t r_shadow_shadowmapping_texturetype = {CVAR_SAVE, "r_shadow_shadowmapping_texturetype", "0", "shadowmap texture types: 0 = auto-select, 1 = 2D, 2 = rectangle, 3 = cubemap"};
282 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)"};
283 cvar_t r_shadow_shadowmapping_precision = {CVAR_SAVE, "r_shadow_shadowmapping_precision", "24", "requested minimum shadowmap texture precision"};
284 cvar_t r_shadow_shadowmapping_vsdct = {CVAR_SAVE, "r_shadow_shadowmapping_vsdct", "1", "enables use of virtual shadow depth cube texture"};
285 cvar_t r_shadow_shadowmapping_minsize = {CVAR_SAVE, "r_shadow_shadowmapping_minsize", "32", "shadowmap size limit"};
286 cvar_t r_shadow_shadowmapping_maxsize = {CVAR_SAVE, "r_shadow_shadowmapping_maxsize", "512", "shadowmap size limit"};
287 cvar_t r_shadow_shadowmapping_lod_bias = {CVAR_SAVE, "r_shadow_shadowmapping_lod_bias", "16", "shadowmap size bias"};
288 cvar_t r_shadow_shadowmapping_lod_scale = {CVAR_SAVE, "r_shadow_shadowmapping_lod_scale", "128", "shadowmap size scaling parameter"};
289 cvar_t r_shadow_shadowmapping_bordersize = {CVAR_SAVE, "r_shadow_shadowmapping_bordersize", "4", "shadowmap size bias for filtering"};
290 cvar_t r_shadow_shadowmapping_nearclip = {CVAR_SAVE, "r_shadow_shadowmapping_nearclip", "1", "shadowmap nearclip in world units"};
291 cvar_t r_shadow_shadowmapping_bias = {CVAR_SAVE, "r_shadow_shadowmapping_bias", "0.03", "shadowmap bias parameter (this is multiplied by nearclip * 1024 / lodsize)"};
292 cvar_t r_shadow_culltriangles = {0, "r_shadow_culltriangles", "1", "performs more expensive tests to remove unnecessary triangles of lit surfaces"};
293 cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
294 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)"};
295 cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "1", "use 3D voxel textures for spherical attenuation rather than cylindrical (does not affect r_glsl lighting)"};
296 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "1", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
297 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"};
298 cvar_t r_coronas_occlusionquery = {CVAR_SAVE, "r_coronas_occlusionquery", "1", "use GL_ARB_occlusion_query extension if supported (fades coronas according to visibility)"};
299 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
300 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
301 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
302 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
303 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
304 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
305 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
306 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
307 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
309 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
310 #define ATTENTABLESIZE 256
311 // 1D gradient, 2D circle and 3D sphere attenuation textures
312 #define ATTEN1DSIZE 32
313 #define ATTEN2DSIZE 64
314 #define ATTEN3DSIZE 32
316 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
317 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
318 static float r_shadow_attentable[ATTENTABLESIZE+1];
320 rtlight_t *r_shadow_compilingrtlight;
321 static memexpandablearray_t r_shadow_worldlightsarray;
322 dlight_t *r_shadow_selectedlight;
323 dlight_t r_shadow_bufferlight;
324 vec3_t r_editlights_cursorlocation;
326 extern int con_vislines;
328 typedef struct cubemapinfo_s
335 #define MAX_CUBEMAPS 256
336 static int numcubemaps;
337 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
339 void R_Shadow_UncompileWorldLights(void);
340 void R_Shadow_ClearWorldLights(void);
341 void R_Shadow_SaveWorldLights(void);
342 void R_Shadow_LoadWorldLights(void);
343 void R_Shadow_LoadLightsFile(void);
344 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
345 void R_Shadow_EditLights_Reload_f(void);
346 void R_Shadow_ValidateCvars(void);
347 static void R_Shadow_MakeTextures(void);
349 // VorteX: custom editor light sprites
350 #define EDLIGHTSPRSIZE 8
351 cachepic_t *r_editlights_sprcursor;
352 cachepic_t *r_editlights_sprlight;
353 cachepic_t *r_editlights_sprnoshadowlight;
354 cachepic_t *r_editlights_sprcubemaplight;
355 cachepic_t *r_editlights_sprcubemapnoshadowlight;
356 cachepic_t *r_editlights_sprselection;
358 void R_Shadow_SetShadowMode(void)
360 r_shadow_shadowmapmaxsize = bound(1, r_shadow_shadowmapping_maxsize.integer, 2048);
361 r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer != 0;
362 r_shadow_shadowmapfilterquality = r_shadow_shadowmapping_filterquality.integer;
363 r_shadow_shadowmaptexturetype = r_shadow_shadowmapping_texturetype.integer;
364 r_shadow_shadowmapprecision = r_shadow_shadowmapping_precision.integer;
365 r_shadow_shadowmapborder = bound(0, r_shadow_shadowmapping_bordersize.integer, 16);
366 r_shadow_shadowmaplod = -1;
367 r_shadow_shadowmapsize = 0;
368 r_shadow_shadowmapsampler = false;
369 r_shadow_shadowmappcf = 0;
370 r_shadow_shadowmode = 0;
371 if(r_shadow_shadowmapping.integer)
373 if(r_shadow_shadowmapfilterquality < 0)
375 if(strstr(gl_vendor, "NVIDIA"))
377 r_shadow_shadowmapsampler = gl_support_arb_shadow;
378 r_shadow_shadowmappcf = 1;
380 else if(gl_support_amd_texture_texture4 || gl_support_arb_texture_gather)
381 r_shadow_shadowmappcf = 1;
382 else if(strstr(gl_vendor, "ATI"))
383 r_shadow_shadowmappcf = 1;
385 r_shadow_shadowmapsampler = gl_support_arb_shadow;
389 switch (r_shadow_shadowmapfilterquality)
392 r_shadow_shadowmapsampler = gl_support_arb_shadow;
395 r_shadow_shadowmapsampler = gl_support_arb_shadow;
396 r_shadow_shadowmappcf = 1;
399 r_shadow_shadowmappcf = 1;
402 r_shadow_shadowmappcf = 2;
406 r_shadow_shadowmode = r_shadow_shadowmaptexturetype;
407 if(r_shadow_shadowmode <= 0)
409 if((gl_support_amd_texture_texture4 || gl_support_arb_texture_gather) && r_shadow_shadowmappcf && !r_shadow_shadowmapsampler)
410 r_shadow_shadowmode = 1;
411 else if(gl_texturerectangle)
412 r_shadow_shadowmode = 2;
414 r_shadow_shadowmode = 1;
419 void R_Shadow_FreeShadowMaps(void)
423 R_Shadow_SetShadowMode();
425 if (r_shadow_fborectangle)
426 qglDeleteFramebuffersEXT(1, &r_shadow_fborectangle);
427 r_shadow_fborectangle = 0;
431 qglDeleteFramebuffersEXT(1, &r_shadow_fbo2d);
434 for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
435 if (r_shadow_fbocubeside[i][0])
436 qglDeleteFramebuffersEXT(6, r_shadow_fbocubeside[i]);
437 memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
440 if (r_shadow_shadowmaprectangletexture)
441 R_FreeTexture(r_shadow_shadowmaprectangletexture);
442 r_shadow_shadowmaprectangletexture = NULL;
444 if (r_shadow_shadowmap2dtexture)
445 R_FreeTexture(r_shadow_shadowmap2dtexture);
446 r_shadow_shadowmap2dtexture = NULL;
448 for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
449 if (r_shadow_shadowmapcubetexture[i])
450 R_FreeTexture(r_shadow_shadowmapcubetexture[i]);
451 memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
453 if (r_shadow_shadowmapvsdcttexture)
454 R_FreeTexture(r_shadow_shadowmapvsdcttexture);
455 r_shadow_shadowmapvsdcttexture = NULL;
460 void r_shadow_start(void)
462 // allocate vertex processing arrays
464 r_shadow_attenuationgradienttexture = NULL;
465 r_shadow_attenuation2dtexture = NULL;
466 r_shadow_attenuation3dtexture = NULL;
467 r_shadow_shadowmode = 0;
468 r_shadow_shadowmaprectangletexture = NULL;
469 r_shadow_shadowmap2dtexture = NULL;
470 memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
471 r_shadow_shadowmapvsdcttexture = NULL;
472 r_shadow_shadowmapmaxsize = 0;
473 r_shadow_shadowmapsize = 0;
474 r_shadow_shadowmaplod = 0;
475 r_shadow_shadowmapfilterquality = 0;
476 r_shadow_shadowmaptexturetype = 0;
477 r_shadow_shadowmapprecision = 0;
478 r_shadow_shadowmapvsdct = false;
479 r_shadow_shadowmapsampler = false;
480 r_shadow_shadowmappcf = 0;
481 r_shadow_fborectangle = 0;
483 memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
485 R_Shadow_FreeShadowMaps();
487 r_shadow_texturepool = NULL;
488 r_shadow_filters_texturepool = NULL;
489 R_Shadow_ValidateCvars();
490 R_Shadow_MakeTextures();
491 maxshadowtriangles = 0;
492 shadowelements = NULL;
493 maxshadowvertices = 0;
494 shadowvertex3f = NULL;
502 shadowmarklist = NULL;
507 shadowsideslist = NULL;
508 r_shadow_buffer_numleafpvsbytes = 0;
509 r_shadow_buffer_visitingleafpvs = NULL;
510 r_shadow_buffer_leafpvs = NULL;
511 r_shadow_buffer_leaflist = NULL;
512 r_shadow_buffer_numsurfacepvsbytes = 0;
513 r_shadow_buffer_surfacepvs = NULL;
514 r_shadow_buffer_surfacelist = NULL;
515 r_shadow_buffer_surfacesides = NULL;
516 r_shadow_buffer_numshadowtrispvsbytes = 0;
517 r_shadow_buffer_shadowtrispvs = NULL;
518 r_shadow_buffer_numlighttrispvsbytes = 0;
519 r_shadow_buffer_lighttrispvs = NULL;
522 void r_shadow_shutdown(void)
525 R_Shadow_UncompileWorldLights();
527 R_Shadow_FreeShadowMaps();
531 r_shadow_attenuationgradienttexture = NULL;
532 r_shadow_attenuation2dtexture = NULL;
533 r_shadow_attenuation3dtexture = NULL;
534 R_FreeTexturePool(&r_shadow_texturepool);
535 R_FreeTexturePool(&r_shadow_filters_texturepool);
536 maxshadowtriangles = 0;
538 Mem_Free(shadowelements);
539 shadowelements = NULL;
541 Mem_Free(shadowvertex3f);
542 shadowvertex3f = NULL;
545 Mem_Free(vertexupdate);
548 Mem_Free(vertexremap);
554 Mem_Free(shadowmark);
557 Mem_Free(shadowmarklist);
558 shadowmarklist = NULL;
563 Mem_Free(shadowsides);
566 Mem_Free(shadowsideslist);
567 shadowsideslist = NULL;
568 r_shadow_buffer_numleafpvsbytes = 0;
569 if (r_shadow_buffer_visitingleafpvs)
570 Mem_Free(r_shadow_buffer_visitingleafpvs);
571 r_shadow_buffer_visitingleafpvs = NULL;
572 if (r_shadow_buffer_leafpvs)
573 Mem_Free(r_shadow_buffer_leafpvs);
574 r_shadow_buffer_leafpvs = NULL;
575 if (r_shadow_buffer_leaflist)
576 Mem_Free(r_shadow_buffer_leaflist);
577 r_shadow_buffer_leaflist = NULL;
578 r_shadow_buffer_numsurfacepvsbytes = 0;
579 if (r_shadow_buffer_surfacepvs)
580 Mem_Free(r_shadow_buffer_surfacepvs);
581 r_shadow_buffer_surfacepvs = NULL;
582 if (r_shadow_buffer_surfacelist)
583 Mem_Free(r_shadow_buffer_surfacelist);
584 r_shadow_buffer_surfacelist = NULL;
585 if (r_shadow_buffer_surfacesides)
586 Mem_Free(r_shadow_buffer_surfacesides);
587 r_shadow_buffer_surfacesides = NULL;
588 r_shadow_buffer_numshadowtrispvsbytes = 0;
589 if (r_shadow_buffer_shadowtrispvs)
590 Mem_Free(r_shadow_buffer_shadowtrispvs);
591 r_shadow_buffer_numlighttrispvsbytes = 0;
592 if (r_shadow_buffer_lighttrispvs)
593 Mem_Free(r_shadow_buffer_lighttrispvs);
596 void r_shadow_newmap(void)
598 if (cl.worldmodel && strncmp(cl.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
599 R_Shadow_EditLights_Reload_f();
602 void R_Shadow_Help_f(void)
605 "Documentation on r_shadow system:\n"
607 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
608 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
609 "r_shadow_debuglight : render only this light number (-1 = all)\n"
610 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
611 "r_shadow_gloss2intensity : brightness of forced gloss\n"
612 "r_shadow_glossintensity : brightness of textured gloss\n"
613 "r_shadow_lightattenuationlinearscale : used to generate attenuation texture\n"
614 "r_shadow_lightattenuationdividebias : used to generate attenuation texture\n"
615 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
616 "r_shadow_lightradiusscale : scale rendering radius of all lights\n"
617 "r_shadow_portallight : use portal visibility for static light precomputation\n"
618 "r_shadow_projectdistance : shadow volume projection distance\n"
619 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
620 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
621 "r_shadow_realtime_world : use high quality world lighting mode\n"
622 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
623 "r_shadow_realtime_world_shadows : cast shadows from world lights\n"
624 "r_shadow_realtime_world_compile : compile surface/visibility information\n"
625 "r_shadow_realtime_world_compileshadow : compile shadow geometry\n"
626 "r_shadow_scissor : use scissor optimization\n"
627 "r_shadow_polygonfactor : nudge shadow volumes closer/further\n"
628 "r_shadow_polygonoffset : nudge shadow volumes closer/further\n"
629 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
630 "r_showlighting : useful for performance testing; bright = slow!\n"
631 "r_showshadowvolumes : useful for performance testing; bright = slow!\n"
633 "r_shadow_help : this help\n"
637 void R_Shadow_Init(void)
639 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
640 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
641 Cvar_RegisterVariable(&r_shadow_usenormalmap);
642 Cvar_RegisterVariable(&r_shadow_debuglight);
643 Cvar_RegisterVariable(&r_shadow_gloss);
644 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
645 Cvar_RegisterVariable(&r_shadow_glossintensity);
646 Cvar_RegisterVariable(&r_shadow_glossexponent);
647 Cvar_RegisterVariable(&r_shadow_gloss2exponent);
648 Cvar_RegisterVariable(&r_shadow_glossexact);
649 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
650 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
651 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
652 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
653 Cvar_RegisterVariable(&r_shadow_portallight);
654 Cvar_RegisterVariable(&r_shadow_projectdistance);
655 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
656 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
657 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
658 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
659 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
660 Cvar_RegisterVariable(&r_shadow_realtime_world);
661 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
662 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
663 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
664 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
665 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
666 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
667 Cvar_RegisterVariable(&r_shadow_scissor);
668 Cvar_RegisterVariable(&r_shadow_shadowmapping);
669 Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
670 Cvar_RegisterVariable(&r_shadow_shadowmapping_texturetype);
671 Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
672 Cvar_RegisterVariable(&r_shadow_shadowmapping_precision);
673 Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
674 Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
675 Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
676 Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
677 Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
678 Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
679 Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
680 Cvar_RegisterVariable(&r_shadow_culltriangles);
681 Cvar_RegisterVariable(&r_shadow_polygonfactor);
682 Cvar_RegisterVariable(&r_shadow_polygonoffset);
683 Cvar_RegisterVariable(&r_shadow_texture3d);
684 Cvar_RegisterVariable(&r_coronas);
685 Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
686 Cvar_RegisterVariable(&r_coronas_occlusionquery);
687 Cvar_RegisterVariable(&gl_flashblend);
688 Cvar_RegisterVariable(&gl_ext_separatestencil);
689 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
690 if (gamemode == GAME_TENEBRAE)
692 Cvar_SetValue("r_shadow_gloss", 2);
693 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
695 Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f, "prints documentation on console commands and variables used by realtime lighting and shadowing system");
696 R_Shadow_EditLights_Init();
697 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
698 maxshadowtriangles = 0;
699 shadowelements = NULL;
700 maxshadowvertices = 0;
701 shadowvertex3f = NULL;
709 shadowmarklist = NULL;
714 shadowsideslist = NULL;
715 r_shadow_buffer_numleafpvsbytes = 0;
716 r_shadow_buffer_visitingleafpvs = NULL;
717 r_shadow_buffer_leafpvs = NULL;
718 r_shadow_buffer_leaflist = NULL;
719 r_shadow_buffer_numsurfacepvsbytes = 0;
720 r_shadow_buffer_surfacepvs = NULL;
721 r_shadow_buffer_surfacelist = NULL;
722 r_shadow_buffer_surfacesides = NULL;
723 r_shadow_buffer_shadowtrispvs = NULL;
724 r_shadow_buffer_lighttrispvs = NULL;
725 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
728 matrix4x4_t matrix_attenuationxyz =
731 {0.5, 0.0, 0.0, 0.5},
732 {0.0, 0.5, 0.0, 0.5},
733 {0.0, 0.0, 0.5, 0.5},
738 matrix4x4_t matrix_attenuationz =
741 {0.0, 0.0, 0.5, 0.5},
742 {0.0, 0.0, 0.0, 0.5},
743 {0.0, 0.0, 0.0, 0.5},
748 void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles, int vertscale, int triscale)
750 numvertices = ((numvertices + 255) & ~255) * vertscale;
751 numtriangles = ((numtriangles + 255) & ~255) * triscale;
752 // make sure shadowelements is big enough for this volume
753 if (maxshadowtriangles < numtriangles)
755 maxshadowtriangles = numtriangles;
757 Mem_Free(shadowelements);
758 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[3]));
760 // make sure shadowvertex3f is big enough for this volume
761 if (maxshadowvertices < numvertices)
763 maxshadowvertices = numvertices;
765 Mem_Free(shadowvertex3f);
766 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[3]));
770 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
772 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
773 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
774 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
775 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
776 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
778 if (r_shadow_buffer_visitingleafpvs)
779 Mem_Free(r_shadow_buffer_visitingleafpvs);
780 if (r_shadow_buffer_leafpvs)
781 Mem_Free(r_shadow_buffer_leafpvs);
782 if (r_shadow_buffer_leaflist)
783 Mem_Free(r_shadow_buffer_leaflist);
784 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
785 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
786 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
787 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
789 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
791 if (r_shadow_buffer_surfacepvs)
792 Mem_Free(r_shadow_buffer_surfacepvs);
793 if (r_shadow_buffer_surfacelist)
794 Mem_Free(r_shadow_buffer_surfacelist);
795 if (r_shadow_buffer_surfacesides)
796 Mem_Free(r_shadow_buffer_surfacesides);
797 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
798 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
799 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
800 r_shadow_buffer_surfacesides = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
802 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
804 if (r_shadow_buffer_shadowtrispvs)
805 Mem_Free(r_shadow_buffer_shadowtrispvs);
806 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
807 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
809 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
811 if (r_shadow_buffer_lighttrispvs)
812 Mem_Free(r_shadow_buffer_lighttrispvs);
813 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
814 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
818 void R_Shadow_PrepareShadowMark(int numtris)
820 // make sure shadowmark is big enough for this volume
821 if (maxshadowmark < numtris)
823 maxshadowmark = numtris;
825 Mem_Free(shadowmark);
827 Mem_Free(shadowmarklist);
828 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
829 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
833 // if shadowmarkcount wrapped we clear the array and adjust accordingly
834 if (shadowmarkcount == 0)
837 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
842 void R_Shadow_PrepareShadowSides(int numtris)
844 if (maxshadowsides < numtris)
846 maxshadowsides = numtris;
848 Mem_Free(shadowsides);
850 Mem_Free(shadowsideslist);
851 shadowsides = (unsigned char *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsides));
852 shadowsideslist = (int *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsideslist));
857 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)
860 int outtriangles = 0, outvertices = 0;
863 float ratio, direction[3], projectvector[3];
865 if (projectdirection)
866 VectorScale(projectdirection, projectdistance, projectvector);
868 VectorClear(projectvector);
870 // create the vertices
871 if (projectdirection)
873 for (i = 0;i < numshadowmarktris;i++)
875 element = inelement3i + shadowmarktris[i] * 3;
876 for (j = 0;j < 3;j++)
878 if (vertexupdate[element[j]] != vertexupdatenum)
880 vertexupdate[element[j]] = vertexupdatenum;
881 vertexremap[element[j]] = outvertices;
882 vertex = invertex3f + element[j] * 3;
883 // project one copy of the vertex according to projectvector
884 VectorCopy(vertex, outvertex3f);
885 VectorAdd(vertex, projectvector, (outvertex3f + 3));
894 for (i = 0;i < numshadowmarktris;i++)
896 element = inelement3i + shadowmarktris[i] * 3;
897 for (j = 0;j < 3;j++)
899 if (vertexupdate[element[j]] != vertexupdatenum)
901 vertexupdate[element[j]] = vertexupdatenum;
902 vertexremap[element[j]] = outvertices;
903 vertex = invertex3f + element[j] * 3;
904 // project one copy of the vertex to the sphere radius of the light
905 // (FIXME: would projecting it to the light box be better?)
906 VectorSubtract(vertex, projectorigin, direction);
907 ratio = projectdistance / VectorLength(direction);
908 VectorCopy(vertex, outvertex3f);
909 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
917 if (r_shadow_frontsidecasting.integer)
919 for (i = 0;i < numshadowmarktris;i++)
921 int remappedelement[3];
923 const int *neighbortriangle;
925 markindex = shadowmarktris[i] * 3;
926 element = inelement3i + markindex;
927 neighbortriangle = inneighbor3i + markindex;
928 // output the front and back triangles
929 outelement3i[0] = vertexremap[element[0]];
930 outelement3i[1] = vertexremap[element[1]];
931 outelement3i[2] = vertexremap[element[2]];
932 outelement3i[3] = vertexremap[element[2]] + 1;
933 outelement3i[4] = vertexremap[element[1]] + 1;
934 outelement3i[5] = vertexremap[element[0]] + 1;
938 // output the sides (facing outward from this triangle)
939 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
941 remappedelement[0] = vertexremap[element[0]];
942 remappedelement[1] = vertexremap[element[1]];
943 outelement3i[0] = remappedelement[1];
944 outelement3i[1] = remappedelement[0];
945 outelement3i[2] = remappedelement[0] + 1;
946 outelement3i[3] = remappedelement[1];
947 outelement3i[4] = remappedelement[0] + 1;
948 outelement3i[5] = remappedelement[1] + 1;
953 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
955 remappedelement[1] = vertexremap[element[1]];
956 remappedelement[2] = vertexremap[element[2]];
957 outelement3i[0] = remappedelement[2];
958 outelement3i[1] = remappedelement[1];
959 outelement3i[2] = remappedelement[1] + 1;
960 outelement3i[3] = remappedelement[2];
961 outelement3i[4] = remappedelement[1] + 1;
962 outelement3i[5] = remappedelement[2] + 1;
967 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
969 remappedelement[0] = vertexremap[element[0]];
970 remappedelement[2] = vertexremap[element[2]];
971 outelement3i[0] = remappedelement[0];
972 outelement3i[1] = remappedelement[2];
973 outelement3i[2] = remappedelement[2] + 1;
974 outelement3i[3] = remappedelement[0];
975 outelement3i[4] = remappedelement[2] + 1;
976 outelement3i[5] = remappedelement[0] + 1;
985 for (i = 0;i < numshadowmarktris;i++)
987 int remappedelement[3];
989 const int *neighbortriangle;
991 markindex = shadowmarktris[i] * 3;
992 element = inelement3i + markindex;
993 neighbortriangle = inneighbor3i + markindex;
994 // output the front and back triangles
995 outelement3i[0] = vertexremap[element[2]];
996 outelement3i[1] = vertexremap[element[1]];
997 outelement3i[2] = vertexremap[element[0]];
998 outelement3i[3] = vertexremap[element[0]] + 1;
999 outelement3i[4] = vertexremap[element[1]] + 1;
1000 outelement3i[5] = vertexremap[element[2]] + 1;
1004 // output the sides (facing outward from this triangle)
1005 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
1007 remappedelement[0] = vertexremap[element[0]];
1008 remappedelement[1] = vertexremap[element[1]];
1009 outelement3i[0] = remappedelement[0];
1010 outelement3i[1] = remappedelement[1];
1011 outelement3i[2] = remappedelement[1] + 1;
1012 outelement3i[3] = remappedelement[0];
1013 outelement3i[4] = remappedelement[1] + 1;
1014 outelement3i[5] = remappedelement[0] + 1;
1019 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1021 remappedelement[1] = vertexremap[element[1]];
1022 remappedelement[2] = vertexremap[element[2]];
1023 outelement3i[0] = remappedelement[1];
1024 outelement3i[1] = remappedelement[2];
1025 outelement3i[2] = remappedelement[2] + 1;
1026 outelement3i[3] = remappedelement[1];
1027 outelement3i[4] = remappedelement[2] + 1;
1028 outelement3i[5] = remappedelement[1] + 1;
1033 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1035 remappedelement[0] = vertexremap[element[0]];
1036 remappedelement[2] = vertexremap[element[2]];
1037 outelement3i[0] = remappedelement[2];
1038 outelement3i[1] = remappedelement[0];
1039 outelement3i[2] = remappedelement[0] + 1;
1040 outelement3i[3] = remappedelement[2];
1041 outelement3i[4] = remappedelement[0] + 1;
1042 outelement3i[5] = remappedelement[2] + 1;
1050 *outnumvertices = outvertices;
1051 return outtriangles;
1054 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)
1057 int outtriangles = 0, outvertices = 0;
1059 const float *vertex;
1060 float ratio, direction[3], projectvector[3];
1063 if (projectdirection)
1064 VectorScale(projectdirection, projectdistance, projectvector);
1066 VectorClear(projectvector);
1068 for (i = 0;i < numshadowmarktris;i++)
1070 int remappedelement[3];
1072 const int *neighbortriangle;
1074 markindex = shadowmarktris[i] * 3;
1075 neighbortriangle = inneighbor3i + markindex;
1076 side[0] = shadowmark[neighbortriangle[0]] == shadowmarkcount;
1077 side[1] = shadowmark[neighbortriangle[1]] == shadowmarkcount;
1078 side[2] = shadowmark[neighbortriangle[2]] == shadowmarkcount;
1079 if (side[0] + side[1] + side[2] == 0)
1083 element = inelement3i + markindex;
1085 // create the vertices
1086 for (j = 0;j < 3;j++)
1088 if (side[j] + side[j+1] == 0)
1091 if (vertexupdate[k] != vertexupdatenum)
1093 vertexupdate[k] = vertexupdatenum;
1094 vertexremap[k] = outvertices;
1095 vertex = invertex3f + k * 3;
1096 VectorCopy(vertex, outvertex3f);
1097 if (projectdirection)
1099 // project one copy of the vertex according to projectvector
1100 VectorAdd(vertex, projectvector, (outvertex3f + 3));
1104 // project one copy of the vertex to the sphere radius of the light
1105 // (FIXME: would projecting it to the light box be better?)
1106 VectorSubtract(vertex, projectorigin, direction);
1107 ratio = projectdistance / VectorLength(direction);
1108 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1115 // output the sides (facing outward from this triangle)
1118 remappedelement[0] = vertexremap[element[0]];
1119 remappedelement[1] = vertexremap[element[1]];
1120 outelement3i[0] = remappedelement[1];
1121 outelement3i[1] = remappedelement[0];
1122 outelement3i[2] = remappedelement[0] + 1;
1123 outelement3i[3] = remappedelement[1];
1124 outelement3i[4] = remappedelement[0] + 1;
1125 outelement3i[5] = remappedelement[1] + 1;
1132 remappedelement[1] = vertexremap[element[1]];
1133 remappedelement[2] = vertexremap[element[2]];
1134 outelement3i[0] = remappedelement[2];
1135 outelement3i[1] = remappedelement[1];
1136 outelement3i[2] = remappedelement[1] + 1;
1137 outelement3i[3] = remappedelement[2];
1138 outelement3i[4] = remappedelement[1] + 1;
1139 outelement3i[5] = remappedelement[2] + 1;
1146 remappedelement[0] = vertexremap[element[0]];
1147 remappedelement[2] = vertexremap[element[2]];
1148 outelement3i[0] = remappedelement[0];
1149 outelement3i[1] = remappedelement[2];
1150 outelement3i[2] = remappedelement[2] + 1;
1151 outelement3i[3] = remappedelement[0];
1152 outelement3i[4] = remappedelement[2] + 1;
1153 outelement3i[5] = remappedelement[0] + 1;
1160 *outnumvertices = outvertices;
1161 return outtriangles;
1164 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)
1170 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1172 tend = firsttriangle + numtris;
1173 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1175 // surface box entirely inside light box, no box cull
1176 if (projectdirection)
1178 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1180 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
1181 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1182 shadowmarklist[numshadowmark++] = t;
1187 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1188 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
1189 shadowmarklist[numshadowmark++] = t;
1194 // surface box not entirely inside light box, cull each triangle
1195 if (projectdirection)
1197 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1199 v[0] = invertex3f + e[0] * 3;
1200 v[1] = invertex3f + e[1] * 3;
1201 v[2] = invertex3f + e[2] * 3;
1202 TriangleNormal(v[0], v[1], v[2], normal);
1203 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1204 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1205 shadowmarklist[numshadowmark++] = t;
1210 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1212 v[0] = invertex3f + e[0] * 3;
1213 v[1] = invertex3f + e[1] * 3;
1214 v[2] = invertex3f + e[2] * 3;
1215 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1216 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1217 shadowmarklist[numshadowmark++] = t;
1223 qboolean R_Shadow_UseZPass(vec3_t mins, vec3_t maxs)
1228 if (r_shadow_compilingrtlight || !r_shadow_frontsidecasting.integer || !r_shadow_usezpassifpossible.integer)
1230 // check if the shadow volume intersects the near plane
1232 // a ray between the eye and light origin may intersect the caster,
1233 // indicating that the shadow may touch the eye location, however we must
1234 // test the near plane (a polygon), not merely the eye location, so it is
1235 // easiest to enlarge the caster bounding shape slightly for this.
1241 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)
1243 int i, tris, outverts;
1244 if (projectdistance < 0.1)
1246 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
1249 if (!numverts || !nummarktris)
1251 // make sure shadowelements is big enough for this volume
1252 if (maxshadowtriangles < nummarktris*8 || maxshadowvertices < numverts*2)
1253 R_Shadow_ResizeShadowArrays(numverts, nummarktris, 2, 8);
1255 if (maxvertexupdate < numverts)
1257 maxvertexupdate = numverts;
1259 Mem_Free(vertexupdate);
1261 Mem_Free(vertexremap);
1262 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1263 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1264 vertexupdatenum = 0;
1267 if (vertexupdatenum == 0)
1269 vertexupdatenum = 1;
1270 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
1271 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
1274 for (i = 0;i < nummarktris;i++)
1275 shadowmark[marktris[i]] = shadowmarkcount;
1277 if (r_shadow_compilingrtlight)
1279 // if we're compiling an rtlight, capture the mesh
1280 //tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1281 //Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zpass, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1282 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1283 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zfail, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1287 // decide which type of shadow to generate and set stencil mode
1288 R_Shadow_RenderMode_StencilShadowVolumes(R_Shadow_UseZPass(trismins, trismaxs));
1289 // generate the sides or a solid volume, depending on type
1290 if (r_shadow_rendermode >= R_SHADOW_RENDERMODE_ZPASS_STENCIL && r_shadow_rendermode <= R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE)
1291 tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1293 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1294 r_refdef.stats.lights_dynamicshadowtriangles += tris;
1295 r_refdef.stats.lights_shadowtriangles += tris;
1297 R_Mesh_VertexPointer(shadowvertex3f, 0, 0);
1298 GL_LockArrays(0, outverts);
1299 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
1301 // increment stencil if frontface is infront of depthbuffer
1302 GL_CullFace(r_refdef.view.cullface_front);
1303 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1304 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1305 // decrement stencil if backface is infront of depthbuffer
1306 GL_CullFace(r_refdef.view.cullface_back);
1307 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1309 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
1311 // decrement stencil if backface is behind depthbuffer
1312 GL_CullFace(r_refdef.view.cullface_front);
1313 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1314 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1315 // increment stencil if frontface is behind depthbuffer
1316 GL_CullFace(r_refdef.view.cullface_back);
1317 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1319 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1320 GL_LockArrays(0, 0);
1325 int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias)
1327 // p1, p2, p3 are in the cubemap's local coordinate system
1328 // bias = border/(size - border)
1331 float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1332 dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2),
1333 dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3);
1334 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1336 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1337 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1338 | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1339 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1341 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1342 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1343 | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1345 dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1346 dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2),
1347 dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3);
1348 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1350 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1351 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1352 | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1353 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1355 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1356 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1357 | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1359 dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1360 dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2),
1361 dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3);
1362 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1364 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1365 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1366 | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1367 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1369 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1370 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1371 | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1376 int R_Shadow_CalcBBoxSideMask(const vec3_t mins, const vec3_t maxs, const matrix4x4_t *worldtolight, const matrix4x4_t *radiustolight, float bias)
1378 vec3_t center, radius, lightcenter, lightradius, pmin, pmax;
1379 float dp1, dn1, ap1, an1, dp2, dn2, ap2, an2;
1382 VectorSubtract(maxs, mins, radius);
1383 VectorScale(radius, 0.5f, radius);
1384 VectorAdd(mins, radius, center);
1385 Matrix4x4_Transform(worldtolight, center, lightcenter);
1386 Matrix4x4_Transform3x3(radiustolight, radius, lightradius);
1387 VectorSubtract(lightcenter, lightradius, pmin);
1388 VectorAdd(lightcenter, lightradius, pmax);
1390 dp1 = pmax[0] + pmax[1], dn1 = pmax[0] - pmin[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1391 dp2 = pmin[0] + pmin[1], dn2 = pmin[0] - pmax[1], ap2 = fabs(dp2), an2 = fabs(dn2);
1392 if(ap1 > bias*an1 && ap2 > bias*an2)
1394 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1395 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1396 if(an1 > bias*ap1 && an2 > bias*ap2)
1398 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1399 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1401 dp1 = pmax[1] + pmax[2], dn1 = pmax[1] - pmin[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1402 dp2 = pmin[1] + pmin[2], dn2 = pmin[1] - pmax[2], ap2 = fabs(dp2), an2 = fabs(dn2);
1403 if(ap1 > bias*an1 && ap2 > bias*an2)
1405 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1406 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1407 if(an1 > bias*ap1 && an2 > bias*ap2)
1409 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1410 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1412 dp1 = pmax[2] + pmax[0], dn1 = pmax[2] - pmin[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1413 dp2 = pmin[2] + pmin[0], dn2 = pmin[2] - pmax[0], ap2 = fabs(dp2), an2 = fabs(dn2);
1414 if(ap1 > bias*an1 && ap2 > bias*an2)
1416 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1417 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1418 if(an1 > bias*ap1 && an2 > bias*ap2)
1420 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1421 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1426 #define R_Shadow_CalcEntitySideMask(ent, worldtolight, radiustolight, bias) R_Shadow_CalcBBoxSideMask((ent)->mins, (ent)->maxs, worldtolight, radiustolight, bias)
1428 int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
1430 // p is in the cubemap's local coordinate system
1431 // bias = border/(size - border)
1432 float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn);
1433 float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn);
1434 float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn);
1436 if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
1437 if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
1438 if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
1439 if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
1440 if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
1441 if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
1445 int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
1449 int sides = 0x3F, masks[6] = { 3<<4, 3<<4, 3<<0, 3<<0, 3<<2, 3<<2 };
1450 float scale = (size - 2*border)/size, len;
1451 float bias = border / (float)(size - border), dp, dn, ap, an;
1452 // check if cone enclosing side would cross frustum plane
1453 scale = 2 / (scale*scale + 2);
1454 for (i = 0;i < 5;i++)
1456 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) > -0.03125)
1458 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[i].normal, n);
1459 len = scale*VectorLength2(n);
1460 if(n[0]*n[0] > len) sides &= n[0] < 0 ? ~(1<<0) : ~(2 << 0);
1461 if(n[1]*n[1] > len) sides &= n[1] < 0 ? ~(1<<2) : ~(2 << 2);
1462 if(n[2]*n[2] > len) sides &= n[2] < 0 ? ~(1<<4) : ~(2 << 4);
1464 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[4]) >= r_refdef.farclip - r_refdef.nearclip + 0.03125)
1466 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[4].normal, n);
1467 len = scale*VectorLength(n);
1468 if(n[0]*n[0] > len) sides &= n[0] >= 0 ? ~(1<<0) : ~(2 << 0);
1469 if(n[1]*n[1] > len) sides &= n[1] >= 0 ? ~(1<<2) : ~(2 << 2);
1470 if(n[2]*n[2] > len) sides &= n[2] >= 0 ? ~(1<<4) : ~(2 << 4);
1472 // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results
1473 // check if frustum corners/origin cross plane sides
1474 for (i = 0;i < 5;i++)
1476 Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p);
1477 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn),
1478 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1479 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1480 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn),
1481 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1482 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1483 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn),
1484 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1485 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1487 return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5];
1490 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)
1498 int mask, surfacemask = 0;
1499 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1501 bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
1502 tend = firsttriangle + numtris;
1503 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1505 // surface box entirely inside light box, no box cull
1506 if (projectdirection)
1508 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1510 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1511 TriangleNormal(v[0], v[1], v[2], normal);
1512 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1514 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1515 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1516 surfacemask |= mask;
1519 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;
1520 shadowsides[numshadowsides] = mask;
1521 shadowsideslist[numshadowsides++] = t;
1528 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1530 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1531 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]))
1533 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1534 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1535 surfacemask |= mask;
1538 totals[0] += mask&1, totals[1] += (mask>>1)&1, totals[2] += (mask>>2)&1, totals[3] += (mask>>3)&1, totals[4] += (mask>>4)&1, totals[5] += mask>>5;
1539 shadowsides[numshadowsides] = mask;
1540 shadowsideslist[numshadowsides++] = t;
1548 // surface box not entirely inside light box, cull each triangle
1549 if (projectdirection)
1551 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1553 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1554 TriangleNormal(v[0], v[1], v[2], normal);
1555 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1556 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1558 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1559 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1560 surfacemask |= mask;
1563 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;
1564 shadowsides[numshadowsides] = mask;
1565 shadowsideslist[numshadowsides++] = t;
1572 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1574 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1575 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1576 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1578 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1579 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1580 surfacemask |= mask;
1583 totals[0] += mask&1, totals[1] += (mask>>1)&1, totals[2] += (mask>>2)&1, totals[3] += (mask>>3)&1, totals[4] += (mask>>4)&1, totals[5] += mask>>5;
1584 shadowsides[numshadowsides] = mask;
1585 shadowsideslist[numshadowsides++] = t;
1594 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)
1596 int i, j, outtriangles = 0;
1597 int *outelement3i[6];
1598 if (!numverts || !numsidetris || !r_shadow_compilingrtlight)
1600 outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5];
1601 // make sure shadowelements is big enough for this mesh
1602 if (maxshadowtriangles < outtriangles)
1603 R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1);
1605 // compute the offset and size of the separate index lists for each cubemap side
1607 for (i = 0;i < 6;i++)
1609 outelement3i[i] = shadowelements + outtriangles * 3;
1610 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles;
1611 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i];
1612 outtriangles += sidetotals[i];
1615 // gather up the (sparse) triangles into separate index lists for each cubemap side
1616 for (i = 0;i < numsidetris;i++)
1618 const int *element = elements + sidetris[i] * 3;
1619 for (j = 0;j < 6;j++)
1621 if (sides[i] & (1 << j))
1623 outelement3i[j][0] = element[0];
1624 outelement3i[j][1] = element[1];
1625 outelement3i[j][2] = element[2];
1626 outelement3i[j] += 3;
1631 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, outtriangles, shadowelements);
1634 static void R_Shadow_MakeTextures_MakeCorona(void)
1638 unsigned char pixels[32][32][4];
1639 for (y = 0;y < 32;y++)
1641 dy = (y - 15.5f) * (1.0f / 16.0f);
1642 for (x = 0;x < 32;x++)
1644 dx = (x - 15.5f) * (1.0f / 16.0f);
1645 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1646 a = bound(0, a, 255);
1647 pixels[y][x][0] = a;
1648 pixels[y][x][1] = a;
1649 pixels[y][x][2] = a;
1650 pixels[y][x][3] = 255;
1653 r_shadow_lightcorona = R_LoadTexture2D(r_shadow_texturepool, "lightcorona", 32, 32, &pixels[0][0][0], TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_FORCELINEAR, NULL);
1656 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1658 float dist = sqrt(x*x+y*y+z*z);
1659 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1660 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1661 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1664 static void R_Shadow_MakeTextures(void)
1667 float intensity, dist;
1669 R_FreeTexturePool(&r_shadow_texturepool);
1670 r_shadow_texturepool = R_AllocTexturePool();
1671 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1672 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1673 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1674 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1675 for (x = 0;x <= ATTENTABLESIZE;x++)
1677 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1678 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1679 r_shadow_attentable[x] = bound(0, intensity, 1);
1681 // 1D gradient texture
1682 for (x = 0;x < ATTEN1DSIZE;x++)
1683 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1684 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);
1685 // 2D circle texture
1686 for (y = 0;y < ATTEN2DSIZE;y++)
1687 for (x = 0;x < ATTEN2DSIZE;x++)
1688 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);
1689 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);
1690 // 3D sphere texture
1691 if (r_shadow_texture3d.integer && gl_texture3d)
1693 for (z = 0;z < ATTEN3DSIZE;z++)
1694 for (y = 0;y < ATTEN3DSIZE;y++)
1695 for (x = 0;x < ATTEN3DSIZE;x++)
1696 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));
1697 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);
1700 r_shadow_attenuation3dtexture = NULL;
1703 R_Shadow_MakeTextures_MakeCorona();
1705 // Editor light sprites
1706 r_editlights_sprcursor = Draw_CachePic ("gfx/editlights/cursor");
1707 r_editlights_sprlight = Draw_CachePic ("gfx/editlights/light");
1708 r_editlights_sprnoshadowlight = Draw_CachePic ("gfx/editlights/noshadow");
1709 r_editlights_sprcubemaplight = Draw_CachePic ("gfx/editlights/cubemaplight");
1710 r_editlights_sprcubemapnoshadowlight = Draw_CachePic ("gfx/editlights/cubemapnoshadowlight");
1711 r_editlights_sprselection = Draw_CachePic ("gfx/editlights/selection");
1714 void R_Shadow_ValidateCvars(void)
1716 if (r_shadow_texture3d.integer && !gl_texture3d)
1717 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1718 if (gl_ext_separatestencil.integer && !gl_support_separatestencil)
1719 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
1720 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
1721 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1724 void R_Shadow_RenderMode_Begin(void)
1730 R_Shadow_ValidateCvars();
1732 if (!r_shadow_attenuation2dtexture
1733 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1734 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1735 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1736 R_Shadow_MakeTextures();
1739 R_Mesh_ColorPointer(NULL, 0, 0);
1740 R_Mesh_ResetTextureState();
1741 GL_BlendFunc(GL_ONE, GL_ZERO);
1742 GL_DepthRange(0, 1);
1743 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1745 GL_DepthMask(false);
1746 GL_Color(0, 0, 0, 1);
1747 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1749 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1751 if (gl_ext_separatestencil.integer)
1753 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
1754 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
1756 else if (gl_ext_stenciltwoside.integer)
1758 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
1759 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
1763 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
1764 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
1767 if (r_glsl.integer && gl_support_fragment_shader)
1768 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1769 else if (gl_dot3arb && gl_texturecubemap && r_textureunits.integer >= 2 && gl_combine.integer && gl_stencil)
1770 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_DOT3;
1772 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1776 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
1777 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
1778 r_shadow_drawbuffer = drawbuffer;
1779 r_shadow_readbuffer = readbuffer;
1781 r_shadow_cullface_front = r_refdef.view.cullface_front;
1782 r_shadow_cullface_back = r_refdef.view.cullface_back;
1785 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
1787 rsurface.rtlight = rtlight;
1790 void R_Shadow_RenderMode_Reset(void)
1793 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE)
1795 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1797 if (gl_support_ext_framebuffer_object)
1799 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);CHECKGLERROR
1802 qglDrawBuffer(r_shadow_drawbuffer);CHECKGLERROR
1803 qglReadBuffer(r_shadow_readbuffer);CHECKGLERROR
1805 R_SetViewport(&r_refdef.view.viewport);
1806 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
1807 R_Mesh_ColorPointer(NULL, 0, 0);
1808 R_Mesh_ResetTextureState();
1809 GL_DepthRange(0, 1);
1811 GL_DepthMask(false);
1812 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1813 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1814 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
1815 qglStencilMask(~0);CHECKGLERROR
1816 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
1817 qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
1818 r_refdef.view.cullface_front = r_shadow_cullface_front;
1819 r_refdef.view.cullface_back = r_shadow_cullface_back;
1820 GL_CullFace(r_refdef.view.cullface_back);
1821 GL_Color(1, 1, 1, 1);
1822 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
1823 GL_BlendFunc(GL_ONE, GL_ZERO);
1824 R_SetupGenericShader(false);
1825 r_shadow_usingshadowmaprect = false;
1826 r_shadow_usingshadowmapcube = false;
1827 r_shadow_usingshadowmap2d = false;
1831 void R_Shadow_ClearStencil(void)
1834 GL_Clear(GL_STENCIL_BUFFER_BIT);
1835 r_refdef.stats.lights_clears++;
1838 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
1840 r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
1841 if (r_shadow_rendermode == mode)
1844 R_Shadow_RenderMode_Reset();
1845 GL_ColorMask(0, 0, 0, 0);
1846 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1847 R_SetupDepthOrShadowShader();
1848 qglDepthFunc(GL_LESS);CHECKGLERROR
1849 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1850 r_shadow_rendermode = mode;
1855 case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
1856 GL_CullFace(GL_NONE);
1857 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1858 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1860 case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
1861 GL_CullFace(GL_NONE);
1862 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1863 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1865 case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
1866 GL_CullFace(GL_NONE);
1867 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1868 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
1869 qglStencilMask(~0);CHECKGLERROR
1870 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1871 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
1872 qglStencilMask(~0);CHECKGLERROR
1873 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1875 case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
1876 GL_CullFace(GL_NONE);
1877 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1878 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
1879 qglStencilMask(~0);CHECKGLERROR
1880 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1881 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
1882 qglStencilMask(~0);CHECKGLERROR
1883 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1888 static void R_Shadow_MakeVSDCT(void)
1890 // maps to a 2x3 texture rectangle with normalized coordinates
1895 // stores abs(dir.xy), offset.xy/2.5
1896 unsigned char data[4*6] =
1898 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
1899 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
1900 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
1901 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
1902 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
1903 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
1905 r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_ALWAYSPRECACHE | TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, NULL);
1908 void R_Shadow_RenderMode_ShadowMap(int side, qboolean clear, int size)
1913 float nearclip, farclip, bias;
1914 r_viewport_t viewport;
1917 maxsize = r_shadow_shadowmapmaxsize;
1918 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
1920 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
1921 r_shadow_shadowmap_parameters[2] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
1922 r_shadow_shadowmap_parameters[3] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
1923 r_shadow_shadowmapside = side;
1924 r_shadow_shadowmapsize = size;
1925 if (r_shadow_shadowmode == 1)
1927 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
1928 r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
1929 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
1930 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D) goto init_done;
1932 // complex unrolled cube approach (more flexible)
1933 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
1934 R_Shadow_MakeVSDCT();
1935 if (!r_shadow_shadowmap2dtexture)
1938 int w = maxsize*2, h = gl_support_arb_texture_non_power_of_two ? maxsize*3 : maxsize*4;
1939 r_shadow_shadowmap2dtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "shadowmap", w, h, r_shadow_shadowmapprecision, r_shadow_shadowmapsampler);
1940 qglGenFramebuffersEXT(1, &r_shadow_fbo2d);CHECKGLERROR
1941 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbo2d);CHECKGLERROR
1942 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_shadowmap2dtexture), 0);CHECKGLERROR
1943 // render depth into the fbo, do not render color at all
1944 qglDrawBuffer(GL_NONE);CHECKGLERROR
1945 qglReadBuffer(GL_NONE);CHECKGLERROR
1946 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
1947 if (status != GL_FRAMEBUFFER_COMPLETE_EXT && r_shadow_shadowmapping.integer)
1949 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
1950 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
1955 if (r_shadow_shadowmap2dtexture) fbo = r_shadow_fbo2d;
1956 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
1957 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
1958 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
1960 else if (r_shadow_shadowmode == 2)
1962 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
1963 r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
1964 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
1965 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE) goto init_done;
1967 // complex unrolled cube approach (more flexible)
1968 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
1969 R_Shadow_MakeVSDCT();
1970 if (!r_shadow_shadowmaprectangletexture)
1973 r_shadow_shadowmaprectangletexture = R_LoadTextureShadowMapRectangle(r_shadow_texturepool, "shadowmap", maxsize*2, maxsize*3, r_shadow_shadowmapprecision, r_shadow_shadowmapsampler);
1974 qglGenFramebuffersEXT(1, &r_shadow_fborectangle);CHECKGLERROR
1975 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fborectangle);CHECKGLERROR
1976 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, R_GetTexture(r_shadow_shadowmaprectangletexture), 0);CHECKGLERROR
1977 // render depth into the fbo, do not render color at all
1978 qglDrawBuffer(GL_NONE);CHECKGLERROR
1979 qglReadBuffer(GL_NONE);CHECKGLERROR
1980 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
1981 if (status != GL_FRAMEBUFFER_COMPLETE_EXT && r_shadow_shadowmapping.integer)
1983 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
1984 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
1989 if(r_shadow_shadowmaprectangletexture) fbo = r_shadow_fborectangle;
1990 r_shadow_shadowmap_texturescale[0] = 1.0f;
1991 r_shadow_shadowmap_texturescale[1] = 1.0f;
1992 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE;
1994 else if (r_shadow_shadowmode == 3)
1996 r_shadow_shadowmap_parameters[0] = 1.0f;
1997 r_shadow_shadowmap_parameters[1] = 1.0f;
1998 R_Viewport_InitCubeSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, nearclip, farclip, NULL);
1999 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE) goto init_done;
2001 // simple cube approach
2002 if (!r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod])
2005 r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod] = R_LoadTextureShadowMapCube(r_shadow_texturepool, "shadowmapcube", size, r_shadow_shadowmapprecision, r_shadow_shadowmapsampler);
2006 qglGenFramebuffersEXT(6, r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR
2007 for (i = 0;i < 6;i++)
2009 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbocubeside[r_shadow_shadowmaplod][i]);CHECKGLERROR
2010 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + i, R_GetTexture(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]), 0);CHECKGLERROR
2011 // render depth into the fbo, do not render color at all
2012 qglDrawBuffer(GL_NONE);CHECKGLERROR
2013 qglReadBuffer(GL_NONE);CHECKGLERROR
2014 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2015 if (status != GL_FRAMEBUFFER_COMPLETE_EXT && r_shadow_shadowmapping.integer)
2017 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2018 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2024 if (r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]) fbo = r_shadow_fbocubeside[r_shadow_shadowmaplod][side];
2025 r_shadow_shadowmap_texturescale[0] = 0.0f;
2026 r_shadow_shadowmap_texturescale[1] = 0.0f;
2027 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE;
2030 R_Shadow_RenderMode_Reset();
2033 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);CHECKGLERROR
2034 R_SetupDepthOrShadowShader();
2038 R_SetupShowDepthShader();
2039 qglClearColor(1,1,1,1);CHECKGLERROR
2042 GL_PolygonOffset(0, 0);
2049 R_SetViewport(&viewport);
2050 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2051 if(r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE)
2053 int flipped = (side&1)^(side>>2);
2054 r_refdef.view.cullface_front = flipped ? r_shadow_cullface_back : r_shadow_cullface_front;
2055 r_refdef.view.cullface_back = flipped ? r_shadow_cullface_front : r_shadow_cullface_back;
2056 GL_CullFace(r_refdef.view.cullface_back);
2059 qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
2063 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
2066 R_Shadow_RenderMode_Reset();
2067 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2070 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2074 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2075 // only draw light where this geometry was already rendered AND the
2076 // stencil is 128 (values other than this mean shadow)
2077 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
2079 r_shadow_rendermode = r_shadow_lightingrendermode;
2080 // do global setup needed for the chosen lighting mode
2081 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2083 R_Mesh_TexBindCubeMap(GL20TU_CUBE, R_GetTexture(rsurface.rtlight->currentcubemap)); // light filter
2084 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2088 if (r_shadow_shadowmode == 1)
2090 r_shadow_usingshadowmap2d = true;
2091 R_Mesh_TexBind(GL20TU_SHADOWMAP2D, R_GetTexture(r_shadow_shadowmap2dtexture));
2094 else if (r_shadow_shadowmode == 2)
2096 r_shadow_usingshadowmaprect = true;
2097 R_Mesh_TexBindRectangle(GL20TU_SHADOWMAPRECT, R_GetTexture(r_shadow_shadowmaprectangletexture));
2100 else if (r_shadow_shadowmode == 3)
2102 r_shadow_usingshadowmapcube = true;
2103 R_Mesh_TexBindCubeMap(GL20TU_SHADOWMAPCUBE, R_GetTexture(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]));
2107 if (r_shadow_shadowmapvsdct && (r_shadow_usingshadowmap2d || r_shadow_usingshadowmaprect))
2109 R_Mesh_TexBindCubeMap(GL20TU_CUBEPROJECTION, R_GetTexture(r_shadow_shadowmapvsdcttexture));
2114 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_VERTEX)
2115 R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
2116 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2120 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
2123 R_Shadow_RenderMode_Reset();
2124 GL_BlendFunc(GL_ONE, GL_ONE);
2125 GL_DepthRange(0, 1);
2126 GL_DepthTest(r_showshadowvolumes.integer < 2);
2127 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
2128 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2129 GL_CullFace(GL_NONE);
2130 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
2133 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
2136 R_Shadow_RenderMode_Reset();
2137 GL_BlendFunc(GL_ONE, GL_ONE);
2138 GL_DepthRange(0, 1);
2139 GL_DepthTest(r_showlighting.integer < 2);
2140 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2143 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2147 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2148 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
2150 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2153 void R_Shadow_RenderMode_End(void)
2156 R_Shadow_RenderMode_Reset();
2157 R_Shadow_RenderMode_ActiveLight(NULL);
2159 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2160 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2163 int bboxedges[12][2] =
2182 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2184 int i, ix1, iy1, ix2, iy2;
2185 float x1, y1, x2, y2;
2187 float vertex[20][3];
2196 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2197 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2198 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2199 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2201 if (!r_shadow_scissor.integer)
2204 // if view is inside the light box, just say yes it's visible
2205 if (BoxesOverlap(r_refdef.view.origin, r_refdef.view.origin, mins, maxs))
2208 x1 = y1 = x2 = y2 = 0;
2210 // transform all corners that are infront of the nearclip plane
2211 VectorNegate(r_refdef.view.frustum[4].normal, plane4f);
2212 plane4f[3] = r_refdef.view.frustum[4].dist;
2214 for (i = 0;i < 8;i++)
2216 Vector4Set(corner[i], (i & 1) ? maxs[0] : mins[0], (i & 2) ? maxs[1] : mins[1], (i & 4) ? maxs[2] : mins[2], 1);
2217 dist[i] = DotProduct4(corner[i], plane4f);
2218 sign[i] = dist[i] > 0;
2221 VectorCopy(corner[i], vertex[numvertices]);
2225 // if some points are behind the nearclip, add clipped edge points to make
2226 // sure that the scissor boundary is complete
2227 if (numvertices > 0 && numvertices < 8)
2229 // add clipped edge points
2230 for (i = 0;i < 12;i++)
2232 j = bboxedges[i][0];
2233 k = bboxedges[i][1];
2234 if (sign[j] != sign[k])
2236 f = dist[j] / (dist[j] - dist[k]);
2237 VectorLerp(corner[j], f, corner[k], vertex[numvertices]);
2243 // if we have no points to check, the light is behind the view plane
2247 // if we have some points to transform, check what screen area is covered
2248 x1 = y1 = x2 = y2 = 0;
2250 //Con_Printf("%i vertices to transform...\n", numvertices);
2251 for (i = 0;i < numvertices;i++)
2253 VectorCopy(vertex[i], v);
2254 R_Viewport_TransformToScreen(&r_refdef.view.viewport, v, v2);
2255 //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]);
2258 if (x1 > v2[0]) x1 = v2[0];
2259 if (x2 < v2[0]) x2 = v2[0];
2260 if (y1 > v2[1]) y1 = v2[1];
2261 if (y2 < v2[1]) y2 = v2[1];
2270 // now convert the scissor rectangle to integer screen coordinates
2271 ix1 = (int)(x1 - 1.0f);
2272 iy1 = vid.height - (int)(y2 - 1.0f);
2273 ix2 = (int)(x2 + 1.0f);
2274 iy2 = vid.height - (int)(y1 + 1.0f);
2275 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
2277 // clamp it to the screen
2278 if (ix1 < r_refdef.view.viewport.x) ix1 = r_refdef.view.viewport.x;
2279 if (iy1 < r_refdef.view.viewport.y) iy1 = r_refdef.view.viewport.y;
2280 if (ix2 > r_refdef.view.viewport.x + r_refdef.view.viewport.width) ix2 = r_refdef.view.viewport.x + r_refdef.view.viewport.width;
2281 if (iy2 > r_refdef.view.viewport.y + r_refdef.view.viewport.height) iy2 = r_refdef.view.viewport.y + r_refdef.view.viewport.height;
2283 // if it is inside out, it's not visible
2284 if (ix2 <= ix1 || iy2 <= iy1)
2287 // the light area is visible, set up the scissor rectangle
2288 r_shadow_lightscissor[0] = ix1;
2289 r_shadow_lightscissor[1] = iy1;
2290 r_shadow_lightscissor[2] = ix2 - ix1;
2291 r_shadow_lightscissor[3] = iy2 - iy1;
2293 r_refdef.stats.lights_scissored++;
2297 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, int numtriangles, const int *element3i, const float *diffusecolor, const float *ambientcolor)
2299 float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
2300 float *normal3f = rsurface.normal3f + 3 * firstvertex;
2301 float *color4f = rsurface.array_color4f + 4 * firstvertex;
2302 float dist, dot, distintensity, shadeintensity, v[3], n[3];
2303 if (r_textureunits.integer >= 3)
2305 if (VectorLength2(diffusecolor) > 0)
2307 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2309 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2310 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2311 if ((dot = DotProduct(n, v)) < 0)
2313 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2314 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
2317 VectorCopy(ambientcolor, color4f);
2318 if (r_refdef.fogenabled)
2321 f = FogPoint_Model(vertex3f);
2322 VectorScale(color4f, f, color4f);
2329 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2331 VectorCopy(ambientcolor, color4f);
2332 if (r_refdef.fogenabled)
2335 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2336 f = FogPoint_Model(vertex3f);
2337 VectorScale(color4f, f, color4f);
2343 else if (r_textureunits.integer >= 2)
2345 if (VectorLength2(diffusecolor) > 0)
2347 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2349 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2350 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2352 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2353 if ((dot = DotProduct(n, v)) < 0)
2355 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2356 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2357 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2358 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2362 color4f[0] = ambientcolor[0] * distintensity;
2363 color4f[1] = ambientcolor[1] * distintensity;
2364 color4f[2] = ambientcolor[2] * distintensity;
2366 if (r_refdef.fogenabled)
2369 f = FogPoint_Model(vertex3f);
2370 VectorScale(color4f, f, color4f);
2374 VectorClear(color4f);
2380 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2382 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2383 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2385 color4f[0] = ambientcolor[0] * distintensity;
2386 color4f[1] = ambientcolor[1] * distintensity;
2387 color4f[2] = ambientcolor[2] * distintensity;
2388 if (r_refdef.fogenabled)
2391 f = FogPoint_Model(vertex3f);
2392 VectorScale(color4f, f, color4f);
2396 VectorClear(color4f);
2403 if (VectorLength2(diffusecolor) > 0)
2405 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2407 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2408 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2410 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2411 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2412 if ((dot = DotProduct(n, v)) < 0)
2414 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2415 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2416 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2417 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2421 color4f[0] = ambientcolor[0] * distintensity;
2422 color4f[1] = ambientcolor[1] * distintensity;
2423 color4f[2] = ambientcolor[2] * distintensity;
2425 if (r_refdef.fogenabled)
2428 f = FogPoint_Model(vertex3f);
2429 VectorScale(color4f, f, color4f);
2433 VectorClear(color4f);
2439 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2441 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2442 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2444 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2445 color4f[0] = ambientcolor[0] * distintensity;
2446 color4f[1] = ambientcolor[1] * distintensity;
2447 color4f[2] = ambientcolor[2] * distintensity;
2448 if (r_refdef.fogenabled)
2451 f = FogPoint_Model(vertex3f);
2452 VectorScale(color4f, f, color4f);
2456 VectorClear(color4f);
2463 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
2465 static void R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
2468 float *out3f = rsurface.array_texcoord3f + 3 * firstvertex;
2469 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
2470 const float *svector3f = rsurface.svector3f + 3 * firstvertex;
2471 const float *tvector3f = rsurface.tvector3f + 3 * firstvertex;
2472 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
2474 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
2476 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
2477 // the cubemap normalizes this for us
2478 out3f[0] = DotProduct(svector3f, lightdir);
2479 out3f[1] = DotProduct(tvector3f, lightdir);
2480 out3f[2] = DotProduct(normal3f, lightdir);
2484 static void R_Shadow_GenTexCoords_Specular_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
2487 float *out3f = rsurface.array_texcoord3f + 3 * firstvertex;
2488 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
2489 const float *svector3f = rsurface.svector3f + 3 * firstvertex;
2490 const float *tvector3f = rsurface.tvector3f + 3 * firstvertex;
2491 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
2492 float lightdir[3], eyedir[3], halfdir[3];
2493 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
2495 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
2496 VectorNormalize(lightdir);
2497 VectorSubtract(rsurface.modelorg, vertex3f, eyedir);
2498 VectorNormalize(eyedir);
2499 VectorAdd(lightdir, eyedir, halfdir);
2500 // the cubemap normalizes this for us
2501 out3f[0] = DotProduct(svector3f, halfdir);
2502 out3f[1] = DotProduct(tvector3f, halfdir);
2503 out3f[2] = DotProduct(normal3f, halfdir);
2507 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)
2509 // used to display how many times a surface is lit for level design purposes
2510 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2513 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)
2515 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2516 R_SetupSurfaceShader(lightcolorbase, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT);
2517 if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND))
2518 R_Mesh_ColorPointer(rsurface.modellightmapcolor4f, rsurface.modellightmapcolor4f_bufferobject, rsurface.modellightmapcolor4f_bufferoffset);
2520 R_Mesh_ColorPointer(NULL, 0, 0);
2521 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
2522 R_Mesh_TexMatrix(1, &rsurface.texture->currentbackgroundtexmatrix);
2523 R_Mesh_TexBind(GL20TU_NORMAL, R_GetTexture(rsurface.texture->currentskinframe->nmap));
2524 R_Mesh_TexBind(GL20TU_COLOR, R_GetTexture(rsurface.texture->basetexture));
2525 R_Mesh_TexBind(GL20TU_GLOSS, R_GetTexture(rsurface.texture->glosstexture));
2526 if (rsurface.texture->backgroundcurrentskinframe)
2528 R_Mesh_TexBind(GL20TU_SECONDARY_NORMAL, R_GetTexture(rsurface.texture->backgroundcurrentskinframe->nmap));
2529 R_Mesh_TexBind(GL20TU_SECONDARY_COLOR, R_GetTexture(rsurface.texture->backgroundbasetexture));
2530 R_Mesh_TexBind(GL20TU_SECONDARY_GLOSS, R_GetTexture(rsurface.texture->backgroundglosstexture));
2531 R_Mesh_TexBind(GL20TU_SECONDARY_GLOW, R_GetTexture(rsurface.texture->backgroundcurrentskinframe->glow));
2533 //R_Mesh_TexBindCubeMap(GL20TU_CUBE, R_GetTexture(rsurface.rtlight->currentcubemap));
2534 R_Mesh_TexBind(GL20TU_FOGMASK, R_GetTexture(r_texture_fogattenuation));
2535 if(rsurface.texture->colormapping)
2537 R_Mesh_TexBind(GL20TU_PANTS, R_GetTexture(rsurface.texture->currentskinframe->pants));
2538 R_Mesh_TexBind(GL20TU_SHIRT, R_GetTexture(rsurface.texture->currentskinframe->shirt));
2540 R_Mesh_TexBind(GL20TU_ATTENUATION, R_GetTexture(r_shadow_attenuationgradienttexture));
2541 R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
2542 R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset);
2543 R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset);
2544 R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset);
2545 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2547 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2549 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2550 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2552 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
2556 static void R_Shadow_RenderLighting_Light_Dot3_Finalize(int firstvertex, int numvertices, int firsttriangle, int numtriangles, const int *element3i, const unsigned short *element3s, int element3i_bufferobject, int element3s_bufferobject, float r, float g, float b)
2558 // shared final code for all the dot3 layers
2560 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2561 for (renders = 0;renders < 64 && (r > 0 || g > 0 || b > 0);renders++, r--, g--, b--)
2563 GL_Color(bound(0, r, 1), bound(0, g, 1), bound(0, b, 1), 1);
2564 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2568 static void R_Shadow_RenderLighting_Light_Dot3_AmbientPass(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, rtexture_t *basetexture, float colorscale)
2571 // colorscale accounts for how much we multiply the brightness
2574 // mult is how many times the final pass of the lighting will be
2575 // performed to get more brightness than otherwise possible.
2577 // Limit mult to 64 for sanity sake.
2579 if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
2581 // 3 3D combine path (Geforce3, Radeon 8500)
2582 memset(&m, 0, sizeof(m));
2583 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2584 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2585 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2586 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2587 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2588 m.tex[1] = R_GetTexture(basetexture);
2589 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
2590 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
2591 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
2592 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
2593 m.texcubemap[2] = R_GetTexture(rsurface.rtlight->currentcubemap);
2594 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2595 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2596 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2597 m.texmatrix[2] = rsurface.entitytolight;
2598 GL_BlendFunc(GL_ONE, GL_ONE);
2600 else if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
2602 // 2 3D combine path (Geforce3, original Radeon)
2603 memset(&m, 0, sizeof(m));
2604 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2605 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2606 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2607 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2608 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2609 m.tex[1] = R_GetTexture(basetexture);
2610 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
2611 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
2612 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
2613 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
2614 GL_BlendFunc(GL_ONE, GL_ONE);
2616 else if (r_textureunits.integer >= 4 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2618 // 4 2D combine path (Geforce3, Radeon 8500)
2619 memset(&m, 0, sizeof(m));
2620 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2621 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2622 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2623 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2624 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2625 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2626 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2627 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2628 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2629 m.texmatrix[1] = rsurface.entitytoattenuationz;
2630 m.tex[2] = R_GetTexture(basetexture);
2631 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
2632 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
2633 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
2634 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
2635 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2637 m.texcubemap[3] = R_GetTexture(rsurface.rtlight->currentcubemap);
2638 m.pointer_texcoord3f[3] = rsurface.vertex3f;
2639 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
2640 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
2641 m.texmatrix[3] = rsurface.entitytolight;
2643 GL_BlendFunc(GL_ONE, GL_ONE);
2645 else if (r_textureunits.integer >= 3 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
2647 // 3 2D combine path (Geforce3, original Radeon)
2648 memset(&m, 0, sizeof(m));
2649 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2650 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2651 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2652 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2653 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2654 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2655 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2656 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2657 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2658 m.texmatrix[1] = rsurface.entitytoattenuationz;
2659 m.tex[2] = R_GetTexture(basetexture);
2660 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
2661 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
2662 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
2663 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
2664 GL_BlendFunc(GL_ONE, GL_ONE);
2668 // 2/2/2 2D combine path (any dot3 card)
2669 memset(&m, 0, sizeof(m));
2670 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2671 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2672 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2673 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2674 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2675 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2676 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2677 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2678 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2679 m.texmatrix[1] = rsurface.entitytoattenuationz;
2680 R_Mesh_TextureState(&m);
2681 GL_ColorMask(0,0,0,1);
2682 GL_BlendFunc(GL_ONE, GL_ZERO);
2683 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2686 memset(&m, 0, sizeof(m));
2687 m.tex[0] = R_GetTexture(basetexture);
2688 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2689 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2690 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2691 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2692 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2694 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2695 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2696 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2697 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2698 m.texmatrix[1] = rsurface.entitytolight;
2700 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2702 // this final code is shared
2703 R_Mesh_TextureState(&m);
2704 R_Shadow_RenderLighting_Light_Dot3_Finalize(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
2707 static void R_Shadow_RenderLighting_Light_Dot3_DiffusePass(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, rtexture_t *basetexture, rtexture_t *normalmaptexture, float colorscale)
2710 // colorscale accounts for how much we multiply the brightness
2713 // mult is how many times the final pass of the lighting will be
2714 // performed to get more brightness than otherwise possible.
2716 // Limit mult to 64 for sanity sake.
2718 // generate normalization cubemap texcoords
2719 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
2720 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
2722 // 3/2 3D combine path (Geforce3, Radeon 8500)
2723 memset(&m, 0, sizeof(m));
2724 m.tex[0] = R_GetTexture(normalmaptexture);
2725 m.texcombinergb[0] = GL_REPLACE;
2726 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2727 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2728 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2729 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2730 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2731 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2732 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2733 m.pointer_texcoord_bufferobject[1] = 0;
2734 m.pointer_texcoord_bufferoffset[1] = 0;
2735 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
2736 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2737 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2738 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2739 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
2740 R_Mesh_TextureState(&m);
2741 GL_ColorMask(0,0,0,1);
2742 GL_BlendFunc(GL_ONE, GL_ZERO);
2743 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2746 memset(&m, 0, sizeof(m));
2747 m.tex[0] = R_GetTexture(basetexture);
2748 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2749 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2750 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2751 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2752 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2754 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2755 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2756 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2757 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2758 m.texmatrix[1] = rsurface.entitytolight;
2760 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2762 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2764 // 1/2/2 3D combine path (original Radeon)
2765 memset(&m, 0, sizeof(m));
2766 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2767 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2768 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2769 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2770 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2771 R_Mesh_TextureState(&m);
2772 GL_ColorMask(0,0,0,1);
2773 GL_BlendFunc(GL_ONE, GL_ZERO);
2774 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2777 memset(&m, 0, sizeof(m));
2778 m.tex[0] = R_GetTexture(normalmaptexture);
2779 m.texcombinergb[0] = GL_REPLACE;
2780 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2781 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2782 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2783 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2784 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2785 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2786 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2787 m.pointer_texcoord_bufferobject[1] = 0;
2788 m.pointer_texcoord_bufferoffset[1] = 0;
2789 R_Mesh_TextureState(&m);
2790 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2791 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2794 memset(&m, 0, sizeof(m));
2795 m.tex[0] = R_GetTexture(basetexture);
2796 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2797 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2798 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2799 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2800 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2802 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2803 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2804 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2805 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2806 m.texmatrix[1] = rsurface.entitytolight;
2808 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2810 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
2812 // 2/2 3D combine path (original Radeon)
2813 memset(&m, 0, sizeof(m));
2814 m.tex[0] = R_GetTexture(normalmaptexture);
2815 m.texcombinergb[0] = GL_REPLACE;
2816 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2817 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2818 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2819 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2820 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2821 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2822 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2823 m.pointer_texcoord_bufferobject[1] = 0;
2824 m.pointer_texcoord_bufferoffset[1] = 0;
2825 R_Mesh_TextureState(&m);
2826 GL_ColorMask(0,0,0,1);
2827 GL_BlendFunc(GL_ONE, GL_ZERO);
2828 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2831 memset(&m, 0, sizeof(m));
2832 m.tex[0] = R_GetTexture(basetexture);
2833 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2834 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2835 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2836 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2837 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2838 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2839 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2840 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2841 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2842 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2844 else if (r_textureunits.integer >= 4)
2846 // 4/2 2D combine path (Geforce3, Radeon 8500)
2847 memset(&m, 0, sizeof(m));
2848 m.tex[0] = R_GetTexture(normalmaptexture);
2849 m.texcombinergb[0] = GL_REPLACE;
2850 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2851 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2852 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2853 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2854 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2855 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2856 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2857 m.pointer_texcoord_bufferobject[1] = 0;
2858 m.pointer_texcoord_bufferoffset[1] = 0;
2859 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2860 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2861 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2862 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2863 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
2864 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
2865 m.pointer_texcoord3f[3] = rsurface.vertex3f;
2866 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
2867 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
2868 m.texmatrix[3] = rsurface.entitytoattenuationz;
2869 R_Mesh_TextureState(&m);
2870 GL_ColorMask(0,0,0,1);
2871 GL_BlendFunc(GL_ONE, GL_ZERO);
2872 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2875 memset(&m, 0, sizeof(m));
2876 m.tex[0] = R_GetTexture(basetexture);
2877 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2878 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2879 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2880 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2881 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2883 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2884 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2885 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2886 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2887 m.texmatrix[1] = rsurface.entitytolight;
2889 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2893 // 2/2/2 2D combine path (any dot3 card)
2894 memset(&m, 0, sizeof(m));
2895 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2896 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2897 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2898 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2899 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2900 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2901 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2902 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2903 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2904 m.texmatrix[1] = rsurface.entitytoattenuationz;
2905 R_Mesh_TextureState(&m);
2906 GL_ColorMask(0,0,0,1);
2907 GL_BlendFunc(GL_ONE, GL_ZERO);
2908 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2911 memset(&m, 0, sizeof(m));
2912 m.tex[0] = R_GetTexture(normalmaptexture);
2913 m.texcombinergb[0] = GL_REPLACE;
2914 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2915 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2916 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2917 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2918 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2919 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2920 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2921 m.pointer_texcoord_bufferobject[1] = 0;
2922 m.pointer_texcoord_bufferoffset[1] = 0;
2923 R_Mesh_TextureState(&m);
2924 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2925 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2928 memset(&m, 0, sizeof(m));
2929 m.tex[0] = R_GetTexture(basetexture);
2930 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2931 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2932 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2933 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2934 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2936 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2937 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2938 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2939 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2940 m.texmatrix[1] = rsurface.entitytolight;
2942 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2944 // this final code is shared
2945 R_Mesh_TextureState(&m);
2946 R_Shadow_RenderLighting_Light_Dot3_Finalize(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
2949 static void R_Shadow_RenderLighting_Light_Dot3_SpecularPass(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, rtexture_t *glosstexture, rtexture_t *normalmaptexture, float colorscale)
2951 float glossexponent;
2953 // FIXME: detect blendsquare!
2954 //if (!gl_support_blendsquare)
2957 // generate normalization cubemap texcoords
2958 R_Shadow_GenTexCoords_Specular_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
2959 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2961 // 2/0/0/1/2 3D combine blendsquare path
2962 memset(&m, 0, sizeof(m));
2963 m.tex[0] = R_GetTexture(normalmaptexture);
2964 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2965 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2966 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2967 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2968 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2969 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2970 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2971 m.pointer_texcoord_bufferobject[1] = 0;
2972 m.pointer_texcoord_bufferoffset[1] = 0;
2973 R_Mesh_TextureState(&m);
2974 GL_ColorMask(0,0,0,1);
2975 // this squares the result
2976 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2977 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2979 // second and third pass
2980 R_Mesh_ResetTextureState();
2981 // square alpha in framebuffer a few times to make it shiny
2982 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2983 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2984 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2987 memset(&m, 0, sizeof(m));
2988 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2989 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2990 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2991 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2992 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2993 R_Mesh_TextureState(&m);
2994 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2995 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2998 memset(&m, 0, sizeof(m));
2999 m.tex[0] = R_GetTexture(glosstexture);
3000 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3001 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3002 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3003 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3004 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
3006 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
3007 m.pointer_texcoord3f[1] = rsurface.vertex3f;
3008 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
3009 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
3010 m.texmatrix[1] = rsurface.entitytolight;
3012 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
3014 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
3016 // 2/0/0/2 3D combine blendsquare path
3017 memset(&m, 0, sizeof(m));
3018 m.tex[0] = R_GetTexture(normalmaptexture);
3019 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3020 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3021 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3022 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3023 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
3024 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
3025 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
3026 m.pointer_texcoord_bufferobject[1] = 0;
3027 m.pointer_texcoord_bufferoffset[1] = 0;
3028 R_Mesh_TextureState(&m);
3029 GL_ColorMask(0,0,0,1);
3030 // this squares the result
3031 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
3032 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3034 // second and third pass
3035 R_Mesh_ResetTextureState();
3036 // square alpha in framebuffer a few times to make it shiny
3037 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
3038 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
3039 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3042 memset(&m, 0, sizeof(m));
3043 m.tex[0] = R_GetTexture(glosstexture);
3044 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3045 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3046 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3047 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3048 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
3049 m.pointer_texcoord3f[1] = rsurface.vertex3f;
3050 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
3051 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
3052 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
3053 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
3057 // 2/0/0/2/2 2D combine blendsquare path
3058 memset(&m, 0, sizeof(m));
3059 m.tex[0] = R_GetTexture(normalmaptexture);
3060 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3061 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3062 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3063 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3064 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
3065 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
3066 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
3067 m.pointer_texcoord_bufferobject[1] = 0;
3068 m.pointer_texcoord_bufferoffset[1] = 0;
3069 R_Mesh_TextureState(&m);
3070 GL_ColorMask(0,0,0,1);
3071 // this squares the result
3072 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
3073 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3075 // second and third pass
3076 R_Mesh_ResetTextureState();
3077 // square alpha in framebuffer a few times to make it shiny
3078 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
3079 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
3080 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3083 memset(&m, 0, sizeof(m));
3084 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
3085 m.pointer_texcoord3f[0] = rsurface.vertex3f;
3086 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
3087 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
3088 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
3089 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
3090 m.pointer_texcoord3f[1] = rsurface.vertex3f;
3091 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
3092 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
3093 m.texmatrix[1] = rsurface.entitytoattenuationz;
3094 R_Mesh_TextureState(&m);
3095 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
3096 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3099 memset(&m, 0, sizeof(m));
3100 m.tex[0] = R_GetTexture(glosstexture);
3101 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3102 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3103 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3104 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3105 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
3107 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
3108 m.pointer_texcoord3f[1] = rsurface.vertex3f;
3109 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
3110 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
3111 m.texmatrix[1] = rsurface.entitytolight;
3113 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
3115 // this final code is shared
3116 R_Mesh_TextureState(&m);
3117 R_Shadow_RenderLighting_Light_Dot3_Finalize(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase[0] * colorscale, lightcolorbase[1] * colorscale, lightcolorbase[2] * colorscale);
3120 static void R_Shadow_RenderLighting_Light_Dot3(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)
3122 // ARB path (any Geforce, any Radeon)
3123 qboolean doambient = ambientscale > 0;
3124 qboolean dodiffuse = diffusescale > 0;
3125 qboolean dospecular = specularscale > 0;
3126 if (!doambient && !dodiffuse && !dospecular)
3128 R_Mesh_ColorPointer(NULL, 0, 0);
3130 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, basetexture, ambientscale * r_refdef.view.colorscale);
3132 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, basetexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
3136 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorpants, pantstexture, ambientscale * r_refdef.view.colorscale);
3138 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorpants, pantstexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
3143 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorshirt, shirttexture, ambientscale * r_refdef.view.colorscale);
3145 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorshirt, shirttexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
3148 R_Shadow_RenderLighting_Light_Dot3_SpecularPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, glosstexture, normalmaptexture, specularscale * r_refdef.view.colorscale);
3151 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
3158 int newnumtriangles;
3162 int maxtriangles = 4096;
3163 int newelements[4096*3];
3164 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, numtriangles, element3i, diffusecolor2, ambientcolor2);
3165 for (renders = 0;renders < 64;renders++)
3170 newnumtriangles = 0;
3172 // due to low fillrate on the cards this vertex lighting path is
3173 // designed for, we manually cull all triangles that do not
3174 // contain a lit vertex
3175 // this builds batches of triangles from multiple surfaces and
3176 // renders them at once
3177 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
3179 if (VectorLength2(rsurface.array_color4f + e[0] * 4) + VectorLength2(rsurface.array_color4f + e[1] * 4) + VectorLength2(rsurface.array_color4f + e[2] * 4) >= 0.01)
3181 if (newnumtriangles)
3183 newfirstvertex = min(newfirstvertex, e[0]);
3184 newlastvertex = max(newlastvertex, e[0]);
3188 newfirstvertex = e[0];
3189 newlastvertex = e[0];
3191 newfirstvertex = min(newfirstvertex, e[1]);
3192 newlastvertex = max(newlastvertex, e[1]);
3193 newfirstvertex = min(newfirstvertex, e[2]);
3194 newlastvertex = max(newlastvertex, e[2]);
3200 if (newnumtriangles >= maxtriangles)
3202 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
3203 newnumtriangles = 0;
3209 if (newnumtriangles >= 1)
3211 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
3214 // if we couldn't find any lit triangles, exit early
3217 // now reduce the intensity for the next overbright pass
3218 // we have to clamp to 0 here incase the drivers have improper
3219 // handling of negative colors
3220 // (some old drivers even have improper handling of >1 color)
3222 for (i = 0, c = rsurface.array_color4f + 4 * firstvertex;i < numvertices;i++, c += 4)
3224 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
3226 c[0] = max(0, c[0] - 1);
3227 c[1] = max(0, c[1] - 1);
3228 c[2] = max(0, c[2] - 1);
3240 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)
3242 // OpenGL 1.1 path (anything)
3243 float ambientcolorbase[3], diffusecolorbase[3];
3244 float ambientcolorpants[3], diffusecolorpants[3];
3245 float ambientcolorshirt[3], diffusecolorshirt[3];
3247 VectorScale(lightcolorbase, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorbase);
3248 VectorScale(lightcolorbase, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorbase);
3249 VectorScale(lightcolorpants, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorpants);
3250 VectorScale(lightcolorpants, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorpants);
3251 VectorScale(lightcolorshirt, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorshirt);
3252 VectorScale(lightcolorshirt, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorshirt);
3253 memset(&m, 0, sizeof(m));
3254 m.tex[0] = R_GetTexture(basetexture);
3255 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3256 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3257 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3258 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3259 if (r_textureunits.integer >= 2)
3262 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
3263 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
3264 m.pointer_texcoord3f[1] = rsurface.vertex3f;
3265 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
3266 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
3267 if (r_textureunits.integer >= 3)
3269 // Voodoo4 or Kyro (or Geforce3/Radeon with gl_combine off)
3270 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
3271 m.texmatrix[2] = rsurface.entitytoattenuationz;
3272 m.pointer_texcoord3f[2] = rsurface.vertex3f;
3273 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
3274 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
3277 R_Mesh_TextureState(&m);
3278 //R_Mesh_TexBind(0, R_GetTexture(basetexture));
3279 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorbase, ambientcolorbase);
3282 R_Mesh_TexBind(0, R_GetTexture(pantstexture));
3283 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorpants, ambientcolorpants);
3287 R_Mesh_TexBind(0, R_GetTexture(shirttexture));
3288 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorshirt, ambientcolorshirt);
3292 extern cvar_t gl_lightmaps;
3293 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)
3295 float ambientscale, diffusescale, specularscale;
3296 vec3_t lightcolorbase, lightcolorpants, lightcolorshirt;
3298 // calculate colors to render this texture with
3299 lightcolorbase[0] = rsurface.rtlight->currentcolor[0] * rsurface.texture->dlightcolor[0];
3300 lightcolorbase[1] = rsurface.rtlight->currentcolor[1] * rsurface.texture->dlightcolor[1];
3301 lightcolorbase[2] = rsurface.rtlight->currentcolor[2] * rsurface.texture->dlightcolor[2];
3302 ambientscale = rsurface.rtlight->ambientscale;
3303 diffusescale = rsurface.rtlight->diffusescale;
3304 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
3305 if (!r_shadow_usenormalmap.integer)
3307 ambientscale += 1.0f * diffusescale;
3311 if ((ambientscale + diffusescale) * VectorLength2(lightcolorbase) + specularscale * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
3313 RSurf_SetupDepthAndCulling();
3314 nmap = rsurface.texture->currentskinframe->nmap;
3315 if (gl_lightmaps.integer)
3316 nmap = r_texture_blanknormalmap;
3317 if (rsurface.texture->colormapping && !gl_lightmaps.integer)
3319 qboolean dopants = rsurface.texture->currentskinframe->pants != NULL && VectorLength2(rsurface.colormap_pantscolor) >= (1.0f / 1048576.0f);
3320 qboolean doshirt = rsurface.texture->currentskinframe->shirt != NULL && VectorLength2(rsurface.colormap_shirtcolor) >= (1.0f / 1048576.0f);
3323 lightcolorpants[0] = lightcolorbase[0] * rsurface.colormap_pantscolor[0];
3324 lightcolorpants[1] = lightcolorbase[1] * rsurface.colormap_pantscolor[1];
3325 lightcolorpants[2] = lightcolorbase[2] * rsurface.colormap_pantscolor[2];
3328 VectorClear(lightcolorpants);
3331 lightcolorshirt[0] = lightcolorbase[0] * rsurface.colormap_shirtcolor[0];
3332 lightcolorshirt[1] = lightcolorbase[1] * rsurface.colormap_shirtcolor[1];
3333 lightcolorshirt[2] = lightcolorbase[2] * rsurface.colormap_shirtcolor[2];
3336 VectorClear(lightcolorshirt);
3337 switch (r_shadow_rendermode)
3339 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
3340 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
3341 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);
3343 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
3344 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);
3346 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
3347 R_Shadow_RenderLighting_Light_Dot3(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);
3349 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3350 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);
3353 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
3359 switch (r_shadow_rendermode)
3361 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
3362 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
3363 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);
3365 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
3366 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);
3368 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
3369 R_Shadow_RenderLighting_Light_Dot3(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);
3371 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3372 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);
3375 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
3381 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)
3383 matrix4x4_t tempmatrix = *matrix;
3384 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
3386 // if this light has been compiled before, free the associated data
3387 R_RTLight_Uncompile(rtlight);
3389 // clear it completely to avoid any lingering data
3390 memset(rtlight, 0, sizeof(*rtlight));
3392 // copy the properties
3393 rtlight->matrix_lighttoworld = tempmatrix;
3394 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
3395 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
3396 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
3397 VectorCopy(color, rtlight->color);
3398 rtlight->cubemapname[0] = 0;
3399 if (cubemapname && cubemapname[0])
3400 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
3401 rtlight->shadow = shadow;
3402 rtlight->corona = corona;
3403 rtlight->style = style;
3404 rtlight->isstatic = isstatic;
3405 rtlight->coronasizescale = coronasizescale;
3406 rtlight->ambientscale = ambientscale;
3407 rtlight->diffusescale = diffusescale;
3408 rtlight->specularscale = specularscale;
3409 rtlight->flags = flags;
3411 // compute derived data
3412 //rtlight->cullradius = rtlight->radius;
3413 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
3414 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3415 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3416 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3417 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3418 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3419 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3422 // compiles rtlight geometry
3423 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
3424 void R_RTLight_Compile(rtlight_t *rtlight)
3427 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
3428 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
3429 entity_render_t *ent = r_refdef.scene.worldentity;
3430 dp_model_t *model = r_refdef.scene.worldmodel;
3431 unsigned char *data;
3434 // compile the light
3435 rtlight->compiled = true;
3436 rtlight->shadowmode = rtlight->shadow ? r_shadow_shadowmode : -1;
3437 rtlight->static_numleafs = 0;
3438 rtlight->static_numleafpvsbytes = 0;
3439 rtlight->static_leaflist = NULL;
3440 rtlight->static_leafpvs = NULL;
3441 rtlight->static_numsurfaces = 0;
3442 rtlight->static_surfacelist = NULL;
3443 rtlight->static_shadowmap_receivers = 0x3F;
3444 rtlight->static_shadowmap_casters = 0x3F;
3445 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3446 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3447 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3448 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3449 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3450 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3452 if (model && model->GetLightInfo)
3454 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
3455 r_shadow_compilingrtlight = rtlight;
3456 R_Shadow_EnlargeLeafSurfaceTrisBuffer(model->brush.num_leafs, model->num_surfaces, model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles, model->surfmesh.num_triangles);
3457 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);
3458 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
3459 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
3460 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3461 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
3462 rtlight->static_numsurfaces = numsurfaces;
3463 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
3464 rtlight->static_numleafs = numleafs;
3465 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
3466 rtlight->static_numleafpvsbytes = numleafpvsbytes;
3467 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
3468 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
3469 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
3470 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
3471 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3472 if (rtlight->static_numsurfaces)
3473 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3474 if (rtlight->static_numleafs)
3475 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3476 if (rtlight->static_numleafpvsbytes)
3477 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3478 if (rtlight->static_numshadowtrispvsbytes)
3479 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3480 if (rtlight->static_numlighttrispvsbytes)
3481 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3482 if (rtlight->shadowmode <= 0)
3484 if (model->CompileShadowVolume && rtlight->shadow)
3485 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3489 if (model->CompileShadowMap && rtlight->shadow)
3490 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3492 // now we're done compiling the rtlight
3493 r_shadow_compilingrtlight = NULL;
3497 // use smallest available cullradius - box radius or light radius
3498 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3499 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3501 shadowzpasstris = 0;
3502 if (rtlight->static_meshchain_shadow_zpass)
3503 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
3504 shadowzpasstris += mesh->numtriangles;
3506 shadowzfailtris = 0;
3507 if (rtlight->static_meshchain_shadow_zfail)
3508 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
3509 shadowzfailtris += mesh->numtriangles;
3512 if (rtlight->static_numlighttrispvsbytes)
3513 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3514 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3518 if (rtlight->static_numlighttrispvsbytes)
3519 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3520 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3523 if (developer.integer >= 10)
3524 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);
3527 void R_RTLight_Uncompile(rtlight_t *rtlight)
3529 if (rtlight->compiled)
3531 if (rtlight->static_meshchain_shadow_zpass)
3532 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
3533 rtlight->static_meshchain_shadow_zpass = NULL;
3534 if (rtlight->static_meshchain_shadow_zfail)
3535 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
3536 rtlight->static_meshchain_shadow_zfail = NULL;
3537 if (rtlight->static_meshchain_shadow_shadowmap)
3538 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
3539 rtlight->static_meshchain_shadow_shadowmap = NULL;
3540 // these allocations are grouped
3541 if (rtlight->static_surfacelist)
3542 Mem_Free(rtlight->static_surfacelist);
3543 rtlight->static_numleafs = 0;
3544 rtlight->static_numleafpvsbytes = 0;
3545 rtlight->static_leaflist = NULL;
3546 rtlight->static_leafpvs = NULL;
3547 rtlight->static_numsurfaces = 0;
3548 rtlight->static_surfacelist = NULL;
3549 rtlight->static_numshadowtrispvsbytes = 0;
3550 rtlight->static_shadowtrispvs = NULL;
3551 rtlight->static_numlighttrispvsbytes = 0;
3552 rtlight->static_lighttrispvs = NULL;
3553 rtlight->compiled = false;
3557 void R_Shadow_UncompileWorldLights(void)
3561 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3562 for (lightindex = 0;lightindex < range;lightindex++)
3564 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3567 R_RTLight_Uncompile(&light->rtlight);
3571 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3575 // reset the count of frustum planes
3576 // see rsurface.rtlight_frustumplanes definition for how much this array
3578 rsurface.rtlight_numfrustumplanes = 0;
3580 // haven't implemented a culling path for ortho rendering
3581 if (!r_refdef.view.useperspective)
3583 // check if the light is on screen and copy the 4 planes if it is
3584 for (i = 0;i < 4;i++)
3585 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3588 for (i = 0;i < 4;i++)
3589 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_refdef.view.frustum[i];
3594 // generate a deformed frustum that includes the light origin, this is
3595 // used to cull shadow casting surfaces that can not possibly cast a
3596 // shadow onto the visible light-receiving surfaces, which can be a
3599 // if the light origin is onscreen the result will be 4 planes exactly
3600 // if the light origin is offscreen on only one axis the result will
3601 // be exactly 5 planes (split-side case)
3602 // if the light origin is offscreen on two axes the result will be
3603 // exactly 4 planes (stretched corner case)
3604 for (i = 0;i < 4;i++)
3606 // quickly reject standard frustum planes that put the light
3607 // origin outside the frustum
3608 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3611 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_refdef.view.frustum[i];
3613 // if all the standard frustum planes were accepted, the light is onscreen
3614 // otherwise we need to generate some more planes below...
3615 if (rsurface.rtlight_numfrustumplanes < 4)
3617 // at least one of the stock frustum planes failed, so we need to
3618 // create one or two custom planes to enclose the light origin
3619 for (i = 0;i < 4;i++)
3621 // create a plane using the view origin and light origin, and a
3622 // single point from the frustum corner set
3623 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3624 VectorNormalize(plane.normal);
3625 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3626 // see if this plane is backwards and flip it if so
3627 for (j = 0;j < 4;j++)
3628 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3632 VectorNegate(plane.normal, plane.normal);
3634 // flipped plane, test again to see if it is now valid
3635 for (j = 0;j < 4;j++)
3636 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3638 // if the plane is still not valid, then it is dividing the
3639 // frustum and has to be rejected
3643 // we have created a valid plane, compute extra info
3644 PlaneClassify(&plane);
3646 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3648 // if we've found 5 frustum planes then we have constructed a
3649 // proper split-side case and do not need to keep searching for
3650 // planes to enclose the light origin
3651 if (rsurface.rtlight_numfrustumplanes == 5)
3659 for (i = 0;i < rsurface.rtlight_numfrustumplanes;i++)
3661 plane = rsurface.rtlight_frustumplanes[i];
3662 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));
3667 // now add the light-space box planes if the light box is rotated, as any
3668 // caster outside the oriented light box is irrelevant (even if it passed
3669 // the worldspace light box, which is axial)
3670 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3672 for (i = 0;i < 6;i++)
3676 v[i >> 1] = (i & 1) ? -1 : 1;
3677 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3678 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3679 plane.dist = VectorNormalizeLength(plane.normal);
3680 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3681 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3687 // add the world-space reduced box planes
3688 for (i = 0;i < 6;i++)
3690 VectorClear(plane.normal);
3691 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3692 plane.dist = (i & 1) ? -rsurface.rtlight_cullmaxs[i >> 1] : rsurface.rtlight_cullmins[i >> 1];
3693 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3702 // reduce all plane distances to tightly fit the rtlight cull box, which
3704 VectorSet(points[0], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
3705 VectorSet(points[1], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
3706 VectorSet(points[2], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
3707 VectorSet(points[3], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
3708 VectorSet(points[4], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
3709 VectorSet(points[5], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
3710 VectorSet(points[6], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
3711 VectorSet(points[7], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
3712 oldnum = rsurface.rtlight_numfrustumplanes;
3713 rsurface.rtlight_numfrustumplanes = 0;
3714 for (j = 0;j < oldnum;j++)
3716 // find the nearest point on the box to this plane
3717 bestdist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[0]);
3718 for (i = 1;i < 8;i++)
3720 dist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[i]);
3721 if (bestdist > dist)
3724 Con_Printf("light %p %splane #%i %f %f %f : %f < %f\n", rtlight, rsurface.rtlight_frustumplanes[j].dist < bestdist + 0.03125 ? "^2" : "^1", j, rsurface.rtlight_frustumplanes[j].normal[0], rsurface.rtlight_frustumplanes[j].normal[1], rsurface.rtlight_frustumplanes[j].normal[2], rsurface.rtlight_frustumplanes[j].dist, bestdist);
3725 // if the nearest point is near or behind the plane, we want this
3726 // plane, otherwise the plane is useless as it won't cull anything
3727 if (rsurface.rtlight_frustumplanes[j].dist < bestdist + 0.03125)
3729 PlaneClassify(&rsurface.rtlight_frustumplanes[j]);
3730 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = rsurface.rtlight_frustumplanes[j];
3737 void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
3741 RSurf_ActiveWorldEntity();
3743 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3746 GL_CullFace(GL_NONE);
3747 mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3748 for (;mesh;mesh = mesh->next)
3750 if (!mesh->sidetotals[r_shadow_shadowmapside])
3752 r_refdef.stats.lights_shadowtriangles += mesh->sidetotals[r_shadow_shadowmapside];
3753 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
3754 R_Mesh_Draw(0, mesh->numverts, mesh->sideoffsets[r_shadow_shadowmapside], mesh->sidetotals[r_shadow_shadowmapside], mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3758 else if (r_refdef.scene.worldentity->model)
3759 r_refdef.scene.worldmodel->DrawShadowMap(r_shadow_shadowmapside, r_refdef.scene.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, surfacesides, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs);
3761 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3764 void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3769 int surfacelistindex;
3770 msurface_t *surface;
3772 RSurf_ActiveWorldEntity();
3774 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3777 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
3778 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
3779 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
3780 for (;mesh;mesh = mesh->next)
3782 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
3783 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
3784 GL_LockArrays(0, mesh->numverts);
3785 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
3787 // increment stencil if frontface is infront of depthbuffer
3788 GL_CullFace(r_refdef.view.cullface_back);
3789 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
3790 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3791 // decrement stencil if backface is infront of depthbuffer
3792 GL_CullFace(r_refdef.view.cullface_front);
3793 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
3795 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
3797 // decrement stencil if backface is behind depthbuffer
3798 GL_CullFace(r_refdef.view.cullface_front);
3799 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
3800 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3801 // increment stencil if frontface is behind depthbuffer
3802 GL_CullFace(r_refdef.view.cullface_back);
3803 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
3805 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3806 GL_LockArrays(0, 0);
3810 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh && r_shadow_culltriangles.integer)
3812 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
3813 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
3815 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
3816 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
3817 if (CHECKPVSBIT(trispvs, t))
3818 shadowmarklist[numshadowmark++] = t;
3820 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);
3822 else if (numsurfaces)
3823 r_refdef.scene.worldmodel->DrawShadowVolume(r_refdef.scene.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs);
3825 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3828 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3830 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3831 vec_t relativeshadowradius;
3832 RSurf_ActiveModelEntity(ent, false, false);
3833 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3834 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3835 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3836 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3837 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3838 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3839 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3840 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3841 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D)
3843 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
3846 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3847 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3850 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3852 // set up properties for rendering light onto this entity
3853 RSurf_ActiveModelEntity(ent, true, true);
3854 GL_AlphaTest(false);
3855 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3856 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3857 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3858 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3859 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
3860 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
3863 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3865 if (!r_refdef.scene.worldmodel->DrawLight)
3868 // set up properties for rendering light onto this entity
3869 RSurf_ActiveWorldEntity();
3870 GL_AlphaTest(false);
3871 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3872 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3873 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3874 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3875 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
3876 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
3878 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, trispvs);
3880 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3883 void R_Shadow_DrawEntityLight(entity_render_t *ent)
3885 dp_model_t *model = ent->model;
3886 if (!model->DrawLight)
3889 R_Shadow_SetupEntityLight(ent);
3891 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3893 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3896 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
3900 int numleafs, numsurfaces;
3901 int *leaflist, *surfacelist;
3902 unsigned char *leafpvs, *shadowtrispvs, *lighttrispvs, *surfacesides;
3903 int numlightentities;
3904 int numlightentities_noselfshadow;
3905 int numshadowentities;
3906 int numshadowentities_noselfshadow;
3907 static entity_render_t *lightentities[MAX_EDICTS];
3908 static entity_render_t *shadowentities[MAX_EDICTS];
3909 static unsigned char entitysides[MAX_EDICTS];
3910 int lightentities_noselfshadow;
3911 int shadowentities_noselfshadow;
3912 vec3_t nearestpoint;
3914 qboolean castshadows;
3917 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3918 // skip lights that are basically invisible (color 0 0 0)
3919 if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
3922 // loading is done before visibility checks because loading should happen
3923 // all at once at the start of a level, not when it stalls gameplay.
3924 // (especially important to benchmarks)
3926 if (rtlight->isstatic && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
3928 if (rtlight->compiled)
3929 R_RTLight_Uncompile(rtlight);
3930 R_RTLight_Compile(rtlight);
3934 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
3936 // look up the light style value at this time
3937 f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3938 VectorScale(rtlight->color, f, rtlight->currentcolor);
3940 if (rtlight->selected)
3942 f = 2 + sin(realtime * M_PI * 4.0);
3943 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3947 // if lightstyle is currently off, don't draw the light
3948 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3951 // if the light box is offscreen, skip it
3952 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3955 VectorCopy(rtlight->cullmins, rsurface.rtlight_cullmins);
3956 VectorCopy(rtlight->cullmaxs, rsurface.rtlight_cullmaxs);
3958 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3960 // compiled light, world available and can receive realtime lighting
3961 // retrieve leaf information
3962 numleafs = rtlight->static_numleafs;
3963 leaflist = rtlight->static_leaflist;
3964 leafpvs = rtlight->static_leafpvs;
3965 numsurfaces = rtlight->static_numsurfaces;
3966 surfacelist = rtlight->static_surfacelist;
3967 surfacesides = NULL;
3968 shadowtrispvs = rtlight->static_shadowtrispvs;
3969 lighttrispvs = rtlight->static_lighttrispvs;
3971 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3973 // dynamic light, world available and can receive realtime lighting
3974 // calculate lit surfaces and leafs
3975 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);
3976 r_refdef.scene.worldmodel->GetLightInfo(r_refdef.scene.worldentity, rtlight->shadoworigin, rtlight->radius, rsurface.rtlight_cullmins, rsurface.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);
3977 leaflist = r_shadow_buffer_leaflist;
3978 leafpvs = r_shadow_buffer_leafpvs;
3979 surfacelist = r_shadow_buffer_surfacelist;
3980 surfacesides = r_shadow_buffer_surfacesides;
3981 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3982 lighttrispvs = r_shadow_buffer_lighttrispvs;
3983 // if the reduced leaf bounds are offscreen, skip it
3984 if (R_CullBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
3995 surfacesides = NULL;
3996 shadowtrispvs = NULL;
3997 lighttrispvs = NULL;
3999 // check if light is illuminating any visible leafs
4002 for (i = 0;i < numleafs;i++)
4003 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
4008 // set up a scissor rectangle for this light
4009 if (R_Shadow_ScissorForBBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
4012 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
4014 // make a list of lit entities and shadow casting entities
4015 numlightentities = 0;
4016 numlightentities_noselfshadow = 0;
4017 lightentities_noselfshadow = sizeof(lightentities)/sizeof(lightentities[0]) - 1;
4018 numshadowentities = 0;
4019 numshadowentities_noselfshadow = 0;
4020 shadowentities_noselfshadow = sizeof(shadowentities)/sizeof(shadowentities[0]) - 1;
4022 // add dynamic entities that are lit by the light
4023 if (r_drawentities.integer)
4025 for (i = 0;i < r_refdef.scene.numentities;i++)
4028 entity_render_t *ent = r_refdef.scene.entities[i];
4030 if (!BoxesOverlap(ent->mins, ent->maxs, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
4032 // skip the object entirely if it is not within the valid
4033 // shadow-casting region (which includes the lit region)
4034 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rsurface.rtlight_numfrustumplanes, rsurface.rtlight_frustumplanes))
4036 if (!(model = ent->model))
4038 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
4040 // this entity wants to receive light, is visible, and is
4041 // inside the light box
4042 // TODO: check if the surfaces in the model can receive light
4043 // so now check if it's in a leaf seen by the light
4044 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))
4046 if (ent->flags & RENDER_NOSELFSHADOW)
4047 lightentities[lightentities_noselfshadow - numlightentities_noselfshadow++] = ent;
4049 lightentities[numlightentities++] = ent;
4050 // since it is lit, it probably also casts a shadow...
4051 // about the VectorDistance2 - light emitting entities should not cast their own shadow
4052 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
4053 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
4055 // note: exterior models without the RENDER_NOSELFSHADOW
4056 // flag still create a RENDER_NOSELFSHADOW shadow but
4057 // are lit normally, this means that they are
4058 // self-shadowing but do not shadow other
4059 // RENDER_NOSELFSHADOW entities such as the gun
4060 // (very weird, but keeps the player shadow off the gun)
4061 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
4062 shadowentities[shadowentities_noselfshadow - numshadowentities_noselfshadow++] = ent;
4064 shadowentities[numshadowentities++] = ent;
4067 else if (ent->flags & RENDER_SHADOW)
4069 // this entity is not receiving light, but may still need to
4071 // TODO: check if the surfaces in the model can cast shadow
4072 // now check if it is in a leaf seen by the light
4073 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))
4075 // about the VectorDistance2 - light emitting entities should not cast their own shadow
4076 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
4077 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
4079 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
4080 shadowentities[shadowentities_noselfshadow - numshadowentities_noselfshadow++] = ent;
4082 shadowentities[numshadowentities++] = ent;
4088 // return if there's nothing at all to light
4089 if (!numlightentities && !numsurfaces)
4092 // don't let sound skip if going slow
4093 if (r_refdef.scene.extraupdate)
4096 // make this the active rtlight for rendering purposes
4097 R_Shadow_RenderMode_ActiveLight(rtlight);
4098 // count this light in the r_speeds
4099 r_refdef.stats.lights++;
4101 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
4103 // optionally draw visible shape of the shadow volumes
4104 // for performance analysis by level designers
4105 R_Shadow_RenderMode_VisibleShadowVolumes();
4107 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
4108 for (i = 0;i < numshadowentities;i++)
4109 R_Shadow_DrawEntityShadow(shadowentities[i]);
4110 for (i = 0;i < numshadowentities_noselfshadow;i++)
4111 R_Shadow_DrawEntityShadow(shadowentities[shadowentities_noselfshadow - i]);
4114 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
4116 // optionally draw the illuminated areas
4117 // for performance analysis by level designers
4118 R_Shadow_RenderMode_VisibleLighting(false, false);
4120 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4121 for (i = 0;i < numlightentities;i++)
4122 R_Shadow_DrawEntityLight(lightentities[i]);
4123 for (i = 0;i < numlightentities_noselfshadow;i++)
4124 R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
4127 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
4129 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
4130 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
4131 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
4132 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
4133 lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
4134 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapping_maxsize.integer);
4136 if (castshadows && r_shadow_shadowmode >= 1 && r_shadow_shadowmode <= 3 && r_glsl.integer && gl_support_fragment_shader)
4142 int receivermask = 0;
4143 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
4144 Matrix4x4_Abs(&radiustolight);
4146 r_shadow_shadowmaplod = 0;
4147 for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
4148 if ((r_shadow_shadowmapping_maxsize.integer >> i) > lodlinear)
4149 r_shadow_shadowmaplod = i;
4151 size = r_shadow_shadowmode == 3 ? r_shadow_shadowmapping_maxsize.integer >> r_shadow_shadowmaplod : lodlinear;
4152 size = bound(1, size, 2048);
4153 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
4157 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
4159 castermask = rtlight->static_shadowmap_casters;
4160 receivermask = rtlight->static_shadowmap_receivers;
4164 for(i = 0;i < numsurfaces;i++)
4166 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
4167 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4168 castermask |= surfacesides[i];
4169 receivermask |= surfacesides[i];
4173 if (receivermask < 0x3F)
4175 for (i = 0;i < numlightentities;i++)
4176 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4177 if (receivermask < 0x3F)
4178 for(i = 0; i < numlightentities_noselfshadow;i++)
4179 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[lightentities_noselfshadow - i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4182 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
4186 for (i = 0;i < numshadowentities;i++)
4187 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
4188 for (i = 0;i < numshadowentities_noselfshadow;i++)
4189 castermask |= (entitysides[shadowentities_noselfshadow - i] = R_Shadow_CalcEntitySideMask(shadowentities[shadowentities_noselfshadow - i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
4192 //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
4194 // render shadow casters into 6 sided depth texture
4195 for (side = 0;side < 6;side++) if (receivermask & (1 << side))
4197 R_Shadow_RenderMode_ShadowMap(side, true, size);
4198 if (! (castermask & (1 << side))) continue;
4200 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
4201 for (i = 0;i < numshadowentities;i++) if (entitysides[i] & (1 << side))
4202 R_Shadow_DrawEntityShadow(shadowentities[i]);
4205 if (numlightentities_noselfshadow)
4207 // render lighting using the depth texture as shadowmap
4208 // draw lighting in the unmasked areas
4209 R_Shadow_RenderMode_Lighting(false, false, true);
4210 for (i = 0;i < numlightentities_noselfshadow;i++)
4211 R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
4214 // render shadow casters into 6 sided depth texture
4215 if (numshadowentities_noselfshadow)
4217 for (side = 0;side < 6;side++) if ((receivermask & castermask) & (1 << side))
4219 R_Shadow_RenderMode_ShadowMap(side, false, size);
4220 for (i = 0;i < numshadowentities_noselfshadow;i++) if (entitysides[shadowentities_noselfshadow - i] && (1 << side))
4221 R_Shadow_DrawEntityShadow(shadowentities[shadowentities_noselfshadow - i]);
4225 // render lighting using the depth texture as shadowmap
4226 // draw lighting in the unmasked areas
4227 R_Shadow_RenderMode_Lighting(false, false, true);
4228 // draw lighting in the unmasked areas
4230 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4231 for (i = 0;i < numlightentities;i++)
4232 R_Shadow_DrawEntityLight(lightentities[i]);
4234 else if (castshadows && gl_stencil)
4236 // draw stencil shadow volumes to mask off pixels that are in shadow
4237 // so that they won't receive lighting
4238 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
4239 R_Shadow_ClearStencil();
4241 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
4242 for (i = 0;i < numshadowentities;i++)
4243 R_Shadow_DrawEntityShadow(shadowentities[i]);
4244 if (numlightentities_noselfshadow)
4246 // draw lighting in the unmasked areas
4247 R_Shadow_RenderMode_Lighting(true, false, false);
4248 for (i = 0;i < numlightentities_noselfshadow;i++)
4249 R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
4251 // optionally draw the illuminated areas
4252 // for performance analysis by level designers
4253 if (r_showlighting.integer && r_refdef.view.showdebug)
4255 R_Shadow_RenderMode_VisibleLighting(!r_showdisabledepthtest.integer, false);
4256 for (i = 0;i < numlightentities_noselfshadow;i++)
4257 R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
4260 for (i = 0;i < numshadowentities_noselfshadow;i++)
4261 R_Shadow_DrawEntityShadow(shadowentities[shadowentities_noselfshadow - i]);
4263 if (numsurfaces + numlightentities)
4265 // draw lighting in the unmasked areas
4266 R_Shadow_RenderMode_Lighting(true, false, false);
4268 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4269 for (i = 0;i < numlightentities;i++)
4270 R_Shadow_DrawEntityLight(lightentities[i]);
4275 if (numsurfaces + numlightentities)
4277 // draw lighting in the unmasked areas
4278 R_Shadow_RenderMode_Lighting(false, false, false);
4280 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4281 for (i = 0;i < numlightentities;i++)
4282 R_Shadow_DrawEntityLight(lightentities[i]);
4283 for (i = 0;i < numlightentities_noselfshadow;i++)
4284 R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
4289 void R_Shadow_DrawLightSprites(void);
4290 void R_ShadowVolumeLighting(qboolean visible)
4298 if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, 2048) ||
4299 (r_shadow_shadowmode != 0) != (r_shadow_shadowmapping.integer != 0) ||
4300 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0) ||
4301 r_shadow_shadowmaptexturetype != r_shadow_shadowmapping_texturetype.integer ||
4302 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
4303 r_shadow_shadowmapprecision != r_shadow_shadowmapping_precision.integer ||
4304 r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
4305 R_Shadow_FreeShadowMaps();
4307 if (r_editlights.integer)
4308 R_Shadow_DrawLightSprites();
4310 R_Shadow_RenderMode_Begin();
4312 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4313 if (r_shadow_debuglight.integer >= 0)
4315 lightindex = r_shadow_debuglight.integer;
4316 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4317 if (light && (light->flags & flag))
4318 R_DrawRTLight(&light->rtlight, visible);
4322 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4323 for (lightindex = 0;lightindex < range;lightindex++)
4325 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4326 if (light && (light->flags & flag))
4327 R_DrawRTLight(&light->rtlight, visible);
4330 if (r_refdef.scene.rtdlight)
4331 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4332 R_DrawRTLight(r_refdef.scene.lights[lnum], visible);
4334 R_Shadow_RenderMode_End();
4337 extern const float r_screenvertex3f[12];
4338 extern void R_SetupView(qboolean allowwaterclippingplane);
4339 extern void R_ResetViewRendering3D(void);
4340 extern void R_ResetViewRendering2D(void);
4341 extern cvar_t r_shadows;
4342 extern cvar_t r_shadows_darken;
4343 extern cvar_t r_shadows_drawafterrtlighting;
4344 extern cvar_t r_shadows_castfrombmodels;
4345 extern cvar_t r_shadows_throwdistance;
4346 extern cvar_t r_shadows_throwdirection;
4347 void R_DrawModelShadows(void)
4350 float relativethrowdistance;
4351 entity_render_t *ent;
4352 vec3_t relativelightorigin;
4353 vec3_t relativelightdirection;
4354 vec3_t relativeshadowmins, relativeshadowmaxs;
4355 vec3_t tmp, shadowdir;
4357 if (!r_drawentities.integer || !gl_stencil)
4361 R_ResetViewRendering3D();
4362 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4363 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4364 R_Shadow_RenderMode_Begin();
4365 R_Shadow_RenderMode_ActiveLight(NULL);
4366 r_shadow_lightscissor[0] = r_refdef.view.x;
4367 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
4368 r_shadow_lightscissor[2] = r_refdef.view.width;
4369 r_shadow_lightscissor[3] = r_refdef.view.height;
4370 R_Shadow_RenderMode_StencilShadowVolumes(false);
4373 if (r_shadows.integer == 2)
4375 Math_atov(r_shadows_throwdirection.string, shadowdir);
4376 VectorNormalize(shadowdir);
4379 R_Shadow_ClearStencil();
4381 for (i = 0;i < r_refdef.scene.numentities;i++)
4383 ent = r_refdef.scene.entities[i];
4385 // cast shadows from anything of the map (submodels are optional)
4386 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4388 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4389 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
4390 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
4391 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
4392 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4395 if(ent->entitynumber != 0)
4397 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
4398 int entnum, entnum2, recursion;
4399 entnum = entnum2 = ent->entitynumber;
4400 for(recursion = 32; recursion > 0; --recursion)
4402 entnum2 = cl.entities[entnum].state_current.tagentity;
4403 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
4408 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
4410 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
4411 // transform into modelspace of OUR entity
4412 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
4413 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
4416 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4419 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4422 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
4423 RSurf_ActiveModelEntity(ent, false, false);
4424 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4425 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4429 // not really the right mode, but this will disable any silly stencil features
4430 R_Shadow_RenderMode_End();
4432 // set up ortho view for rendering this pass
4433 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4434 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4435 //GL_ScissorTest(true);
4436 //R_Mesh_Matrix(&identitymatrix);
4437 //R_Mesh_ResetTextureState();
4438 R_ResetViewRendering2D();
4439 R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
4440 R_Mesh_ColorPointer(NULL, 0, 0);
4441 R_SetupGenericShader(false);
4443 // set up a darkening blend on shadowed areas
4444 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4445 //GL_DepthRange(0, 1);
4446 //GL_DepthTest(false);
4447 //GL_DepthMask(false);
4448 //GL_PolygonOffset(0, 0);CHECKGLERROR
4449 GL_Color(0, 0, 0, r_shadows_darken.value);
4450 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4451 //qglDepthFunc(GL_ALWAYS);CHECKGLERROR
4452 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
4453 qglStencilMask(~0);CHECKGLERROR
4454 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
4455 qglStencilFunc(GL_NOTEQUAL, 128, ~0);CHECKGLERROR
4457 // apply the blend to the shadowed areas
4458 R_Mesh_Draw(0, 4, 0, 2, NULL, polygonelements, 0, 0);
4460 // restore the viewport
4461 R_SetViewport(&r_refdef.view.viewport);
4463 // restore other state to normal
4464 //R_Shadow_RenderMode_End();
4467 void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4470 vec3_t centerorigin;
4471 // if it's too close, skip it
4472 if (VectorLength(rtlight->color) < (1.0f / 256.0f))
4474 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4477 if (usequery && r_numqueries + 2 <= r_maxqueries)
4479 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4480 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4481 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4484 // NOTE: we can't disable depth testing using R_DrawSprite's depthdisable argument, which calls GL_DepthTest, as that's broken in the ATI drivers
4485 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
4486 qglDepthFunc(GL_ALWAYS);
4487 R_DrawSprite(GL_ONE, GL_ZERO, r_shadow_lightcorona, NULL, false, false, centerorigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale, 1, 1, 1, 1);
4488 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4489 qglDepthFunc(GL_LEQUAL);
4490 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
4491 R_DrawSprite(GL_ONE, GL_ZERO, r_shadow_lightcorona, NULL, false, false, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale, 1, 1, 1, 1);
4492 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4495 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4498 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4501 GLint allpixels = 0, visiblepixels = 0;
4502 // now we have to check the query result
4503 if (rtlight->corona_queryindex_visiblepixels)
4506 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
4507 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
4509 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
4510 if (visiblepixels < 1 || allpixels < 1)
4512 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
4513 cscale *= rtlight->corona_visibility;
4517 // FIXME: these traces should scan all render entities instead of cl.world
4518 if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
4521 VectorScale(rtlight->color, cscale, color);
4522 if (VectorLength(color) > (1.0f / 256.0f))
4523 R_DrawSprite(GL_ONE, GL_ONE, r_shadow_lightcorona, NULL, true, false, rtlight->shadoworigin, r_refdef.view.right, r_refdef.view.up, scale, -scale, -scale, scale, color[0], color[1], color[2], 1);
4526 void R_DrawCoronas(void)
4534 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4536 if (r_waterstate.renderingscene)
4538 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4539 R_Mesh_Matrix(&identitymatrix);
4541 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4543 // check occlusion of coronas
4544 // use GL_ARB_occlusion_query if available
4545 // otherwise use raytraces
4547 usequery = gl_support_arb_occlusion_query && r_coronas_occlusionquery.integer;
4550 GL_ColorMask(0,0,0,0);
4551 if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
4552 if (r_maxqueries < R_MAX_OCCLUSION_QUERIES)
4555 r_maxqueries = (range + r_refdef.scene.numlights) * 4;
4556 r_maxqueries = min(r_maxqueries, R_MAX_OCCLUSION_QUERIES);
4558 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
4562 for (lightindex = 0;lightindex < range;lightindex++)
4564 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4567 rtlight = &light->rtlight;
4568 rtlight->corona_visibility = 0;
4569 rtlight->corona_queryindex_visiblepixels = 0;
4570 rtlight->corona_queryindex_allpixels = 0;
4571 if (!(rtlight->flags & flag))
4573 if (rtlight->corona <= 0)
4575 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4577 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4579 for (i = 0;i < r_refdef.scene.numlights;i++)
4581 rtlight = r_refdef.scene.lights[i];
4582 rtlight->corona_visibility = 0;
4583 rtlight->corona_queryindex_visiblepixels = 0;
4584 rtlight->corona_queryindex_allpixels = 0;
4585 if (!(rtlight->flags & flag))
4587 if (rtlight->corona <= 0)
4589 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4592 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4594 // now draw the coronas using the query data for intensity info
4595 for (lightindex = 0;lightindex < range;lightindex++)
4597 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4600 rtlight = &light->rtlight;
4601 if (rtlight->corona_visibility <= 0)
4603 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4605 for (i = 0;i < r_refdef.scene.numlights;i++)
4607 rtlight = r_refdef.scene.lights[i];
4608 if (rtlight->corona_visibility <= 0)
4610 if (gl_flashblend.integer)
4611 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4613 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4619 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
4620 typedef struct suffixinfo_s
4623 qboolean flipx, flipy, flipdiagonal;
4626 static suffixinfo_t suffix[3][6] =
4629 {"px", false, false, false},
4630 {"nx", false, false, false},
4631 {"py", false, false, false},
4632 {"ny", false, false, false},
4633 {"pz", false, false, false},
4634 {"nz", false, false, false}
4637 {"posx", false, false, false},
4638 {"negx", false, false, false},
4639 {"posy", false, false, false},
4640 {"negy", false, false, false},
4641 {"posz", false, false, false},
4642 {"negz", false, false, false}
4645 {"rt", true, false, true},
4646 {"lf", false, true, true},
4647 {"ft", true, true, false},
4648 {"bk", false, false, false},
4649 {"up", true, false, true},
4650 {"dn", true, false, true}
4654 static int componentorder[4] = {0, 1, 2, 3};
4656 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
4658 int i, j, cubemapsize;
4659 unsigned char *cubemappixels, *image_buffer;
4660 rtexture_t *cubemaptexture;
4662 // must start 0 so the first loadimagepixels has no requested width/height
4664 cubemappixels = NULL;
4665 cubemaptexture = NULL;
4666 // keep trying different suffix groups (posx, px, rt) until one loads
4667 for (j = 0;j < 3 && !cubemappixels;j++)
4669 // load the 6 images in the suffix group
4670 for (i = 0;i < 6;i++)
4672 // generate an image name based on the base and and suffix
4673 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
4675 if ((image_buffer = loadimagepixelsbgra(name, false, false)))
4677 // an image loaded, make sure width and height are equal
4678 if (image_width == image_height && (!cubemappixels || image_width == cubemapsize))
4680 // if this is the first image to load successfully, allocate the cubemap memory
4681 if (!cubemappixels && image_width >= 1)
4683 cubemapsize = image_width;
4684 // note this clears to black, so unavailable sides are black
4685 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
4687 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
4689 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);
4692 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
4694 Mem_Free(image_buffer);
4698 // if a cubemap loaded, upload it
4701 if (developer_loading.integer)
4702 Con_Printf("loading cubemap \"%s\"\n", basename);
4704 if (!r_shadow_filters_texturepool)
4705 r_shadow_filters_texturepool = R_AllocTexturePool();
4706 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_BGRA, TEXF_PRECACHE | (gl_texturecompression_lightcubemaps.integer ? TEXF_COMPRESS : 0) | TEXF_FORCELINEAR, NULL);
4707 Mem_Free(cubemappixels);
4711 Con_DPrintf("failed to load cubemap \"%s\"\n", basename);
4712 if (developer_loading.integer)
4714 Con_Printf("(tried tried images ");
4715 for (j = 0;j < 3;j++)
4716 for (i = 0;i < 6;i++)
4717 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
4718 Con_Print(" and was unable to find any of them).\n");
4721 return cubemaptexture;
4724 rtexture_t *R_Shadow_Cubemap(const char *basename)
4727 for (i = 0;i < numcubemaps;i++)
4728 if (!strcasecmp(cubemaps[i].basename, basename))
4729 return cubemaps[i].texture ? cubemaps[i].texture : r_texture_whitecube;
4730 if (i >= MAX_CUBEMAPS)
4731 return r_texture_whitecube;
4733 strlcpy(cubemaps[i].basename, basename, sizeof(cubemaps[i].basename));
4734 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
4735 return cubemaps[i].texture;
4738 void R_Shadow_FreeCubemaps(void)
4741 for (i = 0;i < numcubemaps;i++)
4743 if (developer_loading.integer)
4744 Con_Printf("unloading cubemap \"%s\"\n", cubemaps[i].basename);
4745 if (cubemaps[i].texture)
4746 R_FreeTexture(cubemaps[i].texture);
4750 R_FreeTexturePool(&r_shadow_filters_texturepool);
4753 dlight_t *R_Shadow_NewWorldLight(void)
4755 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4758 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)
4761 // validate parameters
4762 if (style < 0 || style >= MAX_LIGHTSTYLES)
4764 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
4770 // copy to light properties
4771 VectorCopy(origin, light->origin);
4772 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4773 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4774 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4775 light->color[0] = max(color[0], 0);
4776 light->color[1] = max(color[1], 0);
4777 light->color[2] = max(color[2], 0);
4778 light->radius = max(radius, 0);
4779 light->style = style;
4780 light->shadow = shadowenable;
4781 light->corona = corona;
4782 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4783 light->coronasizescale = coronasizescale;
4784 light->ambientscale = ambientscale;
4785 light->diffusescale = diffusescale;
4786 light->specularscale = specularscale;
4787 light->flags = flags;
4789 // update renderable light data
4790 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4791 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);
4794 void R_Shadow_FreeWorldLight(dlight_t *light)
4796 if (r_shadow_selectedlight == light)
4797 r_shadow_selectedlight = NULL;
4798 R_RTLight_Uncompile(&light->rtlight);
4799 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4802 void R_Shadow_ClearWorldLights(void)
4806 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4807 for (lightindex = 0;lightindex < range;lightindex++)
4809 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4811 R_Shadow_FreeWorldLight(light);
4813 r_shadow_selectedlight = NULL;
4814 R_Shadow_FreeCubemaps();
4817 void R_Shadow_SelectLight(dlight_t *light)
4819 if (r_shadow_selectedlight)
4820 r_shadow_selectedlight->selected = false;
4821 r_shadow_selectedlight = light;
4822 if (r_shadow_selectedlight)
4823 r_shadow_selectedlight->selected = true;
4826 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4828 // this is never batched (there can be only one)
4829 R_DrawSprite(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, r_editlights_sprcursor->tex, r_editlights_sprcursor->tex, false, false, r_editlights_cursorlocation, r_refdef.view.right, r_refdef.view.up, EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, -EDLIGHTSPRSIZE, EDLIGHTSPRSIZE, 1, 1, 1, 1);
4832 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4839 // this is never batched (due to the ent parameter changing every time)
4840 // so numsurfaces == 1 and surfacelist[0] == lightnumber
4841 const dlight_t *light = (dlight_t *)ent;
4844 VectorScale(light->color, intensity, spritecolor);
4845 if (VectorLength(spritecolor) < 0.1732f)
4846 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
4847 if (VectorLength(spritecolor) > 1.0f)
4848 VectorNormalize(spritecolor);
4850 // draw light sprite
4851 if (light->cubemapname[0] && !light->shadow)
4852 pic = r_editlights_sprcubemapnoshadowlight;
4853 else if (light->cubemapname[0])
4854 pic = r_editlights_sprcubemaplight;
4855 else if (!light->shadow)
4856 pic = r_editlights_sprnoshadowlight;
4858 pic = r_editlights_sprlight;
4859 R_DrawSprite(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, pic->tex, pic->tex, false, false, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s, spritecolor[0], spritecolor[1], spritecolor[2], 1);
4860 // draw selection sprite if light is selected
4861 if (light->selected)
4862 R_DrawSprite(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, r_editlights_sprselection->tex, r_editlights_sprselection->tex, false, false, light->origin, r_refdef.view.right, r_refdef.view.up, s, -s, -s, s, 1, 1, 1, 1);
4863 // VorteX todo: add normalmode/realtime mode light overlay sprites?
4866 void R_Shadow_DrawLightSprites(void)
4870 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4871 for (lightindex = 0;lightindex < range;lightindex++)
4873 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4875 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
4877 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
4880 void R_Shadow_SelectLightInView(void)
4882 float bestrating, rating, temp[3];
4886 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4889 for (lightindex = 0;lightindex < range;lightindex++)
4891 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4894 VectorSubtract(light->origin, r_refdef.view.origin, temp);
4895 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
4898 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
4899 if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1.0f)
4901 bestrating = rating;
4906 R_Shadow_SelectLight(best);
4909 void R_Shadow_LoadWorldLights(void)
4911 int n, a, style, shadow, flags;
4912 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
4913 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
4914 if (cl.worldmodel == NULL)
4916 Con_Print("No map loaded.\n");
4919 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4920 strlcat (name, ".rtlights", sizeof (name));
4921 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4931 for (;COM_Parse(t, true) && strcmp(
4932 if (COM_Parse(t, true))
4934 if (com_token[0] == '!')
4937 origin[0] = atof(com_token+1);
4940 origin[0] = atof(com_token);
4945 while (*s && *s != '\n' && *s != '\r')
4951 // check for modifier flags
4958 #if _MSC_VER >= 1400
4959 #define sscanf sscanf_s
4961 cubemapname[sizeof(cubemapname)-1] = 0;
4962 #if MAX_QPATH != 128
4963 #error update this code if MAX_QPATH changes
4965 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
4966 #if _MSC_VER >= 1400
4967 , sizeof(cubemapname)
4969 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
4972 flags = LIGHTFLAG_REALTIMEMODE;
4980 coronasizescale = 0.25f;
4982 VectorClear(angles);
4985 if (a < 9 || !strcmp(cubemapname, "\"\""))
4987 // remove quotes on cubemapname
4988 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
4991 namelen = strlen(cubemapname) - 2;
4992 memmove(cubemapname, cubemapname + 1, namelen);
4993 cubemapname[namelen] = '\0';
4997 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);
5000 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5008 Con_Printf("invalid rtlights file \"%s\"\n", name);
5009 Mem_Free(lightsstring);
5013 void R_Shadow_SaveWorldLights(void)
5017 size_t bufchars, bufmaxchars;
5019 char name[MAX_QPATH];
5020 char line[MAX_INPUTLINE];
5021 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
5022 // I hate lines which are 3 times my screen size :( --blub
5025 if (cl.worldmodel == NULL)
5027 Con_Print("No map loaded.\n");
5030 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
5031 strlcat (name, ".rtlights", sizeof (name));
5032 bufchars = bufmaxchars = 0;
5034 for (lightindex = 0;lightindex < range;lightindex++)
5036 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5039 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
5040 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);
5041 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
5042 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]);
5044 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);
5045 if (bufchars + strlen(line) > bufmaxchars)
5047 bufmaxchars = bufchars + strlen(line) + 2048;
5049 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
5053 memcpy(buf, oldbuf, bufchars);
5059 memcpy(buf + bufchars, line, strlen(line));
5060 bufchars += strlen(line);
5064 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
5069 void R_Shadow_LoadLightsFile(void)
5072 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
5073 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
5074 if (cl.worldmodel == NULL)
5076 Con_Print("No map loaded.\n");
5079 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
5080 strlcat (name, ".lights", sizeof (name));
5081 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5089 while (*s && *s != '\n' && *s != '\r')
5095 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);
5099 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);
5102 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
5103 radius = bound(15, radius, 4096);
5104 VectorScale(color, (2.0f / (8388608.0f)), color);
5105 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5113 Con_Printf("invalid lights file \"%s\"\n", name);
5114 Mem_Free(lightsstring);
5118 // tyrlite/hmap2 light types in the delay field
5119 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
5121 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
5123 int entnum, style, islight, skin, pflags, effects, type, n;
5126 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
5127 char key[256], value[MAX_INPUTLINE];
5129 if (cl.worldmodel == NULL)
5131 Con_Print("No map loaded.\n");
5134 // try to load a .ent file first
5135 FS_StripExtension (cl.worldmodel->name, key, sizeof (key));
5136 strlcat (key, ".ent", sizeof (key));
5137 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
5138 // and if that is not found, fall back to the bsp file entity string
5140 data = cl.worldmodel->brush.entities;
5143 for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
5145 type = LIGHTTYPE_MINUSX;
5146 origin[0] = origin[1] = origin[2] = 0;
5147 originhack[0] = originhack[1] = originhack[2] = 0;
5148 angles[0] = angles[1] = angles[2] = 0;
5149 color[0] = color[1] = color[2] = 1;
5150 light[0] = light[1] = light[2] = 1;light[3] = 300;
5151 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
5161 if (!COM_ParseToken_Simple(&data, false, false))
5163 if (com_token[0] == '}')
5164 break; // end of entity
5165 if (com_token[0] == '_')
5166 strlcpy(key, com_token + 1, sizeof(key));
5168 strlcpy(key, com_token, sizeof(key));
5169 while (key[strlen(key)-1] == ' ') // remove trailing spaces
5170 key[strlen(key)-1] = 0;
5171 if (!COM_ParseToken_Simple(&data, false, false))
5173 strlcpy(value, com_token, sizeof(value));
5175 // now that we have the key pair worked out...
5176 if (!strcmp("light", key))
5178 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5182 light[0] = vec[0] * (1.0f / 256.0f);
5183 light[1] = vec[0] * (1.0f / 256.0f);
5184 light[2] = vec[0] * (1.0f / 256.0f);
5190 light[0] = vec[0] * (1.0f / 255.0f);
5191 light[1] = vec[1] * (1.0f / 255.0f);
5192 light[2] = vec[2] * (1.0f / 255.0f);
5196 else if (!strcmp("delay", key))
5198 else if (!strcmp("origin", key))
5199 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5200 else if (!strcmp("angle", key))
5201 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5202 else if (!strcmp("angles", key))
5203 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5204 else if (!strcmp("color", key))
5205 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5206 else if (!strcmp("wait", key))
5207 fadescale = atof(value);
5208 else if (!strcmp("classname", key))
5210 if (!strncmp(value, "light", 5))
5213 if (!strcmp(value, "light_fluoro"))
5218 overridecolor[0] = 1;
5219 overridecolor[1] = 1;
5220 overridecolor[2] = 1;
5222 if (!strcmp(value, "light_fluorospark"))
5227 overridecolor[0] = 1;
5228 overridecolor[1] = 1;
5229 overridecolor[2] = 1;
5231 if (!strcmp(value, "light_globe"))
5236 overridecolor[0] = 1;
5237 overridecolor[1] = 0.8;
5238 overridecolor[2] = 0.4;
5240 if (!strcmp(value, "light_flame_large_yellow"))
5245 overridecolor[0] = 1;
5246 overridecolor[1] = 0.5;
5247 overridecolor[2] = 0.1;
5249 if (!strcmp(value, "light_flame_small_yellow"))
5254 overridecolor[0] = 1;
5255 overridecolor[1] = 0.5;
5256 overridecolor[2] = 0.1;
5258 if (!strcmp(value, "light_torch_small_white"))
5263 overridecolor[0] = 1;
5264 overridecolor[1] = 0.5;
5265 overridecolor[2] = 0.1;
5267 if (!strcmp(value, "light_torch_small_walltorch"))
5272 overridecolor[0] = 1;
5273 overridecolor[1] = 0.5;
5274 overridecolor[2] = 0.1;
5278 else if (!strcmp("style", key))
5279 style = atoi(value);
5280 else if (!strcmp("skin", key))
5281 skin = (int)atof(value);
5282 else if (!strcmp("pflags", key))
5283 pflags = (int)atof(value);
5284 else if (!strcmp("effects", key))
5285 effects = (int)atof(value);
5286 else if (cl.worldmodel->type == mod_brushq3)
5288 if (!strcmp("scale", key))
5289 lightscale = atof(value);
5290 if (!strcmp("fade", key))
5291 fadescale = atof(value);
5296 if (lightscale <= 0)
5300 if (color[0] == color[1] && color[0] == color[2])
5302 color[0] *= overridecolor[0];
5303 color[1] *= overridecolor[1];
5304 color[2] *= overridecolor[2];
5306 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5307 color[0] = color[0] * light[0];
5308 color[1] = color[1] * light[1];
5309 color[2] = color[2] * light[2];
5312 case LIGHTTYPE_MINUSX:
5314 case LIGHTTYPE_RECIPX:
5316 VectorScale(color, (1.0f / 16.0f), color);
5318 case LIGHTTYPE_RECIPXX:
5320 VectorScale(color, (1.0f / 16.0f), color);
5323 case LIGHTTYPE_NONE:
5327 case LIGHTTYPE_MINUSXX:
5330 VectorAdd(origin, originhack, origin);
5332 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);
5335 Mem_Free(entfiledata);
5339 void R_Shadow_SetCursorLocationForView(void)
5342 vec3_t dest, endpos;
5344 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5345 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
5346 if (trace.fraction < 1)
5348 dist = trace.fraction * r_editlights_cursordistance.value;
5349 push = r_editlights_cursorpushback.value;
5353 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5354 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5358 VectorClear( endpos );
5360 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5361 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5362 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5365 void R_Shadow_UpdateWorldLightSelection(void)
5367 if (r_editlights.integer)
5369 R_Shadow_SetCursorLocationForView();
5370 R_Shadow_SelectLightInView();
5373 R_Shadow_SelectLight(NULL);
5376 void R_Shadow_EditLights_Clear_f(void)
5378 R_Shadow_ClearWorldLights();
5381 void R_Shadow_EditLights_Reload_f(void)
5385 strlcpy(r_shadow_mapname, cl.worldmodel->name, sizeof(r_shadow_mapname));
5386 R_Shadow_ClearWorldLights();
5387 R_Shadow_LoadWorldLights();
5388 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5390 R_Shadow_LoadLightsFile();
5391 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5392 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5396 void R_Shadow_EditLights_Save_f(void)
5400 R_Shadow_SaveWorldLights();
5403 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
5405 R_Shadow_ClearWorldLights();
5406 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5409 void R_Shadow_EditLights_ImportLightsFile_f(void)
5411 R_Shadow_ClearWorldLights();
5412 R_Shadow_LoadLightsFile();
5415 void R_Shadow_EditLights_Spawn_f(void)
5418 if (!r_editlights.integer)
5420 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5423 if (Cmd_Argc() != 1)
5425 Con_Print("r_editlights_spawn does not take parameters\n");
5428 color[0] = color[1] = color[2] = 1;
5429 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5432 void R_Shadow_EditLights_Edit_f(void)
5434 vec3_t origin, angles, color;
5435 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5436 int style, shadows, flags, normalmode, realtimemode;
5437 char cubemapname[MAX_INPUTLINE];
5438 if (!r_editlights.integer)
5440 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5443 if (!r_shadow_selectedlight)
5445 Con_Print("No selected light.\n");
5448 VectorCopy(r_shadow_selectedlight->origin, origin);
5449 VectorCopy(r_shadow_selectedlight->angles, angles);
5450 VectorCopy(r_shadow_selectedlight->color, color);
5451 radius = r_shadow_selectedlight->radius;
5452 style = r_shadow_selectedlight->style;
5453 if (r_shadow_selectedlight->cubemapname)
5454 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5457 shadows = r_shadow_selectedlight->shadow;
5458 corona = r_shadow_selectedlight->corona;
5459 coronasizescale = r_shadow_selectedlight->coronasizescale;
5460 ambientscale = r_shadow_selectedlight->ambientscale;
5461 diffusescale = r_shadow_selectedlight->diffusescale;
5462 specularscale = r_shadow_selectedlight->specularscale;
5463 flags = r_shadow_selectedlight->flags;
5464 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5465 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5466 if (!strcmp(Cmd_Argv(1), "origin"))
5468 if (Cmd_Argc() != 5)
5470 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5473 origin[0] = atof(Cmd_Argv(2));
5474 origin[1] = atof(Cmd_Argv(3));
5475 origin[2] = atof(Cmd_Argv(4));
5477 else if (!strcmp(Cmd_Argv(1), "originx"))
5479 if (Cmd_Argc() != 3)
5481 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5484 origin[0] = atof(Cmd_Argv(2));
5486 else if (!strcmp(Cmd_Argv(1), "originy"))
5488 if (Cmd_Argc() != 3)
5490 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5493 origin[1] = atof(Cmd_Argv(2));
5495 else if (!strcmp(Cmd_Argv(1), "originz"))
5497 if (Cmd_Argc() != 3)
5499 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5502 origin[2] = atof(Cmd_Argv(2));
5504 else if (!strcmp(Cmd_Argv(1), "move"))
5506 if (Cmd_Argc() != 5)
5508 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5511 origin[0] += atof(Cmd_Argv(2));
5512 origin[1] += atof(Cmd_Argv(3));
5513 origin[2] += atof(Cmd_Argv(4));
5515 else if (!strcmp(Cmd_Argv(1), "movex"))
5517 if (Cmd_Argc() != 3)
5519 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5522 origin[0] += atof(Cmd_Argv(2));
5524 else if (!strcmp(Cmd_Argv(1), "movey"))
5526 if (Cmd_Argc() != 3)
5528 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5531 origin[1] += atof(Cmd_Argv(2));
5533 else if (!strcmp(Cmd_Argv(1), "movez"))
5535 if (Cmd_Argc() != 3)
5537 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5540 origin[2] += atof(Cmd_Argv(2));
5542 else if (!strcmp(Cmd_Argv(1), "angles"))
5544 if (Cmd_Argc() != 5)
5546 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5549 angles[0] = atof(Cmd_Argv(2));
5550 angles[1] = atof(Cmd_Argv(3));
5551 angles[2] = atof(Cmd_Argv(4));
5553 else if (!strcmp(Cmd_Argv(1), "anglesx"))
5555 if (Cmd_Argc() != 3)
5557 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5560 angles[0] = atof(Cmd_Argv(2));
5562 else if (!strcmp(Cmd_Argv(1), "anglesy"))
5564 if (Cmd_Argc() != 3)
5566 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5569 angles[1] = atof(Cmd_Argv(2));
5571 else if (!strcmp(Cmd_Argv(1), "anglesz"))
5573 if (Cmd_Argc() != 3)
5575 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5578 angles[2] = atof(Cmd_Argv(2));
5580 else if (!strcmp(Cmd_Argv(1), "color"))
5582 if (Cmd_Argc() != 5)
5584 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
5587 color[0] = atof(Cmd_Argv(2));
5588 color[1] = atof(Cmd_Argv(3));
5589 color[2] = atof(Cmd_Argv(4));
5591 else if (!strcmp(Cmd_Argv(1), "radius"))
5593 if (Cmd_Argc() != 3)
5595 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5598 radius = atof(Cmd_Argv(2));
5600 else if (!strcmp(Cmd_Argv(1), "colorscale"))
5602 if (Cmd_Argc() == 3)
5604 double scale = atof(Cmd_Argv(2));
5611 if (Cmd_Argc() != 5)
5613 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
5616 color[0] *= atof(Cmd_Argv(2));
5617 color[1] *= atof(Cmd_Argv(3));
5618 color[2] *= atof(Cmd_Argv(4));
5621 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
5623 if (Cmd_Argc() != 3)
5625 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5628 radius *= atof(Cmd_Argv(2));
5630 else if (!strcmp(Cmd_Argv(1), "style"))
5632 if (Cmd_Argc() != 3)
5634 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5637 style = atoi(Cmd_Argv(2));
5639 else if (!strcmp(Cmd_Argv(1), "cubemap"))
5643 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5646 if (Cmd_Argc() == 3)
5647 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
5651 else if (!strcmp(Cmd_Argv(1), "shadows"))
5653 if (Cmd_Argc() != 3)
5655 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5658 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5660 else if (!strcmp(Cmd_Argv(1), "corona"))
5662 if (Cmd_Argc() != 3)
5664 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5667 corona = atof(Cmd_Argv(2));
5669 else if (!strcmp(Cmd_Argv(1), "coronasize"))
5671 if (Cmd_Argc() != 3)
5673 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5676 coronasizescale = atof(Cmd_Argv(2));
5678 else if (!strcmp(Cmd_Argv(1), "ambient"))
5680 if (Cmd_Argc() != 3)
5682 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5685 ambientscale = atof(Cmd_Argv(2));
5687 else if (!strcmp(Cmd_Argv(1), "diffuse"))
5689 if (Cmd_Argc() != 3)
5691 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5694 diffusescale = atof(Cmd_Argv(2));
5696 else if (!strcmp(Cmd_Argv(1), "specular"))
5698 if (Cmd_Argc() != 3)
5700 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5703 specularscale = atof(Cmd_Argv(2));
5705 else if (!strcmp(Cmd_Argv(1), "normalmode"))
5707 if (Cmd_Argc() != 3)
5709 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5712 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5714 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
5716 if (Cmd_Argc() != 3)
5718 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5721 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5725 Con_Print("usage: r_editlights_edit [property] [value]\n");
5726 Con_Print("Selected light's properties:\n");
5727 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5728 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5729 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5730 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
5731 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
5732 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
5733 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5734 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
5735 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
5736 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
5737 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
5738 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
5739 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5740 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5743 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5744 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5747 void R_Shadow_EditLights_EditAll_f(void)
5753 if (!r_editlights.integer)
5755 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5759 // EditLights doesn't seem to have a "remove" command or something so:
5760 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5761 for (lightindex = 0;lightindex < range;lightindex++)
5763 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5766 R_Shadow_SelectLight(light);
5767 R_Shadow_EditLights_Edit_f();
5771 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
5773 int lightnumber, lightcount;
5774 size_t lightindex, range;
5778 if (!r_editlights.integer)
5780 x = vid_conwidth.value - 240;
5782 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
5785 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5786 for (lightindex = 0;lightindex < range;lightindex++)
5788 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5791 if (light == r_shadow_selectedlight)
5792 lightnumber = lightindex;
5795 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;
5796 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;
5798 if (r_shadow_selectedlight == NULL)
5800 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;
5801 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;
5802 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;
5803 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;
5804 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;
5805 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;
5806 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;
5807 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;
5808 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;
5809 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;
5810 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;
5811 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;
5812 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;
5813 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;
5814 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;
5817 void R_Shadow_EditLights_ToggleShadow_f(void)
5819 if (!r_editlights.integer)
5821 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5824 if (!r_shadow_selectedlight)
5826 Con_Print("No selected light.\n");
5829 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);
5832 void R_Shadow_EditLights_ToggleCorona_f(void)
5834 if (!r_editlights.integer)
5836 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5839 if (!r_shadow_selectedlight)
5841 Con_Print("No selected light.\n");
5844 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);
5847 void R_Shadow_EditLights_Remove_f(void)
5849 if (!r_editlights.integer)
5851 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
5854 if (!r_shadow_selectedlight)
5856 Con_Print("No selected light.\n");
5859 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
5860 r_shadow_selectedlight = NULL;
5863 void R_Shadow_EditLights_Help_f(void)
5866 "Documentation on r_editlights system:\n"
5868 "r_editlights : enable/disable editing mode\n"
5869 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
5870 "r_editlights_cursorpushback : push back cursor this far from surface\n"
5871 "r_editlights_cursorpushoff : push cursor off surface this far\n"
5872 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
5873 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
5875 "r_editlights_help : this help\n"
5876 "r_editlights_clear : remove all lights\n"
5877 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
5878 "r_editlights_save : save to .rtlights file\n"
5879 "r_editlights_spawn : create a light with default settings\n"
5880 "r_editlights_edit command : edit selected light - more documentation below\n"
5881 "r_editlights_remove : remove selected light\n"
5882 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
5883 "r_editlights_importlightentitiesfrommap : reload light entities\n"
5884 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
5886 "origin x y z : set light location\n"
5887 "originx x: set x component of light location\n"
5888 "originy y: set y component of light location\n"
5889 "originz z: set z component of light location\n"
5890 "move x y z : adjust light location\n"
5891 "movex x: adjust x component of light location\n"
5892 "movey y: adjust y component of light location\n"
5893 "movez z: adjust z component of light location\n"
5894 "angles x y z : set light angles\n"
5895 "anglesx x: set x component of light angles\n"
5896 "anglesy y: set y component of light angles\n"
5897 "anglesz z: set z component of light angles\n"
5898 "color r g b : set color of light (can be brighter than 1 1 1)\n"
5899 "radius radius : set radius (size) of light\n"
5900 "colorscale grey : multiply color of light (1 does nothing)\n"
5901 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
5902 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
5903 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
5904 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
5905 "cubemap basename : set filter cubemap of light (not yet supported)\n"
5906 "shadows 1/0 : turn on/off shadows\n"
5907 "corona n : set corona intensity\n"
5908 "coronasize n : set corona size (0-1)\n"
5909 "ambient n : set ambient intensity (0-1)\n"
5910 "diffuse n : set diffuse intensity (0-1)\n"
5911 "specular n : set specular intensity (0-1)\n"
5912 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
5913 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
5914 "<nothing> : print light properties to console\n"
5918 void R_Shadow_EditLights_CopyInfo_f(void)
5920 if (!r_editlights.integer)
5922 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
5925 if (!r_shadow_selectedlight)
5927 Con_Print("No selected light.\n");
5930 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
5931 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
5932 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
5933 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
5934 if (r_shadow_selectedlight->cubemapname)
5935 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
5937 r_shadow_bufferlight.cubemapname[0] = 0;
5938 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
5939 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
5940 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
5941 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
5942 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
5943 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
5944 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
5947 void R_Shadow_EditLights_PasteInfo_f(void)
5949 if (!r_editlights.integer)
5951 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
5954 if (!r_shadow_selectedlight)
5956 Con_Print("No selected light.\n");
5959 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);
5962 void R_Shadow_EditLights_Init(void)
5964 Cvar_RegisterVariable(&r_editlights);
5965 Cvar_RegisterVariable(&r_editlights_cursordistance);
5966 Cvar_RegisterVariable(&r_editlights_cursorpushback);
5967 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
5968 Cvar_RegisterVariable(&r_editlights_cursorgrid);
5969 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
5970 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
5971 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
5972 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)");
5973 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
5974 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
5975 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
5976 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)");
5977 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
5978 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
5979 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
5980 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
5981 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
5982 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
5983 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)");
5989 =============================================================================
5993 =============================================================================
5996 void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, int dynamic)
5998 VectorClear(diffusecolor);
5999 VectorClear(diffusenormal);
6001 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
6003 ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_refdef.scene.ambient * (2.0f / 128.0f);
6004 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
6007 VectorSet(ambientcolor, 1, 1, 1);
6014 for (i = 0;i < r_refdef.scene.numlights;i++)
6016 light = r_refdef.scene.lights[i];
6017 Matrix4x4_Transform(&light->matrix_worldtolight, p, v);
6018 f = 1 - VectorLength2(v);
6019 if (f > 0 && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
6020 VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);