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];
177 int r_shadow_drawbuffer;
178 int r_shadow_readbuffer;
179 int r_shadow_cullface;
180 GLuint r_shadow_fborectangle;
181 GLuint r_shadow_fbocubeside[R_SHADOW_SHADOWMAP_NUMCUBEMAPS][6];
182 GLuint r_shadow_fbo2d;
183 int r_shadow_shadowmode;
184 int r_shadow_shadowmapfilterquality;
185 int r_shadow_shadowmaptexturetype;
186 int r_shadow_shadowmapprecision;
187 int r_shadow_shadowmapmaxsize;
188 qboolean r_shadow_shadowmapvsdct;
189 qboolean r_shadow_shadowmapsampler;
190 int r_shadow_shadowmappcf;
191 int r_shadow_shadowmapborder;
192 int r_shadow_lightscissor[4];
194 int maxshadowtriangles;
197 int maxshadowvertices;
198 float *shadowvertex3f;
208 unsigned char *shadowsides;
209 int *shadowsideslist;
216 int r_shadow_buffer_numleafpvsbytes;
217 unsigned char *r_shadow_buffer_visitingleafpvs;
218 unsigned char *r_shadow_buffer_leafpvs;
219 int *r_shadow_buffer_leaflist;
221 int r_shadow_buffer_numsurfacepvsbytes;
222 unsigned char *r_shadow_buffer_surfacepvs;
223 int *r_shadow_buffer_surfacelist;
225 int r_shadow_buffer_numshadowtrispvsbytes;
226 unsigned char *r_shadow_buffer_shadowtrispvs;
227 int r_shadow_buffer_numlighttrispvsbytes;
228 unsigned char *r_shadow_buffer_lighttrispvs;
230 rtexturepool_t *r_shadow_texturepool;
231 rtexture_t *r_shadow_attenuationgradienttexture;
232 rtexture_t *r_shadow_attenuation2dtexture;
233 rtexture_t *r_shadow_attenuation3dtexture;
234 rtexture_t *r_shadow_lightcorona;
235 rtexture_t *r_shadow_shadowmaprectangletexture;
236 rtexture_t *r_shadow_shadowmap2dtexture;
237 rtexture_t *r_shadow_shadowmapcubetexture[R_SHADOW_SHADOWMAP_NUMCUBEMAPS];
238 rtexture_t *r_shadow_shadowmapvsdcttexture;
239 int r_shadow_shadowmapsize; // changes for each light based on distance
240 int r_shadow_shadowmaplod; // changes for each light based on distance
242 // lights are reloaded when this changes
243 char r_shadow_mapname[MAX_QPATH];
245 // used only for light filters (cubemaps)
246 rtexturepool_t *r_shadow_filters_texturepool;
248 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"};
249 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"};
250 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
251 cvar_t r_shadow_usenormalmap = {CVAR_SAVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"};
252 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)"};
253 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"};
254 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
255 cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
256 cvar_t r_shadow_glossexact = {0, "r_shadow_glossexact", "0", "use exact reflection math for gloss (slightly slower, but should look a tad better)"};
257 cvar_t r_shadow_lightattenuationdividebias = {0, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"};
258 cvar_t r_shadow_lightattenuationlinearscale = {0, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"};
259 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
260 cvar_t r_shadow_lightradiusscale = {0, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
261 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1", "use portal culling to exactly determine lit triangles when compiling world lights"};
262 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000", "how far to cast shadows"};
263 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)"};
264 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
265 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
266 cvar_t r_shadow_realtime_dlight_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
267 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
268 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)"};
269 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"};
270 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
271 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
272 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"};
273 cvar_t r_shadow_realtime_world_compilesvbsp = {0, "r_shadow_realtime_world_compilesvbsp", "1", "enables svbsp optimization during compilation"};
274 cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "1", "enables portal-based culling optimization during compilation"};
275 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)"};
276 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"};
277 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"};
278 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)"};
279 cvar_t r_shadow_shadowmapping_precision = {CVAR_SAVE, "r_shadow_shadowmapping_precision", "24", "requested minimum shadowmap texture precision"};
280 cvar_t r_shadow_shadowmapping_vsdct = {CVAR_SAVE, "r_shadow_shadowmapping_vsdct", "1", "enables use of virtual shadow depth cube texture"};
281 cvar_t r_shadow_shadowmapping_minsize = {CVAR_SAVE, "r_shadow_shadowmapping_minsize", "32", "shadowmap size limit"};
282 cvar_t r_shadow_shadowmapping_maxsize = {CVAR_SAVE, "r_shadow_shadowmapping_maxsize", "512", "shadowmap size limit"};
283 cvar_t r_shadow_shadowmapping_lod_bias = {CVAR_SAVE, "r_shadow_shadowmapping_lod_bias", "16", "shadowmap size bias"};
284 cvar_t r_shadow_shadowmapping_lod_scale = {CVAR_SAVE, "r_shadow_shadowmapping_lod_scale", "128", "shadowmap size scaling parameter"};
285 cvar_t r_shadow_shadowmapping_bordersize = {CVAR_SAVE, "r_shadow_shadowmapping_bordersize", "4", "shadowmap size bias for filtering"};
286 cvar_t r_shadow_shadowmapping_nearclip = {CVAR_SAVE, "r_shadow_shadowmapping_nearclip", "1", "shadowmap nearclip in world units"};
287 cvar_t r_shadow_shadowmapping_bias = {CVAR_SAVE, "r_shadow_shadowmapping_bias", "0.03", "shadowmap bias parameter (this is multiplied by nearclip * 1024 / lodsize)"};
288 cvar_t r_shadow_culltriangles = {0, "r_shadow_culltriangles", "1", "performs more expensive tests to remove unnecessary triangles of lit surfaces"};
289 cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
290 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)"};
291 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)"};
292 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "1", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
293 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"};
294 cvar_t r_coronas_occlusionquery = {CVAR_SAVE, "r_coronas_occlusionquery", "1", "use GL_ARB_occlusion_query extension if supported (fades coronas according to visibility)"};
295 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
296 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
297 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
298 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
299 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
300 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
301 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
302 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
303 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
305 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
306 #define ATTENTABLESIZE 256
307 // 1D gradient, 2D circle and 3D sphere attenuation textures
308 #define ATTEN1DSIZE 32
309 #define ATTEN2DSIZE 64
310 #define ATTEN3DSIZE 32
312 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
313 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
314 static float r_shadow_attentable[ATTENTABLESIZE+1];
316 rtlight_t *r_shadow_compilingrtlight;
317 static memexpandablearray_t r_shadow_worldlightsarray;
318 dlight_t *r_shadow_selectedlight;
319 dlight_t r_shadow_bufferlight;
320 vec3_t r_editlights_cursorlocation;
322 extern int con_vislines;
324 typedef struct cubemapinfo_s
331 #define MAX_CUBEMAPS 256
332 static int numcubemaps;
333 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
335 void R_Shadow_UncompileWorldLights(void);
336 void R_Shadow_ClearWorldLights(void);
337 void R_Shadow_SaveWorldLights(void);
338 void R_Shadow_LoadWorldLights(void);
339 void R_Shadow_LoadLightsFile(void);
340 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
341 void R_Shadow_EditLights_Reload_f(void);
342 void R_Shadow_ValidateCvars(void);
343 static void R_Shadow_MakeTextures(void);
345 // VorteX: custom editor light sprites
346 #define EDLIGHTSPRSIZE 8
347 cachepic_t *r_editlights_sprcursor;
348 cachepic_t *r_editlights_sprlight;
349 cachepic_t *r_editlights_sprnoshadowlight;
350 cachepic_t *r_editlights_sprcubemaplight;
351 cachepic_t *r_editlights_sprcubemapnoshadowlight;
352 cachepic_t *r_editlights_sprselection;
354 void R_Shadow_SetShadowMode(void)
356 r_shadow_shadowmapmaxsize = bound(1, r_shadow_shadowmapping_maxsize.integer, 2048);
357 r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer != 0;
358 r_shadow_shadowmapfilterquality = r_shadow_shadowmapping_filterquality.integer;
359 r_shadow_shadowmaptexturetype = r_shadow_shadowmapping_texturetype.integer;
360 r_shadow_shadowmapprecision = r_shadow_shadowmapping_precision.integer;
361 r_shadow_shadowmapborder = bound(0, r_shadow_shadowmapping_bordersize.integer, 16);
362 r_shadow_shadowmaplod = -1;
363 r_shadow_shadowmapsize = 0;
364 r_shadow_shadowmapsampler = false;
365 r_shadow_shadowmappcf = 0;
366 r_shadow_shadowmode = 0;
367 if(r_shadow_shadowmapping.integer)
369 if(r_shadow_shadowmapfilterquality < 0)
371 if(strstr(gl_vendor, "NVIDIA"))
373 r_shadow_shadowmapsampler = gl_support_arb_shadow;
374 r_shadow_shadowmappcf = 1;
376 else if(gl_support_amd_texture_texture4 || gl_support_arb_texture_gather)
377 r_shadow_shadowmappcf = 1;
378 else if(strstr(gl_vendor, "ATI"))
379 r_shadow_shadowmappcf = 1;
381 r_shadow_shadowmapsampler = gl_support_arb_shadow;
385 switch (r_shadow_shadowmapfilterquality)
388 r_shadow_shadowmapsampler = gl_support_arb_shadow;
391 r_shadow_shadowmapsampler = gl_support_arb_shadow;
392 r_shadow_shadowmappcf = 1;
395 r_shadow_shadowmappcf = 1;
398 r_shadow_shadowmappcf = 2;
402 r_shadow_shadowmode = r_shadow_shadowmaptexturetype;
403 if(r_shadow_shadowmode <= 0)
405 if((gl_support_amd_texture_texture4 || gl_support_arb_texture_gather) && r_shadow_shadowmappcf && !r_shadow_shadowmapsampler)
406 r_shadow_shadowmode = 1;
407 else if(gl_texturerectangle)
408 r_shadow_shadowmode = 2;
410 r_shadow_shadowmode = 1;
415 void R_Shadow_FreeShadowMaps(void)
419 R_Shadow_SetShadowMode();
421 if (r_shadow_fborectangle)
422 qglDeleteFramebuffersEXT(1, &r_shadow_fborectangle);
423 r_shadow_fborectangle = 0;
427 qglDeleteFramebuffersEXT(1, &r_shadow_fbo2d);
430 for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
431 if (r_shadow_fbocubeside[i][0])
432 qglDeleteFramebuffersEXT(6, r_shadow_fbocubeside[i]);
433 memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
436 if (r_shadow_shadowmaprectangletexture)
437 R_FreeTexture(r_shadow_shadowmaprectangletexture);
438 r_shadow_shadowmaprectangletexture = NULL;
440 if (r_shadow_shadowmap2dtexture)
441 R_FreeTexture(r_shadow_shadowmap2dtexture);
442 r_shadow_shadowmap2dtexture = NULL;
444 for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
445 if (r_shadow_shadowmapcubetexture[i])
446 R_FreeTexture(r_shadow_shadowmapcubetexture[i]);
447 memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
449 if (r_shadow_shadowmapvsdcttexture)
450 R_FreeTexture(r_shadow_shadowmapvsdcttexture);
451 r_shadow_shadowmapvsdcttexture = NULL;
456 void r_shadow_start(void)
458 // allocate vertex processing arrays
460 r_shadow_attenuationgradienttexture = NULL;
461 r_shadow_attenuation2dtexture = NULL;
462 r_shadow_attenuation3dtexture = NULL;
463 r_shadow_shadowmode = 0;
464 r_shadow_shadowmaprectangletexture = NULL;
465 r_shadow_shadowmap2dtexture = NULL;
466 memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
467 r_shadow_shadowmapvsdcttexture = NULL;
468 r_shadow_shadowmapmaxsize = 0;
469 r_shadow_shadowmapsize = 0;
470 r_shadow_shadowmaplod = 0;
471 r_shadow_shadowmapfilterquality = 0;
472 r_shadow_shadowmaptexturetype = 0;
473 r_shadow_shadowmapprecision = 0;
474 r_shadow_shadowmapvsdct = false;
475 r_shadow_shadowmapsampler = false;
476 r_shadow_shadowmappcf = 0;
477 r_shadow_fborectangle = 0;
479 memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
481 R_Shadow_FreeShadowMaps();
483 r_shadow_texturepool = NULL;
484 r_shadow_filters_texturepool = NULL;
485 R_Shadow_ValidateCvars();
486 R_Shadow_MakeTextures();
487 maxshadowtriangles = 0;
488 shadowelements = NULL;
489 maxshadowvertices = 0;
490 shadowvertex3f = NULL;
498 shadowmarklist = NULL;
503 shadowsideslist = NULL;
504 r_shadow_buffer_numleafpvsbytes = 0;
505 r_shadow_buffer_visitingleafpvs = NULL;
506 r_shadow_buffer_leafpvs = NULL;
507 r_shadow_buffer_leaflist = NULL;
508 r_shadow_buffer_numsurfacepvsbytes = 0;
509 r_shadow_buffer_surfacepvs = NULL;
510 r_shadow_buffer_surfacelist = NULL;
511 r_shadow_buffer_numshadowtrispvsbytes = 0;
512 r_shadow_buffer_shadowtrispvs = NULL;
513 r_shadow_buffer_numlighttrispvsbytes = 0;
514 r_shadow_buffer_lighttrispvs = NULL;
517 void r_shadow_shutdown(void)
520 R_Shadow_UncompileWorldLights();
522 R_Shadow_FreeShadowMaps();
526 r_shadow_attenuationgradienttexture = NULL;
527 r_shadow_attenuation2dtexture = NULL;
528 r_shadow_attenuation3dtexture = NULL;
529 R_FreeTexturePool(&r_shadow_texturepool);
530 R_FreeTexturePool(&r_shadow_filters_texturepool);
531 maxshadowtriangles = 0;
533 Mem_Free(shadowelements);
534 shadowelements = NULL;
536 Mem_Free(shadowvertex3f);
537 shadowvertex3f = NULL;
540 Mem_Free(vertexupdate);
543 Mem_Free(vertexremap);
549 Mem_Free(shadowmark);
552 Mem_Free(shadowmarklist);
553 shadowmarklist = NULL;
558 Mem_Free(shadowsides);
561 Mem_Free(shadowsideslist);
562 shadowsideslist = NULL;
563 r_shadow_buffer_numleafpvsbytes = 0;
564 if (r_shadow_buffer_visitingleafpvs)
565 Mem_Free(r_shadow_buffer_visitingleafpvs);
566 r_shadow_buffer_visitingleafpvs = NULL;
567 if (r_shadow_buffer_leafpvs)
568 Mem_Free(r_shadow_buffer_leafpvs);
569 r_shadow_buffer_leafpvs = NULL;
570 if (r_shadow_buffer_leaflist)
571 Mem_Free(r_shadow_buffer_leaflist);
572 r_shadow_buffer_leaflist = NULL;
573 r_shadow_buffer_numsurfacepvsbytes = 0;
574 if (r_shadow_buffer_surfacepvs)
575 Mem_Free(r_shadow_buffer_surfacepvs);
576 r_shadow_buffer_surfacepvs = NULL;
577 if (r_shadow_buffer_surfacelist)
578 Mem_Free(r_shadow_buffer_surfacelist);
579 r_shadow_buffer_surfacelist = NULL;
580 r_shadow_buffer_numshadowtrispvsbytes = 0;
581 if (r_shadow_buffer_shadowtrispvs)
582 Mem_Free(r_shadow_buffer_shadowtrispvs);
583 r_shadow_buffer_numlighttrispvsbytes = 0;
584 if (r_shadow_buffer_lighttrispvs)
585 Mem_Free(r_shadow_buffer_lighttrispvs);
588 void r_shadow_newmap(void)
590 if (cl.worldmodel && strncmp(cl.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
591 R_Shadow_EditLights_Reload_f();
594 void R_Shadow_Help_f(void)
597 "Documentation on r_shadow system:\n"
599 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
600 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
601 "r_shadow_debuglight : render only this light number (-1 = all)\n"
602 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
603 "r_shadow_gloss2intensity : brightness of forced gloss\n"
604 "r_shadow_glossintensity : brightness of textured gloss\n"
605 "r_shadow_lightattenuationlinearscale : used to generate attenuation texture\n"
606 "r_shadow_lightattenuationdividebias : used to generate attenuation texture\n"
607 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
608 "r_shadow_lightradiusscale : scale rendering radius of all lights\n"
609 "r_shadow_portallight : use portal visibility for static light precomputation\n"
610 "r_shadow_projectdistance : shadow volume projection distance\n"
611 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
612 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
613 "r_shadow_realtime_world : use high quality world lighting mode\n"
614 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
615 "r_shadow_realtime_world_shadows : cast shadows from world lights\n"
616 "r_shadow_realtime_world_compile : compile surface/visibility information\n"
617 "r_shadow_realtime_world_compileshadow : compile shadow geometry\n"
618 "r_shadow_scissor : use scissor optimization\n"
619 "r_shadow_polygonfactor : nudge shadow volumes closer/further\n"
620 "r_shadow_polygonoffset : nudge shadow volumes closer/further\n"
621 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
622 "r_showlighting : useful for performance testing; bright = slow!\n"
623 "r_showshadowvolumes : useful for performance testing; bright = slow!\n"
625 "r_shadow_help : this help\n"
629 void R_Shadow_Init(void)
631 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
632 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
633 Cvar_RegisterVariable(&r_shadow_usenormalmap);
634 Cvar_RegisterVariable(&r_shadow_debuglight);
635 Cvar_RegisterVariable(&r_shadow_gloss);
636 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
637 Cvar_RegisterVariable(&r_shadow_glossintensity);
638 Cvar_RegisterVariable(&r_shadow_glossexponent);
639 Cvar_RegisterVariable(&r_shadow_glossexact);
640 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
641 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
642 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
643 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
644 Cvar_RegisterVariable(&r_shadow_portallight);
645 Cvar_RegisterVariable(&r_shadow_projectdistance);
646 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
647 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
648 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
649 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
650 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
651 Cvar_RegisterVariable(&r_shadow_realtime_world);
652 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
653 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
654 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
655 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
656 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
657 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
658 Cvar_RegisterVariable(&r_shadow_scissor);
659 Cvar_RegisterVariable(&r_shadow_shadowmapping);
660 Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
661 Cvar_RegisterVariable(&r_shadow_shadowmapping_texturetype);
662 Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
663 Cvar_RegisterVariable(&r_shadow_shadowmapping_precision);
664 Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
665 Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
666 Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
667 Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
668 Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
669 Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
670 Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
671 Cvar_RegisterVariable(&r_shadow_culltriangles);
672 Cvar_RegisterVariable(&r_shadow_polygonfactor);
673 Cvar_RegisterVariable(&r_shadow_polygonoffset);
674 Cvar_RegisterVariable(&r_shadow_texture3d);
675 Cvar_RegisterVariable(&r_coronas);
676 Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
677 Cvar_RegisterVariable(&r_coronas_occlusionquery);
678 Cvar_RegisterVariable(&gl_flashblend);
679 Cvar_RegisterVariable(&gl_ext_separatestencil);
680 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
681 if (gamemode == GAME_TENEBRAE)
683 Cvar_SetValue("r_shadow_gloss", 2);
684 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
686 Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f, "prints documentation on console commands and variables used by realtime lighting and shadowing system");
687 R_Shadow_EditLights_Init();
688 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
689 maxshadowtriangles = 0;
690 shadowelements = NULL;
691 maxshadowvertices = 0;
692 shadowvertex3f = NULL;
700 shadowmarklist = NULL;
705 shadowsideslist = NULL;
706 r_shadow_buffer_numleafpvsbytes = 0;
707 r_shadow_buffer_visitingleafpvs = NULL;
708 r_shadow_buffer_leafpvs = NULL;
709 r_shadow_buffer_leaflist = NULL;
710 r_shadow_buffer_numsurfacepvsbytes = 0;
711 r_shadow_buffer_surfacepvs = NULL;
712 r_shadow_buffer_surfacelist = NULL;
713 r_shadow_buffer_shadowtrispvs = NULL;
714 r_shadow_buffer_lighttrispvs = NULL;
715 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
718 matrix4x4_t matrix_attenuationxyz =
721 {0.5, 0.0, 0.0, 0.5},
722 {0.0, 0.5, 0.0, 0.5},
723 {0.0, 0.0, 0.5, 0.5},
728 matrix4x4_t matrix_attenuationz =
731 {0.0, 0.0, 0.5, 0.5},
732 {0.0, 0.0, 0.0, 0.5},
733 {0.0, 0.0, 0.0, 0.5},
738 void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles, int vertscale, int triscale)
740 numvertices = ((numvertices + 255) & ~255) * vertscale;
741 numtriangles = ((numtriangles + 255) & ~255) * triscale;
742 // make sure shadowelements is big enough for this volume
743 if (maxshadowtriangles < numtriangles)
745 maxshadowtriangles = numtriangles;
747 Mem_Free(shadowelements);
748 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[3]));
750 // make sure shadowvertex3f is big enough for this volume
751 if (maxshadowvertices < numvertices)
753 maxshadowvertices = numvertices;
755 Mem_Free(shadowvertex3f);
756 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[3]));
760 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
762 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
763 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
764 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
765 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
766 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
768 if (r_shadow_buffer_visitingleafpvs)
769 Mem_Free(r_shadow_buffer_visitingleafpvs);
770 if (r_shadow_buffer_leafpvs)
771 Mem_Free(r_shadow_buffer_leafpvs);
772 if (r_shadow_buffer_leaflist)
773 Mem_Free(r_shadow_buffer_leaflist);
774 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
775 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
776 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
777 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
779 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
781 if (r_shadow_buffer_surfacepvs)
782 Mem_Free(r_shadow_buffer_surfacepvs);
783 if (r_shadow_buffer_surfacelist)
784 Mem_Free(r_shadow_buffer_surfacelist);
785 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
786 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
787 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
789 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
791 if (r_shadow_buffer_shadowtrispvs)
792 Mem_Free(r_shadow_buffer_shadowtrispvs);
793 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
794 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
796 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
798 if (r_shadow_buffer_lighttrispvs)
799 Mem_Free(r_shadow_buffer_lighttrispvs);
800 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
801 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
805 void R_Shadow_PrepareShadowMark(int numtris)
807 // make sure shadowmark is big enough for this volume
808 if (maxshadowmark < numtris)
810 maxshadowmark = numtris;
812 Mem_Free(shadowmark);
814 Mem_Free(shadowmarklist);
815 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
816 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
820 // if shadowmarkcount wrapped we clear the array and adjust accordingly
821 if (shadowmarkcount == 0)
824 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
829 void R_Shadow_PrepareShadowSides(int numtris)
831 if (maxshadowsides < numtris)
833 maxshadowsides = numtris;
835 Mem_Free(shadowsides);
837 Mem_Free(shadowsideslist);
838 shadowsides = (unsigned char *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsides));
839 shadowsideslist = (int *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsideslist));
844 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)
847 int outtriangles = 0, outvertices = 0;
850 float ratio, direction[3], projectvector[3];
852 if (projectdirection)
853 VectorScale(projectdirection, projectdistance, projectvector);
855 VectorClear(projectvector);
857 // create the vertices
858 if (projectdirection)
860 for (i = 0;i < numshadowmarktris;i++)
862 element = inelement3i + shadowmarktris[i] * 3;
863 for (j = 0;j < 3;j++)
865 if (vertexupdate[element[j]] != vertexupdatenum)
867 vertexupdate[element[j]] = vertexupdatenum;
868 vertexremap[element[j]] = outvertices;
869 vertex = invertex3f + element[j] * 3;
870 // project one copy of the vertex according to projectvector
871 VectorCopy(vertex, outvertex3f);
872 VectorAdd(vertex, projectvector, (outvertex3f + 3));
881 for (i = 0;i < numshadowmarktris;i++)
883 element = inelement3i + shadowmarktris[i] * 3;
884 for (j = 0;j < 3;j++)
886 if (vertexupdate[element[j]] != vertexupdatenum)
888 vertexupdate[element[j]] = vertexupdatenum;
889 vertexremap[element[j]] = outvertices;
890 vertex = invertex3f + element[j] * 3;
891 // project one copy of the vertex to the sphere radius of the light
892 // (FIXME: would projecting it to the light box be better?)
893 VectorSubtract(vertex, projectorigin, direction);
894 ratio = projectdistance / VectorLength(direction);
895 VectorCopy(vertex, outvertex3f);
896 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
904 if (r_shadow_frontsidecasting.integer)
906 for (i = 0;i < numshadowmarktris;i++)
908 int remappedelement[3];
910 const int *neighbortriangle;
912 markindex = shadowmarktris[i] * 3;
913 element = inelement3i + markindex;
914 neighbortriangle = inneighbor3i + markindex;
915 // output the front and back triangles
916 outelement3i[0] = vertexremap[element[0]];
917 outelement3i[1] = vertexremap[element[1]];
918 outelement3i[2] = vertexremap[element[2]];
919 outelement3i[3] = vertexremap[element[2]] + 1;
920 outelement3i[4] = vertexremap[element[1]] + 1;
921 outelement3i[5] = vertexremap[element[0]] + 1;
925 // output the sides (facing outward from this triangle)
926 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
928 remappedelement[0] = vertexremap[element[0]];
929 remappedelement[1] = vertexremap[element[1]];
930 outelement3i[0] = remappedelement[1];
931 outelement3i[1] = remappedelement[0];
932 outelement3i[2] = remappedelement[0] + 1;
933 outelement3i[3] = remappedelement[1];
934 outelement3i[4] = remappedelement[0] + 1;
935 outelement3i[5] = remappedelement[1] + 1;
940 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
942 remappedelement[1] = vertexremap[element[1]];
943 remappedelement[2] = vertexremap[element[2]];
944 outelement3i[0] = remappedelement[2];
945 outelement3i[1] = remappedelement[1];
946 outelement3i[2] = remappedelement[1] + 1;
947 outelement3i[3] = remappedelement[2];
948 outelement3i[4] = remappedelement[1] + 1;
949 outelement3i[5] = remappedelement[2] + 1;
954 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
956 remappedelement[0] = vertexremap[element[0]];
957 remappedelement[2] = vertexremap[element[2]];
958 outelement3i[0] = remappedelement[0];
959 outelement3i[1] = remappedelement[2];
960 outelement3i[2] = remappedelement[2] + 1;
961 outelement3i[3] = remappedelement[0];
962 outelement3i[4] = remappedelement[2] + 1;
963 outelement3i[5] = remappedelement[0] + 1;
972 for (i = 0;i < numshadowmarktris;i++)
974 int remappedelement[3];
976 const int *neighbortriangle;
978 markindex = shadowmarktris[i] * 3;
979 element = inelement3i + markindex;
980 neighbortriangle = inneighbor3i + markindex;
981 // output the front and back triangles
982 outelement3i[0] = vertexremap[element[2]];
983 outelement3i[1] = vertexremap[element[1]];
984 outelement3i[2] = vertexremap[element[0]];
985 outelement3i[3] = vertexremap[element[0]] + 1;
986 outelement3i[4] = vertexremap[element[1]] + 1;
987 outelement3i[5] = vertexremap[element[2]] + 1;
991 // output the sides (facing outward from this triangle)
992 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
994 remappedelement[0] = vertexremap[element[0]];
995 remappedelement[1] = vertexremap[element[1]];
996 outelement3i[0] = remappedelement[0];
997 outelement3i[1] = remappedelement[1];
998 outelement3i[2] = remappedelement[1] + 1;
999 outelement3i[3] = remappedelement[0];
1000 outelement3i[4] = remappedelement[1] + 1;
1001 outelement3i[5] = remappedelement[0] + 1;
1006 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1008 remappedelement[1] = vertexremap[element[1]];
1009 remappedelement[2] = vertexremap[element[2]];
1010 outelement3i[0] = remappedelement[1];
1011 outelement3i[1] = remappedelement[2];
1012 outelement3i[2] = remappedelement[2] + 1;
1013 outelement3i[3] = remappedelement[1];
1014 outelement3i[4] = remappedelement[2] + 1;
1015 outelement3i[5] = remappedelement[1] + 1;
1020 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1022 remappedelement[0] = vertexremap[element[0]];
1023 remappedelement[2] = vertexremap[element[2]];
1024 outelement3i[0] = remappedelement[2];
1025 outelement3i[1] = remappedelement[0];
1026 outelement3i[2] = remappedelement[0] + 1;
1027 outelement3i[3] = remappedelement[2];
1028 outelement3i[4] = remappedelement[0] + 1;
1029 outelement3i[5] = remappedelement[2] + 1;
1037 *outnumvertices = outvertices;
1038 return outtriangles;
1041 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)
1044 int outtriangles = 0, outvertices = 0;
1046 const float *vertex;
1047 float ratio, direction[3], projectvector[3];
1050 if (projectdirection)
1051 VectorScale(projectdirection, projectdistance, projectvector);
1053 VectorClear(projectvector);
1055 for (i = 0;i < numshadowmarktris;i++)
1057 int remappedelement[3];
1059 const int *neighbortriangle;
1061 markindex = shadowmarktris[i] * 3;
1062 neighbortriangle = inneighbor3i + markindex;
1063 side[0] = shadowmark[neighbortriangle[0]] == shadowmarkcount;
1064 side[1] = shadowmark[neighbortriangle[1]] == shadowmarkcount;
1065 side[2] = shadowmark[neighbortriangle[2]] == shadowmarkcount;
1066 if (side[0] + side[1] + side[2] == 0)
1070 element = inelement3i + markindex;
1072 // create the vertices
1073 for (j = 0;j < 3;j++)
1075 if (side[j] + side[j+1] == 0)
1078 if (vertexupdate[k] != vertexupdatenum)
1080 vertexupdate[k] = vertexupdatenum;
1081 vertexremap[k] = outvertices;
1082 vertex = invertex3f + k * 3;
1083 VectorCopy(vertex, outvertex3f);
1084 if (projectdirection)
1086 // project one copy of the vertex according to projectvector
1087 VectorAdd(vertex, projectvector, (outvertex3f + 3));
1091 // project one copy of the vertex to the sphere radius of the light
1092 // (FIXME: would projecting it to the light box be better?)
1093 VectorSubtract(vertex, projectorigin, direction);
1094 ratio = projectdistance / VectorLength(direction);
1095 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1102 // output the sides (facing outward from this triangle)
1105 remappedelement[0] = vertexremap[element[0]];
1106 remappedelement[1] = vertexremap[element[1]];
1107 outelement3i[0] = remappedelement[1];
1108 outelement3i[1] = remappedelement[0];
1109 outelement3i[2] = remappedelement[0] + 1;
1110 outelement3i[3] = remappedelement[1];
1111 outelement3i[4] = remappedelement[0] + 1;
1112 outelement3i[5] = remappedelement[1] + 1;
1119 remappedelement[1] = vertexremap[element[1]];
1120 remappedelement[2] = vertexremap[element[2]];
1121 outelement3i[0] = remappedelement[2];
1122 outelement3i[1] = remappedelement[1];
1123 outelement3i[2] = remappedelement[1] + 1;
1124 outelement3i[3] = remappedelement[2];
1125 outelement3i[4] = remappedelement[1] + 1;
1126 outelement3i[5] = remappedelement[2] + 1;
1133 remappedelement[0] = vertexremap[element[0]];
1134 remappedelement[2] = vertexremap[element[2]];
1135 outelement3i[0] = remappedelement[0];
1136 outelement3i[1] = remappedelement[2];
1137 outelement3i[2] = remappedelement[2] + 1;
1138 outelement3i[3] = remappedelement[0];
1139 outelement3i[4] = remappedelement[2] + 1;
1140 outelement3i[5] = remappedelement[0] + 1;
1147 *outnumvertices = outvertices;
1148 return outtriangles;
1151 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)
1157 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1159 tend = firsttriangle + numtris;
1160 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1162 // surface box entirely inside light box, no box cull
1163 if (projectdirection)
1165 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1167 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
1168 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1169 shadowmarklist[numshadowmark++] = t;
1174 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1175 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
1176 shadowmarklist[numshadowmark++] = t;
1181 // surface box not entirely inside light box, cull each triangle
1182 if (projectdirection)
1184 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1186 v[0] = invertex3f + e[0] * 3;
1187 v[1] = invertex3f + e[1] * 3;
1188 v[2] = invertex3f + e[2] * 3;
1189 TriangleNormal(v[0], v[1], v[2], normal);
1190 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1191 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1192 shadowmarklist[numshadowmark++] = t;
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 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1203 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1204 shadowmarklist[numshadowmark++] = t;
1210 qboolean R_Shadow_UseZPass(vec3_t mins, vec3_t maxs)
1215 if (r_shadow_compilingrtlight || !r_shadow_frontsidecasting.integer || !r_shadow_usezpassifpossible.integer)
1217 // check if the shadow volume intersects the near plane
1219 // a ray between the eye and light origin may intersect the caster,
1220 // indicating that the shadow may touch the eye location, however we must
1221 // test the near plane (a polygon), not merely the eye location, so it is
1222 // easiest to enlarge the caster bounding shape slightly for this.
1228 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)
1230 int i, tris, outverts;
1231 if (projectdistance < 0.1)
1233 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
1236 if (!numverts || !nummarktris)
1238 // make sure shadowelements is big enough for this volume
1239 if (maxshadowtriangles < nummarktris*8 || maxshadowvertices < numverts*2)
1240 R_Shadow_ResizeShadowArrays(numverts, nummarktris, 2, 8);
1242 if (maxvertexupdate < numverts)
1244 maxvertexupdate = numverts;
1246 Mem_Free(vertexupdate);
1248 Mem_Free(vertexremap);
1249 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1250 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1251 vertexupdatenum = 0;
1254 if (vertexupdatenum == 0)
1256 vertexupdatenum = 1;
1257 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
1258 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
1261 for (i = 0;i < nummarktris;i++)
1262 shadowmark[marktris[i]] = shadowmarkcount;
1264 if (r_shadow_compilingrtlight)
1266 // if we're compiling an rtlight, capture the mesh
1267 //tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1268 //Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zpass, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1269 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1270 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zfail, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1274 // decide which type of shadow to generate and set stencil mode
1275 R_Shadow_RenderMode_StencilShadowVolumes(R_Shadow_UseZPass(trismins, trismaxs));
1276 // generate the sides or a solid volume, depending on type
1277 if (r_shadow_rendermode >= R_SHADOW_RENDERMODE_ZPASS_STENCIL && r_shadow_rendermode <= R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE)
1278 tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1280 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1281 r_refdef.stats.lights_dynamicshadowtriangles += tris;
1282 r_refdef.stats.lights_shadowtriangles += tris;
1284 R_Mesh_VertexPointer(shadowvertex3f, 0, 0);
1285 GL_LockArrays(0, outverts);
1286 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
1288 // increment stencil if frontface is infront of depthbuffer
1289 GL_CullFace(r_refdef.view.cullface_front);
1290 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1291 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1292 // decrement stencil if backface is infront of depthbuffer
1293 GL_CullFace(r_refdef.view.cullface_back);
1294 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1296 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
1298 // decrement stencil if backface is behind depthbuffer
1299 GL_CullFace(r_refdef.view.cullface_front);
1300 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1301 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1302 // increment stencil if frontface is behind depthbuffer
1303 GL_CullFace(r_refdef.view.cullface_back);
1304 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1306 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1307 GL_LockArrays(0, 0);
1312 int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias)
1314 // p1, p2, p3 are in the cubemap's local coordinate system
1315 // bias = border/(size - border)
1318 float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1319 dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2),
1320 dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3);
1321 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1323 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1324 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1325 | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1326 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1328 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1329 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1330 | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1332 dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1333 dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2),
1334 dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3);
1335 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1337 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1338 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1339 | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1340 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1342 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1343 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1344 | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1346 dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1347 dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2),
1348 dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3);
1349 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1351 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1352 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1353 | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1354 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1356 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1357 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1358 | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1363 int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
1365 // p is in the cubemap's local coordinate system
1366 // bias = border/(size - border)
1367 float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn);
1368 float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn);
1369 float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn);
1371 if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
1372 if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
1373 if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
1374 if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
1375 if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
1376 if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
1380 void 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)
1389 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1391 bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
1392 tend = firsttriangle + numtris;
1393 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1395 // surface box entirely inside light box, no box cull
1396 if (projectdirection)
1398 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1400 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1401 TriangleNormal(v[0], v[1], v[2], normal);
1402 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1404 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1405 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1406 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;
1407 shadowsides[numshadowsides] = mask;
1408 shadowsideslist[numshadowsides++] = t;
1414 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1416 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1417 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]))
1419 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1420 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1421 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;
1422 shadowsides[numshadowsides] = mask;
1423 shadowsideslist[numshadowsides++] = t;
1430 // surface box not entirely inside light box, cull each triangle
1431 if (projectdirection)
1433 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1435 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1436 TriangleNormal(v[0], v[1], v[2], normal);
1437 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1438 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1440 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1441 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1442 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;
1443 shadowsides[numshadowsides] = mask;
1444 shadowsideslist[numshadowsides++] = t;
1450 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1452 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1453 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1454 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1456 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1457 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1458 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;
1459 shadowsides[numshadowsides] = mask;
1460 shadowsideslist[numshadowsides++] = t;
1467 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)
1469 int i, j, outtriangles = 0;
1470 int *outelement3i[6];
1471 if (!numverts || !numsidetris || !r_shadow_compilingrtlight)
1473 outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5];
1474 // make sure shadowelements is big enough for this mesh
1475 if (maxshadowtriangles < outtriangles)
1476 R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1);
1478 // compute the offset and size of the separate index lists for each cubemap side
1480 for (i = 0;i < 6;i++)
1482 outelement3i[i] = shadowelements + outtriangles * 3;
1483 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles;
1484 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i];
1485 outtriangles += sidetotals[i];
1488 // gather up the (sparse) triangles into separate index lists for each cubemap side
1489 for (i = 0;i < numsidetris;i++)
1491 const int *element = elements + sidetris[i] * 3;
1492 for (j = 0;j < 6;j++)
1494 if (sides[i] & (1 << j))
1496 outelement3i[j][0] = element[0];
1497 outelement3i[j][1] = element[1];
1498 outelement3i[j][2] = element[2];
1499 outelement3i[j] += 3;
1504 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, outtriangles, shadowelements);
1507 static void R_Shadow_MakeTextures_MakeCorona(void)
1511 unsigned char pixels[32][32][4];
1512 for (y = 0;y < 32;y++)
1514 dy = (y - 15.5f) * (1.0f / 16.0f);
1515 for (x = 0;x < 32;x++)
1517 dx = (x - 15.5f) * (1.0f / 16.0f);
1518 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1519 a = bound(0, a, 255);
1520 pixels[y][x][0] = a;
1521 pixels[y][x][1] = a;
1522 pixels[y][x][2] = a;
1523 pixels[y][x][3] = 255;
1526 r_shadow_lightcorona = R_LoadTexture2D(r_shadow_texturepool, "lightcorona", 32, 32, &pixels[0][0][0], TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_FORCELINEAR, NULL);
1529 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1531 float dist = sqrt(x*x+y*y+z*z);
1532 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1533 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1534 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1537 static void R_Shadow_MakeTextures(void)
1540 float intensity, dist;
1542 R_FreeTexturePool(&r_shadow_texturepool);
1543 r_shadow_texturepool = R_AllocTexturePool();
1544 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1545 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1546 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1547 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1548 for (x = 0;x <= ATTENTABLESIZE;x++)
1550 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1551 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1552 r_shadow_attentable[x] = bound(0, intensity, 1);
1554 // 1D gradient texture
1555 for (x = 0;x < ATTEN1DSIZE;x++)
1556 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1557 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);
1558 // 2D circle texture
1559 for (y = 0;y < ATTEN2DSIZE;y++)
1560 for (x = 0;x < ATTEN2DSIZE;x++)
1561 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);
1562 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);
1563 // 3D sphere texture
1564 if (r_shadow_texture3d.integer && gl_texture3d)
1566 for (z = 0;z < ATTEN3DSIZE;z++)
1567 for (y = 0;y < ATTEN3DSIZE;y++)
1568 for (x = 0;x < ATTEN3DSIZE;x++)
1569 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));
1570 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);
1573 r_shadow_attenuation3dtexture = NULL;
1576 R_Shadow_MakeTextures_MakeCorona();
1578 // Editor light sprites
1579 r_editlights_sprcursor = Draw_CachePic ("gfx/editlights/cursor");
1580 r_editlights_sprlight = Draw_CachePic ("gfx/editlights/light");
1581 r_editlights_sprnoshadowlight = Draw_CachePic ("gfx/editlights/noshadow");
1582 r_editlights_sprcubemaplight = Draw_CachePic ("gfx/editlights/cubemaplight");
1583 r_editlights_sprcubemapnoshadowlight = Draw_CachePic ("gfx/editlights/cubemapnoshadowlight");
1584 r_editlights_sprselection = Draw_CachePic ("gfx/editlights/selection");
1587 void R_Shadow_ValidateCvars(void)
1589 if (r_shadow_texture3d.integer && !gl_texture3d)
1590 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1591 if (gl_ext_separatestencil.integer && !gl_support_separatestencil)
1592 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
1593 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
1594 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1597 void R_Shadow_RenderMode_Begin(void)
1601 R_Shadow_ValidateCvars();
1603 if (!r_shadow_attenuation2dtexture
1604 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1605 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1606 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1607 R_Shadow_MakeTextures();
1610 R_Mesh_ColorPointer(NULL, 0, 0);
1611 R_Mesh_ResetTextureState();
1612 GL_BlendFunc(GL_ONE, GL_ZERO);
1613 GL_DepthRange(0, 1);
1614 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1616 GL_DepthMask(false);
1617 GL_Color(0, 0, 0, 1);
1618 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1620 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1622 if (gl_ext_separatestencil.integer)
1624 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
1625 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
1627 else if (gl_ext_stenciltwoside.integer)
1629 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
1630 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
1634 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
1635 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
1638 if (r_glsl.integer && gl_support_fragment_shader)
1639 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1640 else if (gl_dot3arb && gl_texturecubemap && r_textureunits.integer >= 2 && gl_combine.integer && gl_stencil)
1641 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_DOT3;
1643 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1646 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
1647 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
1648 r_shadow_drawbuffer = drawbuffer;
1649 r_shadow_readbuffer = readbuffer;
1650 r_shadow_cullface = r_refdef.view.cullface_back;
1653 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
1655 rsurface.rtlight = rtlight;
1658 void R_Shadow_RenderMode_Reset(void)
1661 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE)
1663 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1665 if (gl_support_ext_framebuffer_object)
1667 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);CHECKGLERROR
1669 qglDrawBuffer(r_shadow_drawbuffer);CHECKGLERROR
1670 qglReadBuffer(r_shadow_readbuffer);CHECKGLERROR
1671 R_SetViewport(&r_refdef.view.viewport);
1672 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
1673 R_Mesh_ColorPointer(NULL, 0, 0);
1674 R_Mesh_ResetTextureState();
1675 GL_DepthRange(0, 1);
1677 GL_DepthMask(false);
1678 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1679 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1680 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
1681 qglStencilMask(~0);CHECKGLERROR
1682 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
1683 qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
1684 r_refdef.view.cullface_back = r_shadow_cullface;
1685 GL_CullFace(r_refdef.view.cullface_back);
1686 GL_Color(1, 1, 1, 1);
1687 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
1688 GL_BlendFunc(GL_ONE, GL_ZERO);
1689 R_SetupGenericShader(false);
1690 r_shadow_usingshadowmaprect = false;
1691 r_shadow_usingshadowmapcube = false;
1692 r_shadow_usingshadowmap2d = false;
1696 void R_Shadow_ClearStencil(void)
1699 GL_Clear(GL_STENCIL_BUFFER_BIT);
1700 r_refdef.stats.lights_clears++;
1703 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
1705 r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
1706 if (r_shadow_rendermode == mode)
1709 R_Shadow_RenderMode_Reset();
1710 GL_ColorMask(0, 0, 0, 0);
1711 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1712 R_SetupDepthOrShadowShader();
1713 qglDepthFunc(GL_LESS);CHECKGLERROR
1714 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1715 r_shadow_rendermode = mode;
1720 case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
1721 GL_CullFace(GL_NONE);
1722 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1723 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1725 case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
1726 GL_CullFace(GL_NONE);
1727 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1728 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1730 case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
1731 GL_CullFace(GL_NONE);
1732 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1733 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
1734 qglStencilMask(~0);CHECKGLERROR
1735 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1736 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
1737 qglStencilMask(~0);CHECKGLERROR
1738 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1740 case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
1741 GL_CullFace(GL_NONE);
1742 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1743 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
1744 qglStencilMask(~0);CHECKGLERROR
1745 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1746 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
1747 qglStencilMask(~0);CHECKGLERROR
1748 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1753 static void R_Shadow_MakeVSDCT(void)
1755 // maps to a 2x3 texture rectangle with normalized coordinates
1760 // stores abs(dir.xy), offset.xy/2.5
1761 unsigned char data[4*6] =
1763 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
1764 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
1765 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
1766 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
1767 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
1768 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
1770 r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_ALWAYSPRECACHE | TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, NULL);
1773 void R_Shadow_RenderMode_ShadowMap(int side, qboolean clear, int size)
1778 float nearclip, farclip, bias;
1779 r_viewport_t viewport;
1781 maxsize = r_shadow_shadowmapmaxsize;
1782 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
1784 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
1785 r_shadow_shadowmap_parameters[2] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
1786 r_shadow_shadowmap_parameters[3] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
1787 r_shadow_shadowmapside = side;
1788 r_shadow_shadowmapsize = size;
1789 if (r_shadow_shadowmode == 1)
1791 // complex unrolled cube approach (more flexible)
1792 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
1793 R_Shadow_MakeVSDCT();
1794 if (!r_shadow_shadowmap2dtexture)
1797 int w = maxsize*2, h = gl_support_arb_texture_non_power_of_two ? maxsize*3 : maxsize*4;
1798 r_shadow_shadowmap2dtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "shadowmap", w, h, r_shadow_shadowmapprecision, r_shadow_shadowmapsampler);
1799 qglGenFramebuffersEXT(1, &r_shadow_fbo2d);CHECKGLERROR
1800 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbo2d);CHECKGLERROR
1801 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_shadowmap2dtexture), 0);CHECKGLERROR
1805 R_Shadow_RenderMode_Reset();
1806 if (r_shadow_shadowmap2dtexture)
1808 // render depth into the fbo, do not render color at all
1809 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbo2d);CHECKGLERROR
1810 qglDrawBuffer(GL_NONE);CHECKGLERROR
1811 qglReadBuffer(GL_NONE);CHECKGLERROR
1812 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
1813 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
1815 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
1816 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
1818 R_SetupDepthOrShadowShader();
1822 R_SetupShowDepthShader();
1823 qglClearColor(1,1,1,1);CHECKGLERROR
1825 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
1826 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
1827 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
1828 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
1829 r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
1830 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
1832 else if (r_shadow_shadowmode == 2)
1834 // complex unrolled cube approach (more flexible)
1835 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
1836 R_Shadow_MakeVSDCT();
1837 if (!r_shadow_shadowmaprectangletexture)
1840 r_shadow_shadowmaprectangletexture = R_LoadTextureShadowMapRectangle(r_shadow_texturepool, "shadowmap", maxsize*2, maxsize*3, r_shadow_shadowmapprecision, r_shadow_shadowmapsampler);
1841 qglGenFramebuffersEXT(1, &r_shadow_fborectangle);CHECKGLERROR
1842 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fborectangle);CHECKGLERROR
1843 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, R_GetTexture(r_shadow_shadowmaprectangletexture), 0);CHECKGLERROR
1847 R_Shadow_RenderMode_Reset();
1848 if (r_shadow_shadowmaprectangletexture)
1850 // render depth into the fbo, do not render color at all
1851 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fborectangle);CHECKGLERROR
1852 qglDrawBuffer(GL_NONE);CHECKGLERROR
1853 qglReadBuffer(GL_NONE);CHECKGLERROR
1854 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
1855 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
1857 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
1858 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
1860 R_SetupDepthOrShadowShader();
1864 R_SetupShowDepthShader();
1865 qglClearColor(1,1,1,1);CHECKGLERROR
1867 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
1868 r_shadow_shadowmap_texturescale[0] = 1.0f;
1869 r_shadow_shadowmap_texturescale[1] = 1.0f;
1870 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
1871 r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
1872 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE;
1874 else if (r_shadow_shadowmode == 3)
1876 // simple cube approach
1877 if (!r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod])
1880 r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod] = R_LoadTextureShadowMapCube(r_shadow_texturepool, "shadowmapcube", size, r_shadow_shadowmapprecision, r_shadow_shadowmapsampler);
1881 qglGenFramebuffersEXT(6, r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR
1882 for (i = 0;i < 6;i++)
1884 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbocubeside[r_shadow_shadowmaplod][i]);CHECKGLERROR
1885 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
1890 R_Shadow_RenderMode_Reset();
1891 if (r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod])
1893 // render depth into the fbo, do not render color at all
1894 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbocubeside[r_shadow_shadowmaplod][side]);CHECKGLERROR
1895 qglDrawBuffer(GL_NONE);CHECKGLERROR
1896 qglReadBuffer(GL_NONE);CHECKGLERROR
1897 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
1898 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
1900 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
1901 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
1903 R_SetupDepthOrShadowShader();
1907 R_SetupShowDepthShader();
1908 qglClearColor(1,1,1,1);CHECKGLERROR
1910 R_Viewport_InitCubeSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, nearclip, farclip, NULL);
1911 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]);
1912 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureWidth(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]);
1913 r_shadow_shadowmap_parameters[0] = 1.0f;
1914 r_shadow_shadowmap_parameters[1] = 1.0f;
1915 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE;
1918 R_SetViewport(&viewport);
1919 GL_PolygonOffset(0, 0);
1920 if(r_shadow_shadowmode >= 1 && r_shadow_shadowmode <= 2)
1922 static qboolean cullfront[6] = { false, true, false, true, true, false };
1923 if(cullfront[side]) r_refdef.view.cullface_back = r_refdef.view.cullface_front;
1925 GL_CullFace(r_refdef.view.cullface_back);
1926 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
1929 qglClearDepth(1);CHECKGLERROR
1932 qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
1936 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
1939 R_Shadow_RenderMode_Reset();
1940 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1943 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1947 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1948 // only draw light where this geometry was already rendered AND the
1949 // stencil is 128 (values other than this mean shadow)
1950 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
1952 r_shadow_rendermode = r_shadow_lightingrendermode;
1953 // do global setup needed for the chosen lighting mode
1954 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
1956 R_Mesh_TexBindCubeMap(GL20TU_CUBE, R_GetTexture(rsurface.rtlight->currentcubemap)); // light filter
1957 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
1961 if (r_shadow_shadowmode == 1)
1963 r_shadow_usingshadowmap2d = true;
1964 R_Mesh_TexBind(GL20TU_SHADOWMAP2D, R_GetTexture(r_shadow_shadowmap2dtexture));
1967 else if (r_shadow_shadowmode == 2)
1969 r_shadow_usingshadowmaprect = true;
1970 R_Mesh_TexBindRectangle(GL20TU_SHADOWMAPRECT, R_GetTexture(r_shadow_shadowmaprectangletexture));
1973 else if (r_shadow_shadowmode == 3)
1975 r_shadow_usingshadowmapcube = true;
1976 R_Mesh_TexBindCubeMap(GL20TU_SHADOWMAPCUBE, R_GetTexture(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]));
1980 if (r_shadow_shadowmapvsdct && (r_shadow_usingshadowmap2d || r_shadow_usingshadowmaprect))
1982 R_Mesh_TexBindCubeMap(GL20TU_CUBEPROJECTION, R_GetTexture(r_shadow_shadowmapvsdcttexture));
1987 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_VERTEX)
1988 R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
1989 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1993 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
1996 R_Shadow_RenderMode_Reset();
1997 GL_BlendFunc(GL_ONE, GL_ONE);
1998 GL_DepthRange(0, 1);
1999 GL_DepthTest(r_showshadowvolumes.integer < 2);
2000 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
2001 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2002 GL_CullFace(GL_NONE);
2003 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
2006 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
2009 R_Shadow_RenderMode_Reset();
2010 GL_BlendFunc(GL_ONE, GL_ONE);
2011 GL_DepthRange(0, 1);
2012 GL_DepthTest(r_showlighting.integer < 2);
2013 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2016 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2020 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2021 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
2023 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2026 void R_Shadow_RenderMode_End(void)
2029 R_Shadow_RenderMode_Reset();
2030 R_Shadow_RenderMode_ActiveLight(NULL);
2032 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2033 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2036 int bboxedges[12][2] =
2055 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2057 int i, ix1, iy1, ix2, iy2;
2058 float x1, y1, x2, y2;
2060 float vertex[20][3];
2069 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2070 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2071 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2072 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2074 if (!r_shadow_scissor.integer)
2077 // if view is inside the light box, just say yes it's visible
2078 if (BoxesOverlap(r_refdef.view.origin, r_refdef.view.origin, mins, maxs))
2081 x1 = y1 = x2 = y2 = 0;
2083 // transform all corners that are infront of the nearclip plane
2084 VectorNegate(r_refdef.view.frustum[4].normal, plane4f);
2085 plane4f[3] = r_refdef.view.frustum[4].dist;
2087 for (i = 0;i < 8;i++)
2089 Vector4Set(corner[i], (i & 1) ? maxs[0] : mins[0], (i & 2) ? maxs[1] : mins[1], (i & 4) ? maxs[2] : mins[2], 1);
2090 dist[i] = DotProduct4(corner[i], plane4f);
2091 sign[i] = dist[i] > 0;
2094 VectorCopy(corner[i], vertex[numvertices]);
2098 // if some points are behind the nearclip, add clipped edge points to make
2099 // sure that the scissor boundary is complete
2100 if (numvertices > 0 && numvertices < 8)
2102 // add clipped edge points
2103 for (i = 0;i < 12;i++)
2105 j = bboxedges[i][0];
2106 k = bboxedges[i][1];
2107 if (sign[j] != sign[k])
2109 f = dist[j] / (dist[j] - dist[k]);
2110 VectorLerp(corner[j], f, corner[k], vertex[numvertices]);
2116 // if we have no points to check, the light is behind the view plane
2120 // if we have some points to transform, check what screen area is covered
2121 x1 = y1 = x2 = y2 = 0;
2123 //Con_Printf("%i vertices to transform...\n", numvertices);
2124 for (i = 0;i < numvertices;i++)
2126 VectorCopy(vertex[i], v);
2127 R_Viewport_TransformToScreen(&r_refdef.view.viewport, v, v2);
2128 //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]);
2131 if (x1 > v2[0]) x1 = v2[0];
2132 if (x2 < v2[0]) x2 = v2[0];
2133 if (y1 > v2[1]) y1 = v2[1];
2134 if (y2 < v2[1]) y2 = v2[1];
2143 // now convert the scissor rectangle to integer screen coordinates
2144 ix1 = (int)(x1 - 1.0f);
2145 iy1 = vid.height - (int)(y2 - 1.0f);
2146 ix2 = (int)(x2 + 1.0f);
2147 iy2 = vid.height - (int)(y1 + 1.0f);
2148 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
2150 // clamp it to the screen
2151 if (ix1 < r_refdef.view.viewport.x) ix1 = r_refdef.view.viewport.x;
2152 if (iy1 < r_refdef.view.viewport.y) iy1 = r_refdef.view.viewport.y;
2153 if (ix2 > r_refdef.view.viewport.x + r_refdef.view.viewport.width) ix2 = r_refdef.view.viewport.x + r_refdef.view.viewport.width;
2154 if (iy2 > r_refdef.view.viewport.y + r_refdef.view.viewport.height) iy2 = r_refdef.view.viewport.y + r_refdef.view.viewport.height;
2156 // if it is inside out, it's not visible
2157 if (ix2 <= ix1 || iy2 <= iy1)
2160 // the light area is visible, set up the scissor rectangle
2161 r_shadow_lightscissor[0] = ix1;
2162 r_shadow_lightscissor[1] = iy1;
2163 r_shadow_lightscissor[2] = ix2 - ix1;
2164 r_shadow_lightscissor[3] = iy2 - iy1;
2166 r_refdef.stats.lights_scissored++;
2170 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, int numtriangles, const int *element3i, const float *diffusecolor, const float *ambientcolor)
2172 float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
2173 float *normal3f = rsurface.normal3f + 3 * firstvertex;
2174 float *color4f = rsurface.array_color4f + 4 * firstvertex;
2175 float dist, dot, distintensity, shadeintensity, v[3], n[3];
2176 if (r_textureunits.integer >= 3)
2178 if (VectorLength2(diffusecolor) > 0)
2180 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2182 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2183 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2184 if ((dot = DotProduct(n, v)) < 0)
2186 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2187 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
2190 VectorCopy(ambientcolor, color4f);
2191 if (r_refdef.fogenabled)
2194 f = FogPoint_Model(vertex3f);
2195 VectorScale(color4f, f, color4f);
2202 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2204 VectorCopy(ambientcolor, color4f);
2205 if (r_refdef.fogenabled)
2208 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2209 f = FogPoint_Model(vertex3f);
2210 VectorScale(color4f, f, color4f);
2216 else if (r_textureunits.integer >= 2)
2218 if (VectorLength2(diffusecolor) > 0)
2220 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2222 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2223 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2225 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2226 if ((dot = DotProduct(n, v)) < 0)
2228 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2229 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2230 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2231 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2235 color4f[0] = ambientcolor[0] * distintensity;
2236 color4f[1] = ambientcolor[1] * distintensity;
2237 color4f[2] = ambientcolor[2] * distintensity;
2239 if (r_refdef.fogenabled)
2242 f = FogPoint_Model(vertex3f);
2243 VectorScale(color4f, f, color4f);
2247 VectorClear(color4f);
2253 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2255 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2256 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2258 color4f[0] = ambientcolor[0] * distintensity;
2259 color4f[1] = ambientcolor[1] * distintensity;
2260 color4f[2] = ambientcolor[2] * distintensity;
2261 if (r_refdef.fogenabled)
2264 f = FogPoint_Model(vertex3f);
2265 VectorScale(color4f, f, color4f);
2269 VectorClear(color4f);
2276 if (VectorLength2(diffusecolor) > 0)
2278 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2280 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2281 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2283 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2284 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2285 if ((dot = DotProduct(n, v)) < 0)
2287 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2288 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2289 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2290 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2294 color4f[0] = ambientcolor[0] * distintensity;
2295 color4f[1] = ambientcolor[1] * distintensity;
2296 color4f[2] = ambientcolor[2] * distintensity;
2298 if (r_refdef.fogenabled)
2301 f = FogPoint_Model(vertex3f);
2302 VectorScale(color4f, f, color4f);
2306 VectorClear(color4f);
2312 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2314 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2315 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2317 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2318 color4f[0] = ambientcolor[0] * distintensity;
2319 color4f[1] = ambientcolor[1] * distintensity;
2320 color4f[2] = ambientcolor[2] * distintensity;
2321 if (r_refdef.fogenabled)
2324 f = FogPoint_Model(vertex3f);
2325 VectorScale(color4f, f, color4f);
2329 VectorClear(color4f);
2336 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
2338 static void R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
2341 float *out3f = rsurface.array_texcoord3f + 3 * firstvertex;
2342 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
2343 const float *svector3f = rsurface.svector3f + 3 * firstvertex;
2344 const float *tvector3f = rsurface.tvector3f + 3 * firstvertex;
2345 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
2347 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
2349 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
2350 // the cubemap normalizes this for us
2351 out3f[0] = DotProduct(svector3f, lightdir);
2352 out3f[1] = DotProduct(tvector3f, lightdir);
2353 out3f[2] = DotProduct(normal3f, lightdir);
2357 static void R_Shadow_GenTexCoords_Specular_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
2360 float *out3f = rsurface.array_texcoord3f + 3 * firstvertex;
2361 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
2362 const float *svector3f = rsurface.svector3f + 3 * firstvertex;
2363 const float *tvector3f = rsurface.tvector3f + 3 * firstvertex;
2364 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
2365 float lightdir[3], eyedir[3], halfdir[3];
2366 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
2368 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
2369 VectorNormalize(lightdir);
2370 VectorSubtract(rsurface.modelorg, vertex3f, eyedir);
2371 VectorNormalize(eyedir);
2372 VectorAdd(lightdir, eyedir, halfdir);
2373 // the cubemap normalizes this for us
2374 out3f[0] = DotProduct(svector3f, halfdir);
2375 out3f[1] = DotProduct(tvector3f, halfdir);
2376 out3f[2] = DotProduct(normal3f, halfdir);
2380 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)
2382 // used to display how many times a surface is lit for level design purposes
2383 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2386 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)
2388 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2389 R_SetupSurfaceShader(lightcolorbase, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT);
2390 if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND))
2391 R_Mesh_ColorPointer(rsurface.modellightmapcolor4f, rsurface.modellightmapcolor4f_bufferobject, rsurface.modellightmapcolor4f_bufferoffset);
2393 R_Mesh_ColorPointer(NULL, 0, 0);
2394 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
2395 R_Mesh_TexMatrix(1, &rsurface.texture->currentbackgroundtexmatrix);
2396 R_Mesh_TexBind(GL20TU_NORMAL, R_GetTexture(rsurface.texture->currentskinframe->nmap));
2397 R_Mesh_TexBind(GL20TU_COLOR, R_GetTexture(rsurface.texture->basetexture));
2398 R_Mesh_TexBind(GL20TU_GLOSS, R_GetTexture(rsurface.texture->glosstexture));
2399 if (rsurface.texture->backgroundcurrentskinframe)
2401 R_Mesh_TexBind(GL20TU_SECONDARY_NORMAL, R_GetTexture(rsurface.texture->backgroundcurrentskinframe->nmap));
2402 R_Mesh_TexBind(GL20TU_SECONDARY_COLOR, R_GetTexture(rsurface.texture->backgroundbasetexture));
2403 R_Mesh_TexBind(GL20TU_SECONDARY_GLOSS, R_GetTexture(rsurface.texture->backgroundglosstexture));
2404 R_Mesh_TexBind(GL20TU_SECONDARY_GLOW, R_GetTexture(rsurface.texture->backgroundcurrentskinframe->glow));
2406 //R_Mesh_TexBindCubeMap(GL20TU_CUBE, R_GetTexture(rsurface.rtlight->currentcubemap));
2407 R_Mesh_TexBind(GL20TU_FOGMASK, R_GetTexture(r_texture_fogattenuation));
2408 if(rsurface.texture->colormapping)
2410 R_Mesh_TexBind(GL20TU_PANTS, R_GetTexture(rsurface.texture->currentskinframe->pants));
2411 R_Mesh_TexBind(GL20TU_SHIRT, R_GetTexture(rsurface.texture->currentskinframe->shirt));
2413 R_Mesh_TexBind(GL20TU_ATTENUATION, R_GetTexture(r_shadow_attenuationgradienttexture));
2414 R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
2415 R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset);
2416 R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset);
2417 R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset);
2418 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2420 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2422 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2423 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2425 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
2429 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)
2431 // shared final code for all the dot3 layers
2433 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2434 for (renders = 0;renders < 64 && (r > 0 || g > 0 || b > 0);renders++, r--, g--, b--)
2436 GL_Color(bound(0, r, 1), bound(0, g, 1), bound(0, b, 1), 1);
2437 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2441 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)
2444 // colorscale accounts for how much we multiply the brightness
2447 // mult is how many times the final pass of the lighting will be
2448 // performed to get more brightness than otherwise possible.
2450 // Limit mult to 64 for sanity sake.
2452 if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
2454 // 3 3D combine path (Geforce3, Radeon 8500)
2455 memset(&m, 0, sizeof(m));
2456 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2457 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2458 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2459 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2460 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2461 m.tex[1] = R_GetTexture(basetexture);
2462 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
2463 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
2464 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
2465 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
2466 m.texcubemap[2] = R_GetTexture(rsurface.rtlight->currentcubemap);
2467 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2468 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2469 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2470 m.texmatrix[2] = rsurface.entitytolight;
2471 GL_BlendFunc(GL_ONE, GL_ONE);
2473 else if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
2475 // 2 3D combine path (Geforce3, original Radeon)
2476 memset(&m, 0, sizeof(m));
2477 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2478 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2479 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2480 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2481 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2482 m.tex[1] = R_GetTexture(basetexture);
2483 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
2484 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
2485 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
2486 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
2487 GL_BlendFunc(GL_ONE, GL_ONE);
2489 else if (r_textureunits.integer >= 4 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2491 // 4 2D combine path (Geforce3, Radeon 8500)
2492 memset(&m, 0, sizeof(m));
2493 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2494 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2495 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2496 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2497 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2498 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2499 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2500 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2501 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2502 m.texmatrix[1] = rsurface.entitytoattenuationz;
2503 m.tex[2] = R_GetTexture(basetexture);
2504 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
2505 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
2506 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
2507 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
2508 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2510 m.texcubemap[3] = R_GetTexture(rsurface.rtlight->currentcubemap);
2511 m.pointer_texcoord3f[3] = rsurface.vertex3f;
2512 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
2513 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
2514 m.texmatrix[3] = rsurface.entitytolight;
2516 GL_BlendFunc(GL_ONE, GL_ONE);
2518 else if (r_textureunits.integer >= 3 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
2520 // 3 2D combine path (Geforce3, original Radeon)
2521 memset(&m, 0, sizeof(m));
2522 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2523 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2524 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2525 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2526 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2527 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2528 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2529 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2530 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2531 m.texmatrix[1] = rsurface.entitytoattenuationz;
2532 m.tex[2] = R_GetTexture(basetexture);
2533 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
2534 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
2535 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
2536 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
2537 GL_BlendFunc(GL_ONE, GL_ONE);
2541 // 2/2/2 2D combine path (any dot3 card)
2542 memset(&m, 0, sizeof(m));
2543 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2544 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2545 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2546 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2547 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2548 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2549 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2550 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2551 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2552 m.texmatrix[1] = rsurface.entitytoattenuationz;
2553 R_Mesh_TextureState(&m);
2554 GL_ColorMask(0,0,0,1);
2555 GL_BlendFunc(GL_ONE, GL_ZERO);
2556 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2559 memset(&m, 0, sizeof(m));
2560 m.tex[0] = R_GetTexture(basetexture);
2561 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2562 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2563 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2564 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2565 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2567 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2568 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2569 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2570 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2571 m.texmatrix[1] = rsurface.entitytolight;
2573 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2575 // this final code is shared
2576 R_Mesh_TextureState(&m);
2577 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);
2580 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)
2583 // colorscale accounts for how much we multiply the brightness
2586 // mult is how many times the final pass of the lighting will be
2587 // performed to get more brightness than otherwise possible.
2589 // Limit mult to 64 for sanity sake.
2591 // generate normalization cubemap texcoords
2592 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
2593 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
2595 // 3/2 3D combine path (Geforce3, Radeon 8500)
2596 memset(&m, 0, sizeof(m));
2597 m.tex[0] = R_GetTexture(normalmaptexture);
2598 m.texcombinergb[0] = GL_REPLACE;
2599 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2600 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2601 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2602 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2603 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2604 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2605 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2606 m.pointer_texcoord_bufferobject[1] = 0;
2607 m.pointer_texcoord_bufferoffset[1] = 0;
2608 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
2609 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2610 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2611 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2612 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
2613 R_Mesh_TextureState(&m);
2614 GL_ColorMask(0,0,0,1);
2615 GL_BlendFunc(GL_ONE, GL_ZERO);
2616 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2619 memset(&m, 0, sizeof(m));
2620 m.tex[0] = R_GetTexture(basetexture);
2621 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2622 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2623 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2624 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2625 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2627 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2628 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2629 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2630 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2631 m.texmatrix[1] = rsurface.entitytolight;
2633 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2635 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2637 // 1/2/2 3D combine path (original Radeon)
2638 memset(&m, 0, sizeof(m));
2639 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2640 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2641 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2642 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2643 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2644 R_Mesh_TextureState(&m);
2645 GL_ColorMask(0,0,0,1);
2646 GL_BlendFunc(GL_ONE, GL_ZERO);
2647 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2650 memset(&m, 0, sizeof(m));
2651 m.tex[0] = R_GetTexture(normalmaptexture);
2652 m.texcombinergb[0] = GL_REPLACE;
2653 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2654 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2655 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2656 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2657 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2658 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2659 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2660 m.pointer_texcoord_bufferobject[1] = 0;
2661 m.pointer_texcoord_bufferoffset[1] = 0;
2662 R_Mesh_TextureState(&m);
2663 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2664 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2667 memset(&m, 0, sizeof(m));
2668 m.tex[0] = R_GetTexture(basetexture);
2669 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2670 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2671 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2672 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2673 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2675 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
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.entitytolight;
2681 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2683 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
2685 // 2/2 3D combine path (original Radeon)
2686 memset(&m, 0, sizeof(m));
2687 m.tex[0] = R_GetTexture(normalmaptexture);
2688 m.texcombinergb[0] = GL_REPLACE;
2689 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2690 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2691 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2692 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2693 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2694 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2695 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2696 m.pointer_texcoord_bufferobject[1] = 0;
2697 m.pointer_texcoord_bufferoffset[1] = 0;
2698 R_Mesh_TextureState(&m);
2699 GL_ColorMask(0,0,0,1);
2700 GL_BlendFunc(GL_ONE, GL_ZERO);
2701 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2704 memset(&m, 0, sizeof(m));
2705 m.tex[0] = R_GetTexture(basetexture);
2706 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2707 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2708 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2709 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2710 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2711 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2712 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2713 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2714 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2715 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2717 else if (r_textureunits.integer >= 4)
2719 // 4/2 2D combine path (Geforce3, Radeon 8500)
2720 memset(&m, 0, sizeof(m));
2721 m.tex[0] = R_GetTexture(normalmaptexture);
2722 m.texcombinergb[0] = GL_REPLACE;
2723 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2724 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2725 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2726 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2727 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2728 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2729 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2730 m.pointer_texcoord_bufferobject[1] = 0;
2731 m.pointer_texcoord_bufferoffset[1] = 0;
2732 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2733 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2734 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2735 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2736 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
2737 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
2738 m.pointer_texcoord3f[3] = rsurface.vertex3f;
2739 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
2740 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
2741 m.texmatrix[3] = rsurface.entitytoattenuationz;
2742 R_Mesh_TextureState(&m);
2743 GL_ColorMask(0,0,0,1);
2744 GL_BlendFunc(GL_ONE, GL_ZERO);
2745 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2748 memset(&m, 0, sizeof(m));
2749 m.tex[0] = R_GetTexture(basetexture);
2750 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2751 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2752 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2753 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2754 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2756 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2757 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2758 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2759 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2760 m.texmatrix[1] = rsurface.entitytolight;
2762 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2766 // 2/2/2 2D combine path (any dot3 card)
2767 memset(&m, 0, sizeof(m));
2768 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2769 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2770 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2771 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2772 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2773 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2774 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2775 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2776 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2777 m.texmatrix[1] = rsurface.entitytoattenuationz;
2778 R_Mesh_TextureState(&m);
2779 GL_ColorMask(0,0,0,1);
2780 GL_BlendFunc(GL_ONE, GL_ZERO);
2781 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2784 memset(&m, 0, sizeof(m));
2785 m.tex[0] = R_GetTexture(normalmaptexture);
2786 m.texcombinergb[0] = GL_REPLACE;
2787 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2788 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2789 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2790 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2791 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2792 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2793 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2794 m.pointer_texcoord_bufferobject[1] = 0;
2795 m.pointer_texcoord_bufferoffset[1] = 0;
2796 R_Mesh_TextureState(&m);
2797 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2798 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2801 memset(&m, 0, sizeof(m));
2802 m.tex[0] = R_GetTexture(basetexture);
2803 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2804 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2805 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2806 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2807 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2809 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2810 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2811 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2812 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2813 m.texmatrix[1] = rsurface.entitytolight;
2815 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2817 // this final code is shared
2818 R_Mesh_TextureState(&m);
2819 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);
2822 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)
2824 float glossexponent;
2826 // FIXME: detect blendsquare!
2827 //if (!gl_support_blendsquare)
2830 // generate normalization cubemap texcoords
2831 R_Shadow_GenTexCoords_Specular_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
2832 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2834 // 2/0/0/1/2 3D combine blendsquare path
2835 memset(&m, 0, sizeof(m));
2836 m.tex[0] = R_GetTexture(normalmaptexture);
2837 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2838 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2839 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2840 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2841 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2842 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2843 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2844 m.pointer_texcoord_bufferobject[1] = 0;
2845 m.pointer_texcoord_bufferoffset[1] = 0;
2846 R_Mesh_TextureState(&m);
2847 GL_ColorMask(0,0,0,1);
2848 // this squares the result
2849 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2850 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2852 // second and third pass
2853 R_Mesh_ResetTextureState();
2854 // square alpha in framebuffer a few times to make it shiny
2855 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2856 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2857 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2860 memset(&m, 0, sizeof(m));
2861 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2862 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2863 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2864 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2865 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2866 R_Mesh_TextureState(&m);
2867 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2868 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2871 memset(&m, 0, sizeof(m));
2872 m.tex[0] = R_GetTexture(glosstexture);
2873 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2874 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2875 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2876 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2877 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2879 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2880 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2881 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2882 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2883 m.texmatrix[1] = rsurface.entitytolight;
2885 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2887 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
2889 // 2/0/0/2 3D combine blendsquare path
2890 memset(&m, 0, sizeof(m));
2891 m.tex[0] = R_GetTexture(normalmaptexture);
2892 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2893 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2894 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2895 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2896 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2897 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2898 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2899 m.pointer_texcoord_bufferobject[1] = 0;
2900 m.pointer_texcoord_bufferoffset[1] = 0;
2901 R_Mesh_TextureState(&m);
2902 GL_ColorMask(0,0,0,1);
2903 // this squares the result
2904 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2905 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2907 // second and third pass
2908 R_Mesh_ResetTextureState();
2909 // square alpha in framebuffer a few times to make it shiny
2910 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2911 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2912 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2915 memset(&m, 0, sizeof(m));
2916 m.tex[0] = R_GetTexture(glosstexture);
2917 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2918 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2919 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2920 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2921 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2922 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2923 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2924 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2925 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2926 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2930 // 2/0/0/2/2 2D combine blendsquare path
2931 memset(&m, 0, sizeof(m));
2932 m.tex[0] = R_GetTexture(normalmaptexture);
2933 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2934 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2935 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2936 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2937 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2938 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2939 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2940 m.pointer_texcoord_bufferobject[1] = 0;
2941 m.pointer_texcoord_bufferoffset[1] = 0;
2942 R_Mesh_TextureState(&m);
2943 GL_ColorMask(0,0,0,1);
2944 // this squares the result
2945 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2946 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2948 // second and third pass
2949 R_Mesh_ResetTextureState();
2950 // square alpha in framebuffer a few times to make it shiny
2951 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2952 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2953 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2956 memset(&m, 0, sizeof(m));
2957 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2958 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2959 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2960 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2961 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2962 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2963 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2964 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2965 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2966 m.texmatrix[1] = rsurface.entitytoattenuationz;
2967 R_Mesh_TextureState(&m);
2968 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2969 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2972 memset(&m, 0, sizeof(m));
2973 m.tex[0] = R_GetTexture(glosstexture);
2974 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2975 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2976 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2977 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2978 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2980 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2981 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2982 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2983 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2984 m.texmatrix[1] = rsurface.entitytolight;
2986 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2988 // this final code is shared
2989 R_Mesh_TextureState(&m);
2990 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);
2993 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)
2995 // ARB path (any Geforce, any Radeon)
2996 qboolean doambient = ambientscale > 0;
2997 qboolean dodiffuse = diffusescale > 0;
2998 qboolean dospecular = specularscale > 0;
2999 if (!doambient && !dodiffuse && !dospecular)
3001 R_Mesh_ColorPointer(NULL, 0, 0);
3003 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, basetexture, ambientscale * r_refdef.view.colorscale);
3005 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, basetexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
3009 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorpants, pantstexture, ambientscale * r_refdef.view.colorscale);
3011 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorpants, pantstexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
3016 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorshirt, shirttexture, ambientscale * r_refdef.view.colorscale);
3018 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorshirt, shirttexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
3021 R_Shadow_RenderLighting_Light_Dot3_SpecularPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, glosstexture, normalmaptexture, specularscale * r_refdef.view.colorscale);
3024 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
3031 int newnumtriangles;
3035 int maxtriangles = 4096;
3036 int newelements[4096*3];
3037 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, numtriangles, element3i, diffusecolor2, ambientcolor2);
3038 for (renders = 0;renders < 64;renders++)
3043 newnumtriangles = 0;
3045 // due to low fillrate on the cards this vertex lighting path is
3046 // designed for, we manually cull all triangles that do not
3047 // contain a lit vertex
3048 // this builds batches of triangles from multiple surfaces and
3049 // renders them at once
3050 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
3052 if (VectorLength2(rsurface.array_color4f + e[0] * 4) + VectorLength2(rsurface.array_color4f + e[1] * 4) + VectorLength2(rsurface.array_color4f + e[2] * 4) >= 0.01)
3054 if (newnumtriangles)
3056 newfirstvertex = min(newfirstvertex, e[0]);
3057 newlastvertex = max(newlastvertex, e[0]);
3061 newfirstvertex = e[0];
3062 newlastvertex = e[0];
3064 newfirstvertex = min(newfirstvertex, e[1]);
3065 newlastvertex = max(newlastvertex, e[1]);
3066 newfirstvertex = min(newfirstvertex, e[2]);
3067 newlastvertex = max(newlastvertex, e[2]);
3073 if (newnumtriangles >= maxtriangles)
3075 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
3076 newnumtriangles = 0;
3082 if (newnumtriangles >= 1)
3084 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
3087 // if we couldn't find any lit triangles, exit early
3090 // now reduce the intensity for the next overbright pass
3091 // we have to clamp to 0 here incase the drivers have improper
3092 // handling of negative colors
3093 // (some old drivers even have improper handling of >1 color)
3095 for (i = 0, c = rsurface.array_color4f + 4 * firstvertex;i < numvertices;i++, c += 4)
3097 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
3099 c[0] = max(0, c[0] - 1);
3100 c[1] = max(0, c[1] - 1);
3101 c[2] = max(0, c[2] - 1);
3113 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)
3115 // OpenGL 1.1 path (anything)
3116 float ambientcolorbase[3], diffusecolorbase[3];
3117 float ambientcolorpants[3], diffusecolorpants[3];
3118 float ambientcolorshirt[3], diffusecolorshirt[3];
3120 VectorScale(lightcolorbase, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorbase);
3121 VectorScale(lightcolorbase, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorbase);
3122 VectorScale(lightcolorpants, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorpants);
3123 VectorScale(lightcolorpants, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorpants);
3124 VectorScale(lightcolorshirt, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorshirt);
3125 VectorScale(lightcolorshirt, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorshirt);
3126 memset(&m, 0, sizeof(m));
3127 m.tex[0] = R_GetTexture(basetexture);
3128 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3129 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3130 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3131 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3132 if (r_textureunits.integer >= 2)
3135 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
3136 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
3137 m.pointer_texcoord3f[1] = rsurface.vertex3f;
3138 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
3139 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
3140 if (r_textureunits.integer >= 3)
3142 // Voodoo4 or Kyro (or Geforce3/Radeon with gl_combine off)
3143 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
3144 m.texmatrix[2] = rsurface.entitytoattenuationz;
3145 m.pointer_texcoord3f[2] = rsurface.vertex3f;
3146 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
3147 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
3150 R_Mesh_TextureState(&m);
3151 //R_Mesh_TexBind(0, R_GetTexture(basetexture));
3152 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorbase, ambientcolorbase);
3155 R_Mesh_TexBind(0, R_GetTexture(pantstexture));
3156 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorpants, ambientcolorpants);
3160 R_Mesh_TexBind(0, R_GetTexture(shirttexture));
3161 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorshirt, ambientcolorshirt);
3165 extern cvar_t gl_lightmaps;
3166 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)
3168 float ambientscale, diffusescale, specularscale;
3169 vec3_t lightcolorbase, lightcolorpants, lightcolorshirt;
3171 // calculate colors to render this texture with
3172 lightcolorbase[0] = rsurface.rtlight->currentcolor[0] * rsurface.texture->dlightcolor[0];
3173 lightcolorbase[1] = rsurface.rtlight->currentcolor[1] * rsurface.texture->dlightcolor[1];
3174 lightcolorbase[2] = rsurface.rtlight->currentcolor[2] * rsurface.texture->dlightcolor[2];
3175 ambientscale = rsurface.rtlight->ambientscale;
3176 diffusescale = rsurface.rtlight->diffusescale;
3177 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
3178 if (!r_shadow_usenormalmap.integer)
3180 ambientscale += 1.0f * diffusescale;
3184 if ((ambientscale + diffusescale) * VectorLength2(lightcolorbase) + specularscale * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
3186 RSurf_SetupDepthAndCulling();
3187 nmap = rsurface.texture->currentskinframe->nmap;
3188 if (gl_lightmaps.integer)
3189 nmap = r_texture_blanknormalmap;
3190 if (rsurface.texture->colormapping && !gl_lightmaps.integer)
3192 qboolean dopants = rsurface.texture->currentskinframe->pants != NULL && VectorLength2(rsurface.colormap_pantscolor) >= (1.0f / 1048576.0f);
3193 qboolean doshirt = rsurface.texture->currentskinframe->shirt != NULL && VectorLength2(rsurface.colormap_shirtcolor) >= (1.0f / 1048576.0f);
3196 lightcolorpants[0] = lightcolorbase[0] * rsurface.colormap_pantscolor[0];
3197 lightcolorpants[1] = lightcolorbase[1] * rsurface.colormap_pantscolor[1];
3198 lightcolorpants[2] = lightcolorbase[2] * rsurface.colormap_pantscolor[2];
3201 VectorClear(lightcolorpants);
3204 lightcolorshirt[0] = lightcolorbase[0] * rsurface.colormap_shirtcolor[0];
3205 lightcolorshirt[1] = lightcolorbase[1] * rsurface.colormap_shirtcolor[1];
3206 lightcolorshirt[2] = lightcolorbase[2] * rsurface.colormap_shirtcolor[2];
3209 VectorClear(lightcolorshirt);
3210 switch (r_shadow_rendermode)
3212 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
3213 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
3214 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);
3216 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
3217 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);
3219 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
3220 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);
3222 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3223 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);
3226 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
3232 switch (r_shadow_rendermode)
3234 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
3235 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
3236 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);
3238 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
3239 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);
3241 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
3242 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);
3244 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3245 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);
3248 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
3254 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)
3256 matrix4x4_t tempmatrix = *matrix;
3257 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
3259 // if this light has been compiled before, free the associated data
3260 R_RTLight_Uncompile(rtlight);
3262 // clear it completely to avoid any lingering data
3263 memset(rtlight, 0, sizeof(*rtlight));
3265 // copy the properties
3266 rtlight->matrix_lighttoworld = tempmatrix;
3267 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
3268 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
3269 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
3270 VectorCopy(color, rtlight->color);
3271 rtlight->cubemapname[0] = 0;
3272 if (cubemapname && cubemapname[0])
3273 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
3274 rtlight->shadow = shadow;
3275 rtlight->corona = corona;
3276 rtlight->style = style;
3277 rtlight->isstatic = isstatic;
3278 rtlight->coronasizescale = coronasizescale;
3279 rtlight->ambientscale = ambientscale;
3280 rtlight->diffusescale = diffusescale;
3281 rtlight->specularscale = specularscale;
3282 rtlight->flags = flags;
3284 // compute derived data
3285 //rtlight->cullradius = rtlight->radius;
3286 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
3287 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3288 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3289 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3290 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3291 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3292 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3295 // compiles rtlight geometry
3296 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
3297 void R_RTLight_Compile(rtlight_t *rtlight)
3300 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
3301 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
3302 entity_render_t *ent = r_refdef.scene.worldentity;
3303 dp_model_t *model = r_refdef.scene.worldmodel;
3304 unsigned char *data;
3307 // compile the light
3308 rtlight->compiled = true;
3309 rtlight->shadowmode = rtlight->shadow ? r_shadow_shadowmode : -1;
3310 rtlight->static_numleafs = 0;
3311 rtlight->static_numleafpvsbytes = 0;
3312 rtlight->static_leaflist = NULL;
3313 rtlight->static_leafpvs = NULL;
3314 rtlight->static_numsurfaces = 0;
3315 rtlight->static_surfacelist = NULL;
3316 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3317 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3318 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3319 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3320 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3321 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3323 if (model && model->GetLightInfo)
3325 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
3326 r_shadow_compilingrtlight = rtlight;
3327 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);
3328 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);
3329 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
3330 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
3331 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3332 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
3333 rtlight->static_numsurfaces = numsurfaces;
3334 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
3335 rtlight->static_numleafs = numleafs;
3336 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
3337 rtlight->static_numleafpvsbytes = numleafpvsbytes;
3338 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
3339 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
3340 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
3341 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
3342 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3343 if (rtlight->static_numsurfaces)
3344 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3345 if (rtlight->static_numleafs)
3346 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3347 if (rtlight->static_numleafpvsbytes)
3348 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3349 if (rtlight->static_numshadowtrispvsbytes)
3350 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3351 if (rtlight->static_numlighttrispvsbytes)
3352 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3353 if (rtlight->shadowmode <= 0)
3355 if (model->CompileShadowVolume && rtlight->shadow)
3356 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3360 if (model->CompileShadowMap && rtlight->shadow)
3361 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3363 // now we're done compiling the rtlight
3364 r_shadow_compilingrtlight = NULL;
3368 // use smallest available cullradius - box radius or light radius
3369 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3370 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3372 shadowzpasstris = 0;
3373 if (rtlight->static_meshchain_shadow_zpass)
3374 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
3375 shadowzpasstris += mesh->numtriangles;
3377 shadowzfailtris = 0;
3378 if (rtlight->static_meshchain_shadow_zfail)
3379 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
3380 shadowzfailtris += mesh->numtriangles;
3383 if (rtlight->static_numlighttrispvsbytes)
3384 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3385 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3389 if (rtlight->static_numlighttrispvsbytes)
3390 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3391 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3394 if (developer.integer >= 10)
3395 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);
3398 void R_RTLight_Uncompile(rtlight_t *rtlight)
3400 if (rtlight->compiled)
3402 if (rtlight->static_meshchain_shadow_zpass)
3403 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
3404 rtlight->static_meshchain_shadow_zpass = NULL;
3405 if (rtlight->static_meshchain_shadow_zfail)
3406 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
3407 rtlight->static_meshchain_shadow_zfail = NULL;
3408 if (rtlight->static_meshchain_shadow_shadowmap)
3409 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
3410 rtlight->static_meshchain_shadow_shadowmap = NULL;
3411 // these allocations are grouped
3412 if (rtlight->static_surfacelist)
3413 Mem_Free(rtlight->static_surfacelist);
3414 rtlight->static_numleafs = 0;
3415 rtlight->static_numleafpvsbytes = 0;
3416 rtlight->static_leaflist = NULL;
3417 rtlight->static_leafpvs = NULL;
3418 rtlight->static_numsurfaces = 0;
3419 rtlight->static_surfacelist = NULL;
3420 rtlight->static_numshadowtrispvsbytes = 0;
3421 rtlight->static_shadowtrispvs = NULL;
3422 rtlight->static_numlighttrispvsbytes = 0;
3423 rtlight->static_lighttrispvs = NULL;
3424 rtlight->compiled = false;
3428 void R_Shadow_UncompileWorldLights(void)
3432 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3433 for (lightindex = 0;lightindex < range;lightindex++)
3435 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3438 R_RTLight_Uncompile(&light->rtlight);
3442 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3446 // reset the count of frustum planes
3447 // see rsurface.rtlight_frustumplanes definition for how much this array
3449 rsurface.rtlight_numfrustumplanes = 0;
3451 // haven't implemented a culling path for ortho rendering
3452 if (!r_refdef.view.useperspective)
3454 // check if the light is on screen and copy the 4 planes if it is
3455 for (i = 0;i < 4;i++)
3456 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3459 for (i = 0;i < 4;i++)
3460 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_refdef.view.frustum[i];
3465 // generate a deformed frustum that includes the light origin, this is
3466 // used to cull shadow casting surfaces that can not possibly cast a
3467 // shadow onto the visible light-receiving surfaces, which can be a
3470 // if the light origin is onscreen the result will be 4 planes exactly
3471 // if the light origin is offscreen on only one axis the result will
3472 // be exactly 5 planes (split-side case)
3473 // if the light origin is offscreen on two axes the result will be
3474 // exactly 4 planes (stretched corner case)
3475 for (i = 0;i < 4;i++)
3477 // quickly reject standard frustum planes that put the light
3478 // origin outside the frustum
3479 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3482 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_refdef.view.frustum[i];
3484 // if all the standard frustum planes were accepted, the light is onscreen
3485 // otherwise we need to generate some more planes below...
3486 if (rsurface.rtlight_numfrustumplanes < 4)
3488 // at least one of the stock frustum planes failed, so we need to
3489 // create one or two custom planes to enclose the light origin
3490 for (i = 0;i < 4;i++)
3492 // create a plane using the view origin and light origin, and a
3493 // single point from the frustum corner set
3494 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3495 VectorNormalize(plane.normal);
3496 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3497 // see if this plane is backwards and flip it if so
3498 for (j = 0;j < 4;j++)
3499 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3503 VectorNegate(plane.normal, plane.normal);
3505 // flipped plane, test again to see if it is now valid
3506 for (j = 0;j < 4;j++)
3507 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3509 // if the plane is still not valid, then it is dividing the
3510 // frustum and has to be rejected
3514 // we have created a valid plane, compute extra info
3515 PlaneClassify(&plane);
3517 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3519 // if we've found 5 frustum planes then we have constructed a
3520 // proper split-side case and do not need to keep searching for
3521 // planes to enclose the light origin
3522 if (rsurface.rtlight_numfrustumplanes == 5)
3530 for (i = 0;i < rsurface.rtlight_numfrustumplanes;i++)
3532 plane = rsurface.rtlight_frustumplanes[i];
3533 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));
3538 // now add the light-space box planes if the light box is rotated, as any
3539 // caster outside the oriented light box is irrelevant (even if it passed
3540 // the worldspace light box, which is axial)
3541 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3543 for (i = 0;i < 6;i++)
3547 v[i >> 1] = (i & 1) ? -1 : 1;
3548 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3549 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3550 plane.dist = VectorNormalizeLength(plane.normal);
3551 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3552 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3558 // add the world-space reduced box planes
3559 for (i = 0;i < 6;i++)
3561 VectorClear(plane.normal);
3562 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3563 plane.dist = (i & 1) ? -rsurface.rtlight_cullmaxs[i >> 1] : rsurface.rtlight_cullmins[i >> 1];
3564 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3573 // reduce all plane distances to tightly fit the rtlight cull box, which
3575 VectorSet(points[0], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
3576 VectorSet(points[1], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
3577 VectorSet(points[2], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
3578 VectorSet(points[3], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
3579 VectorSet(points[4], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
3580 VectorSet(points[5], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
3581 VectorSet(points[6], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
3582 VectorSet(points[7], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
3583 oldnum = rsurface.rtlight_numfrustumplanes;
3584 rsurface.rtlight_numfrustumplanes = 0;
3585 for (j = 0;j < oldnum;j++)
3587 // find the nearest point on the box to this plane
3588 bestdist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[0]);
3589 for (i = 1;i < 8;i++)
3591 dist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[i]);
3592 if (bestdist > dist)
3595 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);
3596 // if the nearest point is near or behind the plane, we want this
3597 // plane, otherwise the plane is useless as it won't cull anything
3598 if (rsurface.rtlight_frustumplanes[j].dist < bestdist + 0.03125)
3600 PlaneClassify(&rsurface.rtlight_frustumplanes[j]);
3601 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = rsurface.rtlight_frustumplanes[j];
3608 void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3612 RSurf_ActiveWorldEntity();
3614 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3617 GL_CullFace(GL_NONE);
3618 mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3619 for (;mesh;mesh = mesh->next)
3621 if (!mesh->sidetotals[r_shadow_shadowmapside])
3623 r_refdef.stats.lights_shadowtriangles += mesh->sidetotals[r_shadow_shadowmapside];
3624 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
3625 R_Mesh_Draw(0, mesh->numverts, mesh->sideoffsets[r_shadow_shadowmapside], mesh->sidetotals[r_shadow_shadowmapside], mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3629 else if (r_refdef.scene.worldentity->model)
3630 r_refdef.scene.worldmodel->DrawShadowMap(r_shadow_shadowmapside, r_refdef.scene.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs);
3632 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3635 void R_Shadow_DrawWorldShadow(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3640 int surfacelistindex;
3641 msurface_t *surface;
3643 RSurf_ActiveWorldEntity();
3645 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3648 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
3649 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
3650 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
3651 for (;mesh;mesh = mesh->next)
3653 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
3654 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
3655 GL_LockArrays(0, mesh->numverts);
3656 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
3658 // increment stencil if frontface is infront of depthbuffer
3659 GL_CullFace(r_refdef.view.cullface_back);
3660 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
3661 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3662 // decrement stencil if backface is infront of depthbuffer
3663 GL_CullFace(r_refdef.view.cullface_front);
3664 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
3666 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
3668 // decrement stencil if backface is behind depthbuffer
3669 GL_CullFace(r_refdef.view.cullface_front);
3670 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
3671 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3672 // increment stencil if frontface is behind depthbuffer
3673 GL_CullFace(r_refdef.view.cullface_back);
3674 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
3676 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3677 GL_LockArrays(0, 0);
3681 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh && r_shadow_culltriangles.integer)
3683 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
3684 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
3686 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
3687 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
3688 if (CHECKPVSBIT(trispvs, t))
3689 shadowmarklist[numshadowmark++] = t;
3691 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);
3693 else if (numsurfaces)
3694 r_refdef.scene.worldmodel->DrawShadowVolume(r_refdef.scene.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs);
3696 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3699 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3701 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3702 vec_t relativeshadowradius;
3703 RSurf_ActiveModelEntity(ent, false, false);
3704 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3705 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3706 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3707 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3708 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3709 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3710 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3711 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3712 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D)
3714 vec3_t radius, worldorigin, lightorigin;
3715 VectorSubtract(ent->maxs, ent->mins, radius);
3716 VectorScale(radius, 0.5f, radius);
3717 VectorAdd(ent->mins, radius, worldorigin);
3718 Matrix4x4_Transform(&rsurface.rtlight->matrix_worldtolight, worldorigin, lightorigin);
3719 if (R_Shadow_CalcSphereSideMask(lightorigin, VectorLength(radius) / relativeshadowradius, r_shadow_shadowmapborder / (float)(r_shadow_shadowmapsize - r_shadow_shadowmapborder)) & (1 << r_shadow_shadowmapside))
3720 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3723 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3724 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3727 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3729 // set up properties for rendering light onto this entity
3730 RSurf_ActiveModelEntity(ent, true, true);
3731 GL_AlphaTest(false);
3732 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3733 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3734 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3735 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3736 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
3737 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
3740 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3742 if (!r_refdef.scene.worldmodel->DrawLight)
3745 // set up properties for rendering light onto this entity
3746 RSurf_ActiveWorldEntity();
3747 GL_AlphaTest(false);
3748 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3749 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3750 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3751 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3752 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
3753 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
3755 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, trispvs);
3757 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3760 void R_Shadow_DrawEntityLight(entity_render_t *ent)
3762 dp_model_t *model = ent->model;
3763 if (!model->DrawLight)
3766 R_Shadow_SetupEntityLight(ent);
3768 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3770 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3773 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
3777 int numleafs, numsurfaces;
3778 int *leaflist, *surfacelist;
3779 unsigned char *leafpvs, *shadowtrispvs, *lighttrispvs;
3780 int numlightentities;
3781 int numlightentities_noselfshadow;
3782 int numshadowentities;
3783 int numshadowentities_noselfshadow;
3784 static entity_render_t *lightentities[MAX_EDICTS];
3785 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3786 static entity_render_t *shadowentities[MAX_EDICTS];
3787 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3788 vec3_t nearestpoint;
3790 qboolean castshadows;
3793 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3794 // skip lights that are basically invisible (color 0 0 0)
3795 if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
3798 // loading is done before visibility checks because loading should happen
3799 // all at once at the start of a level, not when it stalls gameplay.
3800 // (especially important to benchmarks)
3802 if (rtlight->isstatic && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
3804 if (rtlight->compiled)
3805 R_RTLight_Uncompile(rtlight);
3806 R_RTLight_Compile(rtlight);
3810 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
3812 // look up the light style value at this time
3813 f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3814 VectorScale(rtlight->color, f, rtlight->currentcolor);
3816 if (rtlight->selected)
3818 f = 2 + sin(realtime * M_PI * 4.0);
3819 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3823 // if lightstyle is currently off, don't draw the light
3824 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3827 // if the light box is offscreen, skip it
3828 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3831 VectorCopy(rtlight->cullmins, rsurface.rtlight_cullmins);
3832 VectorCopy(rtlight->cullmaxs, rsurface.rtlight_cullmaxs);
3834 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3836 // compiled light, world available and can receive realtime lighting
3837 // retrieve leaf information
3838 numleafs = rtlight->static_numleafs;
3839 leaflist = rtlight->static_leaflist;
3840 leafpvs = rtlight->static_leafpvs;
3841 numsurfaces = rtlight->static_numsurfaces;
3842 surfacelist = rtlight->static_surfacelist;
3843 shadowtrispvs = rtlight->static_shadowtrispvs;
3844 lighttrispvs = rtlight->static_lighttrispvs;
3846 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3848 // dynamic light, world available and can receive realtime lighting
3849 // calculate lit surfaces and leafs
3850 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);
3851 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);
3852 leaflist = r_shadow_buffer_leaflist;
3853 leafpvs = r_shadow_buffer_leafpvs;
3854 surfacelist = r_shadow_buffer_surfacelist;
3855 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3856 lighttrispvs = r_shadow_buffer_lighttrispvs;
3857 // if the reduced leaf bounds are offscreen, skip it
3858 if (R_CullBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
3869 shadowtrispvs = NULL;
3870 lighttrispvs = NULL;
3872 // check if light is illuminating any visible leafs
3875 for (i = 0;i < numleafs;i++)
3876 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3881 // set up a scissor rectangle for this light
3882 if (R_Shadow_ScissorForBBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
3885 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3887 // make a list of lit entities and shadow casting entities
3888 numlightentities = 0;
3889 numlightentities_noselfshadow = 0;
3890 numshadowentities = 0;
3891 numshadowentities_noselfshadow = 0;
3892 // add dynamic entities that are lit by the light
3893 if (r_drawentities.integer)
3895 for (i = 0;i < r_refdef.scene.numentities;i++)
3898 entity_render_t *ent = r_refdef.scene.entities[i];
3900 if (!BoxesOverlap(ent->mins, ent->maxs, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
3902 // skip the object entirely if it is not within the valid
3903 // shadow-casting region (which includes the lit region)
3904 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rsurface.rtlight_numfrustumplanes, rsurface.rtlight_frustumplanes))
3906 if (!(model = ent->model))
3908 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
3910 // this entity wants to receive light, is visible, and is
3911 // inside the light box
3912 // TODO: check if the surfaces in the model can receive light
3913 // so now check if it's in a leaf seen by the light
3914 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))
3916 if (ent->flags & RENDER_NOSELFSHADOW)
3917 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
3919 lightentities[numlightentities++] = ent;
3920 // since it is lit, it probably also casts a shadow...
3921 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3922 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3923 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3925 // note: exterior models without the RENDER_NOSELFSHADOW
3926 // flag still create a RENDER_NOSELFSHADOW shadow but
3927 // are lit normally, this means that they are
3928 // self-shadowing but do not shadow other
3929 // RENDER_NOSELFSHADOW entities such as the gun
3930 // (very weird, but keeps the player shadow off the gun)
3931 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3932 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3934 shadowentities[numshadowentities++] = ent;
3937 else if (ent->flags & RENDER_SHADOW)
3939 // this entity is not receiving light, but may still need to
3941 // TODO: check if the surfaces in the model can cast shadow
3942 // now check if it is in a leaf seen by the light
3943 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))
3945 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3946 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3947 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3949 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3950 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3952 shadowentities[numshadowentities++] = ent;
3958 // return if there's nothing at all to light
3959 if (!numlightentities && !numsurfaces)
3962 // don't let sound skip if going slow
3963 if (r_refdef.scene.extraupdate)
3966 // make this the active rtlight for rendering purposes
3967 R_Shadow_RenderMode_ActiveLight(rtlight);
3968 // count this light in the r_speeds
3969 r_refdef.stats.lights++;
3971 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
3973 // optionally draw visible shape of the shadow volumes
3974 // for performance analysis by level designers
3975 R_Shadow_RenderMode_VisibleShadowVolumes();
3977 R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
3978 for (i = 0;i < numshadowentities;i++)
3979 R_Shadow_DrawEntityShadow(shadowentities[i]);
3980 for (i = 0;i < numshadowentities_noselfshadow;i++)
3981 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3984 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
3986 // optionally draw the illuminated areas
3987 // for performance analysis by level designers
3988 R_Shadow_RenderMode_VisibleLighting(false, false);
3990 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3991 for (i = 0;i < numlightentities;i++)
3992 R_Shadow_DrawEntityLight(lightentities[i]);
3993 for (i = 0;i < numlightentities_noselfshadow;i++)
3994 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3997 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
3999 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
4000 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
4001 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
4002 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
4003 lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
4004 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapping_maxsize.integer);
4006 if (castshadows && r_shadow_shadowmode >= 1 && r_shadow_shadowmode <= 3 && r_glsl.integer && gl_support_fragment_shader)
4011 r_shadow_shadowmaplod = 0;
4012 for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
4013 if ((r_shadow_shadowmapping_maxsize.integer >> i) > lodlinear)
4014 r_shadow_shadowmaplod = i;
4016 size = r_shadow_shadowmode == 3 ? r_shadow_shadowmapping_maxsize.integer >> r_shadow_shadowmaplod : lodlinear;
4017 size = bound(1, size, 2048);
4019 //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
4021 // render shadow casters into 6 sided depth texture
4022 for (side = 0;side < 6;side++)
4024 R_Shadow_RenderMode_ShadowMap(side, true, size);
4026 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs);
4027 for (i = 0;i < numshadowentities;i++)
4028 R_Shadow_DrawEntityShadow(shadowentities[i]);
4031 if (numlightentities_noselfshadow)
4033 // render lighting using the depth texture as shadowmap
4034 // draw lighting in the unmasked areas
4035 R_Shadow_RenderMode_Lighting(false, false, true);
4036 for (i = 0;i < numlightentities_noselfshadow;i++)
4037 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4040 // render shadow casters into 6 sided depth texture
4041 for (side = 0;side < 6;side++)
4043 R_Shadow_RenderMode_ShadowMap(side, false, size);
4044 for (i = 0;i < numshadowentities_noselfshadow;i++)
4045 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
4048 // render lighting using the depth texture as shadowmap
4049 // draw lighting in the unmasked areas
4050 R_Shadow_RenderMode_Lighting(false, false, true);
4051 // draw lighting in the unmasked areas
4053 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4054 for (i = 0;i < numlightentities;i++)
4055 R_Shadow_DrawEntityLight(lightentities[i]);
4057 else if (castshadows && gl_stencil)
4059 // draw stencil shadow volumes to mask off pixels that are in shadow
4060 // so that they won't receive lighting
4061 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
4062 R_Shadow_ClearStencil();
4064 R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
4065 for (i = 0;i < numshadowentities;i++)
4066 R_Shadow_DrawEntityShadow(shadowentities[i]);
4067 if (numlightentities_noselfshadow)
4069 // draw lighting in the unmasked areas
4070 R_Shadow_RenderMode_Lighting(true, false, false);
4071 for (i = 0;i < numlightentities_noselfshadow;i++)
4072 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4074 // optionally draw the illuminated areas
4075 // for performance analysis by level designers
4076 if (r_showlighting.integer && r_refdef.view.showdebug)
4078 R_Shadow_RenderMode_VisibleLighting(!r_showdisabledepthtest.integer, false);
4079 for (i = 0;i < numlightentities_noselfshadow;i++)
4080 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4083 for (i = 0;i < numshadowentities_noselfshadow;i++)
4084 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
4086 if (numsurfaces + numlightentities)
4088 // draw lighting in the unmasked areas
4089 R_Shadow_RenderMode_Lighting(true, false, false);
4091 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4092 for (i = 0;i < numlightentities;i++)
4093 R_Shadow_DrawEntityLight(lightentities[i]);
4098 if (numsurfaces + numlightentities)
4100 // draw lighting in the unmasked areas
4101 R_Shadow_RenderMode_Lighting(false, false, false);
4103 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4104 for (i = 0;i < numlightentities;i++)
4105 R_Shadow_DrawEntityLight(lightentities[i]);
4106 for (i = 0;i < numlightentities_noselfshadow;i++)
4107 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4112 void R_Shadow_DrawLightSprites(void);
4113 void R_ShadowVolumeLighting(qboolean visible)
4121 if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, 2048) ||
4122 (r_shadow_shadowmode != 0) != (r_shadow_shadowmapping.integer != 0) ||
4123 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0) ||
4124 r_shadow_shadowmaptexturetype != r_shadow_shadowmapping_texturetype.integer ||
4125 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
4126 r_shadow_shadowmapprecision != r_shadow_shadowmapping_precision.integer ||
4127 r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
4128 R_Shadow_FreeShadowMaps();
4130 if (r_editlights.integer)
4131 R_Shadow_DrawLightSprites();
4133 R_Shadow_RenderMode_Begin();
4135 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4136 if (r_shadow_debuglight.integer >= 0)
4138 lightindex = r_shadow_debuglight.integer;
4139 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4140 if (light && (light->flags & flag))
4141 R_DrawRTLight(&light->rtlight, visible);
4145 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4146 for (lightindex = 0;lightindex < range;lightindex++)
4148 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4149 if (light && (light->flags & flag))
4150 R_DrawRTLight(&light->rtlight, visible);
4153 if (r_refdef.scene.rtdlight)
4154 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4155 R_DrawRTLight(r_refdef.scene.lights[lnum], visible);
4157 R_Shadow_RenderMode_End();
4160 extern const float r_screenvertex3f[12];
4161 extern void R_SetupView(qboolean allowwaterclippingplane);
4162 extern void R_ResetViewRendering3D(void);
4163 extern void R_ResetViewRendering2D(void);
4164 extern cvar_t r_shadows;
4165 extern cvar_t r_shadows_darken;
4166 extern cvar_t r_shadows_drawafterrtlighting;
4167 extern cvar_t r_shadows_castfrombmodels;
4168 extern cvar_t r_shadows_throwdistance;
4169 extern cvar_t r_shadows_throwdirection;
4170 void R_DrawModelShadows(void)
4173 float relativethrowdistance;
4174 entity_render_t *ent;
4175 vec3_t relativelightorigin;
4176 vec3_t relativelightdirection;
4177 vec3_t relativeshadowmins, relativeshadowmaxs;
4178 vec3_t tmp, shadowdir;
4180 if (!r_drawentities.integer || !gl_stencil)
4184 R_ResetViewRendering3D();
4185 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4186 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4187 R_Shadow_RenderMode_Begin();
4188 R_Shadow_RenderMode_ActiveLight(NULL);
4189 r_shadow_lightscissor[0] = r_refdef.view.x;
4190 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
4191 r_shadow_lightscissor[2] = r_refdef.view.width;
4192 r_shadow_lightscissor[3] = r_refdef.view.height;
4193 R_Shadow_RenderMode_StencilShadowVolumes(false);
4196 if (r_shadows.integer == 2)
4198 Math_atov(r_shadows_throwdirection.string, shadowdir);
4199 VectorNormalize(shadowdir);
4202 R_Shadow_ClearStencil();
4204 for (i = 0;i < r_refdef.scene.numentities;i++)
4206 ent = r_refdef.scene.entities[i];
4208 // cast shadows from anything of the map (submodels are optional)
4209 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4211 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4212 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
4213 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
4214 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
4215 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4218 if(ent->entitynumber != 0)
4220 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
4221 int entnum, entnum2, recursion;
4222 entnum = entnum2 = ent->entitynumber;
4223 for(recursion = 32; recursion > 0; --recursion)
4225 entnum2 = cl.entities[entnum].state_current.tagentity;
4226 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
4231 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
4233 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
4234 // transform into modelspace of OUR entity
4235 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
4236 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
4239 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4242 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4245 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
4246 RSurf_ActiveModelEntity(ent, false, false);
4247 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4248 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4252 // not really the right mode, but this will disable any silly stencil features
4253 R_Shadow_RenderMode_End();
4255 // set up ortho view for rendering this pass
4256 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4257 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4258 //GL_ScissorTest(true);
4259 //R_Mesh_Matrix(&identitymatrix);
4260 //R_Mesh_ResetTextureState();
4261 R_ResetViewRendering2D();
4262 R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
4263 R_Mesh_ColorPointer(NULL, 0, 0);
4264 R_SetupGenericShader(false);
4266 // set up a darkening blend on shadowed areas
4267 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4268 //GL_DepthRange(0, 1);
4269 //GL_DepthTest(false);
4270 //GL_DepthMask(false);
4271 //GL_PolygonOffset(0, 0);CHECKGLERROR
4272 GL_Color(0, 0, 0, r_shadows_darken.value);
4273 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4274 //qglDepthFunc(GL_ALWAYS);CHECKGLERROR
4275 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
4276 qglStencilMask(~0);CHECKGLERROR
4277 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
4278 qglStencilFunc(GL_NOTEQUAL, 128, ~0);CHECKGLERROR
4280 // apply the blend to the shadowed areas
4281 R_Mesh_Draw(0, 4, 0, 2, NULL, polygonelements, 0, 0);
4283 // restore the viewport
4284 R_SetViewport(&r_refdef.view.viewport);
4286 // restore other state to normal
4287 //R_Shadow_RenderMode_End();
4290 void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4293 vec3_t centerorigin;
4294 // if it's too close, skip it
4295 if (VectorLength(rtlight->color) < (1.0f / 256.0f))
4297 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4300 if (usequery && r_numqueries + 2 <= r_maxqueries)
4302 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4303 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4304 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4307 // 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
4308 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
4309 qglDepthFunc(GL_ALWAYS);
4310 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);
4311 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4312 qglDepthFunc(GL_LEQUAL);
4313 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
4314 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);
4315 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4318 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4321 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4324 GLint allpixels = 0, visiblepixels = 0;
4325 // now we have to check the query result
4326 if (rtlight->corona_queryindex_visiblepixels)
4329 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
4330 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
4332 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
4333 if (visiblepixels < 1 || allpixels < 1)
4335 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
4336 cscale *= rtlight->corona_visibility;
4340 // FIXME: these traces should scan all render entities instead of cl.world
4341 if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
4344 VectorScale(rtlight->color, cscale, color);
4345 if (VectorLength(color) > (1.0f / 256.0f))
4346 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);
4349 void R_DrawCoronas(void)
4357 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4359 if (r_waterstate.renderingscene)
4361 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4362 R_Mesh_Matrix(&identitymatrix);
4364 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4366 // check occlusion of coronas
4367 // use GL_ARB_occlusion_query if available
4368 // otherwise use raytraces
4370 usequery = gl_support_arb_occlusion_query && r_coronas_occlusionquery.integer;
4373 GL_ColorMask(0,0,0,0);
4374 if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
4375 if (r_maxqueries < R_MAX_OCCLUSION_QUERIES)
4378 r_maxqueries = (range + r_refdef.scene.numlights) * 4;
4379 r_maxqueries = min(r_maxqueries, R_MAX_OCCLUSION_QUERIES);
4381 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
4385 for (lightindex = 0;lightindex < range;lightindex++)
4387 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4390 rtlight = &light->rtlight;
4391 rtlight->corona_visibility = 0;
4392 rtlight->corona_queryindex_visiblepixels = 0;
4393 rtlight->corona_queryindex_allpixels = 0;
4394 if (!(rtlight->flags & flag))
4396 if (rtlight->corona <= 0)
4398 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4400 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4402 for (i = 0;i < r_refdef.scene.numlights;i++)
4404 rtlight = r_refdef.scene.lights[i];
4405 rtlight->corona_visibility = 0;
4406 rtlight->corona_queryindex_visiblepixels = 0;
4407 rtlight->corona_queryindex_allpixels = 0;
4408 if (!(rtlight->flags & flag))
4410 if (rtlight->corona <= 0)
4412 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4415 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4417 // now draw the coronas using the query data for intensity info
4418 for (lightindex = 0;lightindex < range;lightindex++)
4420 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4423 rtlight = &light->rtlight;
4424 if (rtlight->corona_visibility <= 0)
4426 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4428 for (i = 0;i < r_refdef.scene.numlights;i++)
4430 rtlight = r_refdef.scene.lights[i];
4431 if (rtlight->corona_visibility <= 0)
4433 if (gl_flashblend.integer)
4434 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4436 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4442 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
4443 typedef struct suffixinfo_s
4446 qboolean flipx, flipy, flipdiagonal;
4449 static suffixinfo_t suffix[3][6] =
4452 {"px", false, false, false},
4453 {"nx", false, false, false},
4454 {"py", false, false, false},
4455 {"ny", false, false, false},
4456 {"pz", false, false, false},
4457 {"nz", false, false, false}
4460 {"posx", false, false, false},
4461 {"negx", false, false, false},
4462 {"posy", false, false, false},
4463 {"negy", false, false, false},
4464 {"posz", false, false, false},
4465 {"negz", false, false, false}
4468 {"rt", true, false, true},
4469 {"lf", false, true, true},
4470 {"ft", true, true, false},
4471 {"bk", false, false, false},
4472 {"up", true, false, true},
4473 {"dn", true, false, true}
4477 static int componentorder[4] = {0, 1, 2, 3};
4479 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
4481 int i, j, cubemapsize;
4482 unsigned char *cubemappixels, *image_buffer;
4483 rtexture_t *cubemaptexture;
4485 // must start 0 so the first loadimagepixels has no requested width/height
4487 cubemappixels = NULL;
4488 cubemaptexture = NULL;
4489 // keep trying different suffix groups (posx, px, rt) until one loads
4490 for (j = 0;j < 3 && !cubemappixels;j++)
4492 // load the 6 images in the suffix group
4493 for (i = 0;i < 6;i++)
4495 // generate an image name based on the base and and suffix
4496 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
4498 if ((image_buffer = loadimagepixelsbgra(name, false, false)))
4500 // an image loaded, make sure width and height are equal
4501 if (image_width == image_height && (!cubemappixels || image_width == cubemapsize))
4503 // if this is the first image to load successfully, allocate the cubemap memory
4504 if (!cubemappixels && image_width >= 1)
4506 cubemapsize = image_width;
4507 // note this clears to black, so unavailable sides are black
4508 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
4510 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
4512 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);
4515 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
4517 Mem_Free(image_buffer);
4521 // if a cubemap loaded, upload it
4524 if (developer_loading.integer)
4525 Con_Printf("loading cubemap \"%s\"\n", basename);
4527 if (!r_shadow_filters_texturepool)
4528 r_shadow_filters_texturepool = R_AllocTexturePool();
4529 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_BGRA, TEXF_PRECACHE | (gl_texturecompression_lightcubemaps.integer ? TEXF_COMPRESS : 0) | TEXF_FORCELINEAR, NULL);
4530 Mem_Free(cubemappixels);
4534 Con_DPrintf("failed to load cubemap \"%s\"\n", basename);
4535 if (developer_loading.integer)
4537 Con_Printf("(tried tried images ");
4538 for (j = 0;j < 3;j++)
4539 for (i = 0;i < 6;i++)
4540 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
4541 Con_Print(" and was unable to find any of them).\n");
4544 return cubemaptexture;
4547 rtexture_t *R_Shadow_Cubemap(const char *basename)
4550 for (i = 0;i < numcubemaps;i++)
4551 if (!strcasecmp(cubemaps[i].basename, basename))
4552 return cubemaps[i].texture ? cubemaps[i].texture : r_texture_whitecube;
4553 if (i >= MAX_CUBEMAPS)
4554 return r_texture_whitecube;
4556 strlcpy(cubemaps[i].basename, basename, sizeof(cubemaps[i].basename));
4557 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
4558 return cubemaps[i].texture;
4561 void R_Shadow_FreeCubemaps(void)
4564 for (i = 0;i < numcubemaps;i++)
4566 if (developer_loading.integer)
4567 Con_Printf("unloading cubemap \"%s\"\n", cubemaps[i].basename);
4568 if (cubemaps[i].texture)
4569 R_FreeTexture(cubemaps[i].texture);
4573 R_FreeTexturePool(&r_shadow_filters_texturepool);
4576 dlight_t *R_Shadow_NewWorldLight(void)
4578 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4581 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)
4584 // validate parameters
4585 if (style < 0 || style >= MAX_LIGHTSTYLES)
4587 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
4593 // copy to light properties
4594 VectorCopy(origin, light->origin);
4595 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4596 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4597 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4598 light->color[0] = max(color[0], 0);
4599 light->color[1] = max(color[1], 0);
4600 light->color[2] = max(color[2], 0);
4601 light->radius = max(radius, 0);
4602 light->style = style;
4603 light->shadow = shadowenable;
4604 light->corona = corona;
4605 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4606 light->coronasizescale = coronasizescale;
4607 light->ambientscale = ambientscale;
4608 light->diffusescale = diffusescale;
4609 light->specularscale = specularscale;
4610 light->flags = flags;
4612 // update renderable light data
4613 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4614 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);
4617 void R_Shadow_FreeWorldLight(dlight_t *light)
4619 if (r_shadow_selectedlight == light)
4620 r_shadow_selectedlight = NULL;
4621 R_RTLight_Uncompile(&light->rtlight);
4622 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4625 void R_Shadow_ClearWorldLights(void)
4629 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4630 for (lightindex = 0;lightindex < range;lightindex++)
4632 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4634 R_Shadow_FreeWorldLight(light);
4636 r_shadow_selectedlight = NULL;
4637 R_Shadow_FreeCubemaps();
4640 void R_Shadow_SelectLight(dlight_t *light)
4642 if (r_shadow_selectedlight)
4643 r_shadow_selectedlight->selected = false;
4644 r_shadow_selectedlight = light;
4645 if (r_shadow_selectedlight)
4646 r_shadow_selectedlight->selected = true;
4649 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4651 // this is never batched (there can be only one)
4652 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);
4655 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4662 // this is never batched (due to the ent parameter changing every time)
4663 // so numsurfaces == 1 and surfacelist[0] == lightnumber
4664 const dlight_t *light = (dlight_t *)ent;
4667 VectorScale(light->color, intensity, spritecolor);
4668 if (VectorLength(spritecolor) < 0.1732f)
4669 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
4670 if (VectorLength(spritecolor) > 1.0f)
4671 VectorNormalize(spritecolor);
4673 // draw light sprite
4674 if (light->cubemapname[0] && !light->shadow)
4675 pic = r_editlights_sprcubemapnoshadowlight;
4676 else if (light->cubemapname[0])
4677 pic = r_editlights_sprcubemaplight;
4678 else if (!light->shadow)
4679 pic = r_editlights_sprnoshadowlight;
4681 pic = r_editlights_sprlight;
4682 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);
4683 // draw selection sprite if light is selected
4684 if (light->selected)
4685 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);
4686 // VorteX todo: add normalmode/realtime mode light overlay sprites?
4689 void R_Shadow_DrawLightSprites(void)
4693 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4694 for (lightindex = 0;lightindex < range;lightindex++)
4696 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4698 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
4700 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
4703 void R_Shadow_SelectLightInView(void)
4705 float bestrating, rating, temp[3];
4709 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4712 for (lightindex = 0;lightindex < range;lightindex++)
4714 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4717 VectorSubtract(light->origin, r_refdef.view.origin, temp);
4718 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
4721 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
4722 if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1.0f)
4724 bestrating = rating;
4729 R_Shadow_SelectLight(best);
4732 void R_Shadow_LoadWorldLights(void)
4734 int n, a, style, shadow, flags;
4735 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
4736 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
4737 if (cl.worldmodel == NULL)
4739 Con_Print("No map loaded.\n");
4742 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4743 strlcat (name, ".rtlights", sizeof (name));
4744 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4754 for (;COM_Parse(t, true) && strcmp(
4755 if (COM_Parse(t, true))
4757 if (com_token[0] == '!')
4760 origin[0] = atof(com_token+1);
4763 origin[0] = atof(com_token);
4768 while (*s && *s != '\n' && *s != '\r')
4774 // check for modifier flags
4781 #if _MSC_VER >= 1400
4782 #define sscanf sscanf_s
4784 cubemapname[sizeof(cubemapname)-1] = 0;
4785 #if MAX_QPATH != 128
4786 #error update this code if MAX_QPATH changes
4788 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
4789 #if _MSC_VER >= 1400
4790 , sizeof(cubemapname)
4792 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
4795 flags = LIGHTFLAG_REALTIMEMODE;
4803 coronasizescale = 0.25f;
4805 VectorClear(angles);
4808 if (a < 9 || !strcmp(cubemapname, "\"\""))
4810 // remove quotes on cubemapname
4811 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
4814 namelen = strlen(cubemapname) - 2;
4815 memmove(cubemapname, cubemapname + 1, namelen);
4816 cubemapname[namelen] = '\0';
4820 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);
4823 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4831 Con_Printf("invalid rtlights file \"%s\"\n", name);
4832 Mem_Free(lightsstring);
4836 void R_Shadow_SaveWorldLights(void)
4840 size_t bufchars, bufmaxchars;
4842 char name[MAX_QPATH];
4843 char line[MAX_INPUTLINE];
4844 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
4845 // I hate lines which are 3 times my screen size :( --blub
4848 if (cl.worldmodel == NULL)
4850 Con_Print("No map loaded.\n");
4853 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4854 strlcat (name, ".rtlights", sizeof (name));
4855 bufchars = bufmaxchars = 0;
4857 for (lightindex = 0;lightindex < range;lightindex++)
4859 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4862 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
4863 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);
4864 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
4865 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]);
4867 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);
4868 if (bufchars + strlen(line) > bufmaxchars)
4870 bufmaxchars = bufchars + strlen(line) + 2048;
4872 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
4876 memcpy(buf, oldbuf, bufchars);
4882 memcpy(buf + bufchars, line, strlen(line));
4883 bufchars += strlen(line);
4887 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
4892 void R_Shadow_LoadLightsFile(void)
4895 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
4896 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
4897 if (cl.worldmodel == NULL)
4899 Con_Print("No map loaded.\n");
4902 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4903 strlcat (name, ".lights", sizeof (name));
4904 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4912 while (*s && *s != '\n' && *s != '\r')
4918 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);
4922 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);
4925 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
4926 radius = bound(15, radius, 4096);
4927 VectorScale(color, (2.0f / (8388608.0f)), color);
4928 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
4936 Con_Printf("invalid lights file \"%s\"\n", name);
4937 Mem_Free(lightsstring);
4941 // tyrlite/hmap2 light types in the delay field
4942 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
4944 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
4946 int entnum, style, islight, skin, pflags, effects, type, n;
4949 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
4950 char key[256], value[MAX_INPUTLINE];
4952 if (cl.worldmodel == NULL)
4954 Con_Print("No map loaded.\n");
4957 // try to load a .ent file first
4958 FS_StripExtension (cl.worldmodel->name, key, sizeof (key));
4959 strlcat (key, ".ent", sizeof (key));
4960 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
4961 // and if that is not found, fall back to the bsp file entity string
4963 data = cl.worldmodel->brush.entities;
4966 for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
4968 type = LIGHTTYPE_MINUSX;
4969 origin[0] = origin[1] = origin[2] = 0;
4970 originhack[0] = originhack[1] = originhack[2] = 0;
4971 angles[0] = angles[1] = angles[2] = 0;
4972 color[0] = color[1] = color[2] = 1;
4973 light[0] = light[1] = light[2] = 1;light[3] = 300;
4974 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
4984 if (!COM_ParseToken_Simple(&data, false, false))
4986 if (com_token[0] == '}')
4987 break; // end of entity
4988 if (com_token[0] == '_')
4989 strlcpy(key, com_token + 1, sizeof(key));
4991 strlcpy(key, com_token, sizeof(key));
4992 while (key[strlen(key)-1] == ' ') // remove trailing spaces
4993 key[strlen(key)-1] = 0;
4994 if (!COM_ParseToken_Simple(&data, false, false))
4996 strlcpy(value, com_token, sizeof(value));
4998 // now that we have the key pair worked out...
4999 if (!strcmp("light", key))
5001 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5005 light[0] = vec[0] * (1.0f / 256.0f);
5006 light[1] = vec[0] * (1.0f / 256.0f);
5007 light[2] = vec[0] * (1.0f / 256.0f);
5013 light[0] = vec[0] * (1.0f / 255.0f);
5014 light[1] = vec[1] * (1.0f / 255.0f);
5015 light[2] = vec[2] * (1.0f / 255.0f);
5019 else if (!strcmp("delay", key))
5021 else if (!strcmp("origin", key))
5022 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5023 else if (!strcmp("angle", key))
5024 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5025 else if (!strcmp("angles", key))
5026 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5027 else if (!strcmp("color", key))
5028 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5029 else if (!strcmp("wait", key))
5030 fadescale = atof(value);
5031 else if (!strcmp("classname", key))
5033 if (!strncmp(value, "light", 5))
5036 if (!strcmp(value, "light_fluoro"))
5041 overridecolor[0] = 1;
5042 overridecolor[1] = 1;
5043 overridecolor[2] = 1;
5045 if (!strcmp(value, "light_fluorospark"))
5050 overridecolor[0] = 1;
5051 overridecolor[1] = 1;
5052 overridecolor[2] = 1;
5054 if (!strcmp(value, "light_globe"))
5059 overridecolor[0] = 1;
5060 overridecolor[1] = 0.8;
5061 overridecolor[2] = 0.4;
5063 if (!strcmp(value, "light_flame_large_yellow"))
5068 overridecolor[0] = 1;
5069 overridecolor[1] = 0.5;
5070 overridecolor[2] = 0.1;
5072 if (!strcmp(value, "light_flame_small_yellow"))
5077 overridecolor[0] = 1;
5078 overridecolor[1] = 0.5;
5079 overridecolor[2] = 0.1;
5081 if (!strcmp(value, "light_torch_small_white"))
5086 overridecolor[0] = 1;
5087 overridecolor[1] = 0.5;
5088 overridecolor[2] = 0.1;
5090 if (!strcmp(value, "light_torch_small_walltorch"))
5095 overridecolor[0] = 1;
5096 overridecolor[1] = 0.5;
5097 overridecolor[2] = 0.1;
5101 else if (!strcmp("style", key))
5102 style = atoi(value);
5103 else if (!strcmp("skin", key))
5104 skin = (int)atof(value);
5105 else if (!strcmp("pflags", key))
5106 pflags = (int)atof(value);
5107 else if (!strcmp("effects", key))
5108 effects = (int)atof(value);
5109 else if (cl.worldmodel->type == mod_brushq3)
5111 if (!strcmp("scale", key))
5112 lightscale = atof(value);
5113 if (!strcmp("fade", key))
5114 fadescale = atof(value);
5119 if (lightscale <= 0)
5123 if (color[0] == color[1] && color[0] == color[2])
5125 color[0] *= overridecolor[0];
5126 color[1] *= overridecolor[1];
5127 color[2] *= overridecolor[2];
5129 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5130 color[0] = color[0] * light[0];
5131 color[1] = color[1] * light[1];
5132 color[2] = color[2] * light[2];
5135 case LIGHTTYPE_MINUSX:
5137 case LIGHTTYPE_RECIPX:
5139 VectorScale(color, (1.0f / 16.0f), color);
5141 case LIGHTTYPE_RECIPXX:
5143 VectorScale(color, (1.0f / 16.0f), color);
5146 case LIGHTTYPE_NONE:
5150 case LIGHTTYPE_MINUSXX:
5153 VectorAdd(origin, originhack, origin);
5155 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);
5158 Mem_Free(entfiledata);
5162 void R_Shadow_SetCursorLocationForView(void)
5165 vec3_t dest, endpos;
5167 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5168 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
5169 if (trace.fraction < 1)
5171 dist = trace.fraction * r_editlights_cursordistance.value;
5172 push = r_editlights_cursorpushback.value;
5176 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5177 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5181 VectorClear( endpos );
5183 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5184 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5185 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5188 void R_Shadow_UpdateWorldLightSelection(void)
5190 if (r_editlights.integer)
5192 R_Shadow_SetCursorLocationForView();
5193 R_Shadow_SelectLightInView();
5196 R_Shadow_SelectLight(NULL);
5199 void R_Shadow_EditLights_Clear_f(void)
5201 R_Shadow_ClearWorldLights();
5204 void R_Shadow_EditLights_Reload_f(void)
5208 strlcpy(r_shadow_mapname, cl.worldmodel->name, sizeof(r_shadow_mapname));
5209 R_Shadow_ClearWorldLights();
5210 R_Shadow_LoadWorldLights();
5211 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5213 R_Shadow_LoadLightsFile();
5214 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5215 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5219 void R_Shadow_EditLights_Save_f(void)
5223 R_Shadow_SaveWorldLights();
5226 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
5228 R_Shadow_ClearWorldLights();
5229 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5232 void R_Shadow_EditLights_ImportLightsFile_f(void)
5234 R_Shadow_ClearWorldLights();
5235 R_Shadow_LoadLightsFile();
5238 void R_Shadow_EditLights_Spawn_f(void)
5241 if (!r_editlights.integer)
5243 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5246 if (Cmd_Argc() != 1)
5248 Con_Print("r_editlights_spawn does not take parameters\n");
5251 color[0] = color[1] = color[2] = 1;
5252 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5255 void R_Shadow_EditLights_Edit_f(void)
5257 vec3_t origin, angles, color;
5258 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5259 int style, shadows, flags, normalmode, realtimemode;
5260 char cubemapname[MAX_INPUTLINE];
5261 if (!r_editlights.integer)
5263 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5266 if (!r_shadow_selectedlight)
5268 Con_Print("No selected light.\n");
5271 VectorCopy(r_shadow_selectedlight->origin, origin);
5272 VectorCopy(r_shadow_selectedlight->angles, angles);
5273 VectorCopy(r_shadow_selectedlight->color, color);
5274 radius = r_shadow_selectedlight->radius;
5275 style = r_shadow_selectedlight->style;
5276 if (r_shadow_selectedlight->cubemapname)
5277 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5280 shadows = r_shadow_selectedlight->shadow;
5281 corona = r_shadow_selectedlight->corona;
5282 coronasizescale = r_shadow_selectedlight->coronasizescale;
5283 ambientscale = r_shadow_selectedlight->ambientscale;
5284 diffusescale = r_shadow_selectedlight->diffusescale;
5285 specularscale = r_shadow_selectedlight->specularscale;
5286 flags = r_shadow_selectedlight->flags;
5287 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5288 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5289 if (!strcmp(Cmd_Argv(1), "origin"))
5291 if (Cmd_Argc() != 5)
5293 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5296 origin[0] = atof(Cmd_Argv(2));
5297 origin[1] = atof(Cmd_Argv(3));
5298 origin[2] = atof(Cmd_Argv(4));
5300 else if (!strcmp(Cmd_Argv(1), "originx"))
5302 if (Cmd_Argc() != 3)
5304 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5307 origin[0] = atof(Cmd_Argv(2));
5309 else if (!strcmp(Cmd_Argv(1), "originy"))
5311 if (Cmd_Argc() != 3)
5313 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5316 origin[1] = atof(Cmd_Argv(2));
5318 else if (!strcmp(Cmd_Argv(1), "originz"))
5320 if (Cmd_Argc() != 3)
5322 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5325 origin[2] = atof(Cmd_Argv(2));
5327 else if (!strcmp(Cmd_Argv(1), "move"))
5329 if (Cmd_Argc() != 5)
5331 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5334 origin[0] += atof(Cmd_Argv(2));
5335 origin[1] += atof(Cmd_Argv(3));
5336 origin[2] += atof(Cmd_Argv(4));
5338 else if (!strcmp(Cmd_Argv(1), "movex"))
5340 if (Cmd_Argc() != 3)
5342 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5345 origin[0] += atof(Cmd_Argv(2));
5347 else if (!strcmp(Cmd_Argv(1), "movey"))
5349 if (Cmd_Argc() != 3)
5351 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5354 origin[1] += atof(Cmd_Argv(2));
5356 else if (!strcmp(Cmd_Argv(1), "movez"))
5358 if (Cmd_Argc() != 3)
5360 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5363 origin[2] += atof(Cmd_Argv(2));
5365 else if (!strcmp(Cmd_Argv(1), "angles"))
5367 if (Cmd_Argc() != 5)
5369 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5372 angles[0] = atof(Cmd_Argv(2));
5373 angles[1] = atof(Cmd_Argv(3));
5374 angles[2] = atof(Cmd_Argv(4));
5376 else if (!strcmp(Cmd_Argv(1), "anglesx"))
5378 if (Cmd_Argc() != 3)
5380 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5383 angles[0] = atof(Cmd_Argv(2));
5385 else if (!strcmp(Cmd_Argv(1), "anglesy"))
5387 if (Cmd_Argc() != 3)
5389 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5392 angles[1] = atof(Cmd_Argv(2));
5394 else if (!strcmp(Cmd_Argv(1), "anglesz"))
5396 if (Cmd_Argc() != 3)
5398 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5401 angles[2] = atof(Cmd_Argv(2));
5403 else if (!strcmp(Cmd_Argv(1), "color"))
5405 if (Cmd_Argc() != 5)
5407 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
5410 color[0] = atof(Cmd_Argv(2));
5411 color[1] = atof(Cmd_Argv(3));
5412 color[2] = atof(Cmd_Argv(4));
5414 else if (!strcmp(Cmd_Argv(1), "radius"))
5416 if (Cmd_Argc() != 3)
5418 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5421 radius = atof(Cmd_Argv(2));
5423 else if (!strcmp(Cmd_Argv(1), "colorscale"))
5425 if (Cmd_Argc() == 3)
5427 double scale = atof(Cmd_Argv(2));
5434 if (Cmd_Argc() != 5)
5436 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
5439 color[0] *= atof(Cmd_Argv(2));
5440 color[1] *= atof(Cmd_Argv(3));
5441 color[2] *= atof(Cmd_Argv(4));
5444 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
5446 if (Cmd_Argc() != 3)
5448 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5451 radius *= atof(Cmd_Argv(2));
5453 else if (!strcmp(Cmd_Argv(1), "style"))
5455 if (Cmd_Argc() != 3)
5457 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5460 style = atoi(Cmd_Argv(2));
5462 else if (!strcmp(Cmd_Argv(1), "cubemap"))
5466 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5469 if (Cmd_Argc() == 3)
5470 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
5474 else if (!strcmp(Cmd_Argv(1), "shadows"))
5476 if (Cmd_Argc() != 3)
5478 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5481 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5483 else if (!strcmp(Cmd_Argv(1), "corona"))
5485 if (Cmd_Argc() != 3)
5487 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5490 corona = atof(Cmd_Argv(2));
5492 else if (!strcmp(Cmd_Argv(1), "coronasize"))
5494 if (Cmd_Argc() != 3)
5496 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5499 coronasizescale = atof(Cmd_Argv(2));
5501 else if (!strcmp(Cmd_Argv(1), "ambient"))
5503 if (Cmd_Argc() != 3)
5505 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5508 ambientscale = atof(Cmd_Argv(2));
5510 else if (!strcmp(Cmd_Argv(1), "diffuse"))
5512 if (Cmd_Argc() != 3)
5514 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5517 diffusescale = atof(Cmd_Argv(2));
5519 else if (!strcmp(Cmd_Argv(1), "specular"))
5521 if (Cmd_Argc() != 3)
5523 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5526 specularscale = atof(Cmd_Argv(2));
5528 else if (!strcmp(Cmd_Argv(1), "normalmode"))
5530 if (Cmd_Argc() != 3)
5532 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5535 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5537 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
5539 if (Cmd_Argc() != 3)
5541 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5544 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5548 Con_Print("usage: r_editlights_edit [property] [value]\n");
5549 Con_Print("Selected light's properties:\n");
5550 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5551 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5552 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5553 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
5554 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
5555 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
5556 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5557 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
5558 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
5559 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
5560 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
5561 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
5562 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5563 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5566 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5567 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5570 void R_Shadow_EditLights_EditAll_f(void)
5576 if (!r_editlights.integer)
5578 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5582 // EditLights doesn't seem to have a "remove" command or something so:
5583 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5584 for (lightindex = 0;lightindex < range;lightindex++)
5586 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5589 R_Shadow_SelectLight(light);
5590 R_Shadow_EditLights_Edit_f();
5594 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
5596 int lightnumber, lightcount;
5597 size_t lightindex, range;
5601 if (!r_editlights.integer)
5603 x = vid_conwidth.value - 240;
5605 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
5608 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5609 for (lightindex = 0;lightindex < range;lightindex++)
5611 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5614 if (light == r_shadow_selectedlight)
5615 lightnumber = lightindex;
5618 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;
5619 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;
5621 if (r_shadow_selectedlight == NULL)
5623 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;
5624 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;
5625 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;
5626 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;
5627 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;
5628 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;
5629 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;
5630 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;
5631 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;
5632 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;
5633 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;
5634 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;
5635 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;
5636 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;
5637 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;
5640 void R_Shadow_EditLights_ToggleShadow_f(void)
5642 if (!r_editlights.integer)
5644 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5647 if (!r_shadow_selectedlight)
5649 Con_Print("No selected light.\n");
5652 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);
5655 void R_Shadow_EditLights_ToggleCorona_f(void)
5657 if (!r_editlights.integer)
5659 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5662 if (!r_shadow_selectedlight)
5664 Con_Print("No selected light.\n");
5667 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);
5670 void R_Shadow_EditLights_Remove_f(void)
5672 if (!r_editlights.integer)
5674 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
5677 if (!r_shadow_selectedlight)
5679 Con_Print("No selected light.\n");
5682 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
5683 r_shadow_selectedlight = NULL;
5686 void R_Shadow_EditLights_Help_f(void)
5689 "Documentation on r_editlights system:\n"
5691 "r_editlights : enable/disable editing mode\n"
5692 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
5693 "r_editlights_cursorpushback : push back cursor this far from surface\n"
5694 "r_editlights_cursorpushoff : push cursor off surface this far\n"
5695 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
5696 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
5698 "r_editlights_help : this help\n"
5699 "r_editlights_clear : remove all lights\n"
5700 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
5701 "r_editlights_save : save to .rtlights file\n"
5702 "r_editlights_spawn : create a light with default settings\n"
5703 "r_editlights_edit command : edit selected light - more documentation below\n"
5704 "r_editlights_remove : remove selected light\n"
5705 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
5706 "r_editlights_importlightentitiesfrommap : reload light entities\n"
5707 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
5709 "origin x y z : set light location\n"
5710 "originx x: set x component of light location\n"
5711 "originy y: set y component of light location\n"
5712 "originz z: set z component of light location\n"
5713 "move x y z : adjust light location\n"
5714 "movex x: adjust x component of light location\n"
5715 "movey y: adjust y component of light location\n"
5716 "movez z: adjust z component of light location\n"
5717 "angles x y z : set light angles\n"
5718 "anglesx x: set x component of light angles\n"
5719 "anglesy y: set y component of light angles\n"
5720 "anglesz z: set z component of light angles\n"
5721 "color r g b : set color of light (can be brighter than 1 1 1)\n"
5722 "radius radius : set radius (size) of light\n"
5723 "colorscale grey : multiply color of light (1 does nothing)\n"
5724 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
5725 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
5726 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
5727 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
5728 "cubemap basename : set filter cubemap of light (not yet supported)\n"
5729 "shadows 1/0 : turn on/off shadows\n"
5730 "corona n : set corona intensity\n"
5731 "coronasize n : set corona size (0-1)\n"
5732 "ambient n : set ambient intensity (0-1)\n"
5733 "diffuse n : set diffuse intensity (0-1)\n"
5734 "specular n : set specular intensity (0-1)\n"
5735 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
5736 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
5737 "<nothing> : print light properties to console\n"
5741 void R_Shadow_EditLights_CopyInfo_f(void)
5743 if (!r_editlights.integer)
5745 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
5748 if (!r_shadow_selectedlight)
5750 Con_Print("No selected light.\n");
5753 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
5754 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
5755 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
5756 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
5757 if (r_shadow_selectedlight->cubemapname)
5758 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
5760 r_shadow_bufferlight.cubemapname[0] = 0;
5761 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
5762 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
5763 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
5764 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
5765 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
5766 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
5767 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
5770 void R_Shadow_EditLights_PasteInfo_f(void)
5772 if (!r_editlights.integer)
5774 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
5777 if (!r_shadow_selectedlight)
5779 Con_Print("No selected light.\n");
5782 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);
5785 void R_Shadow_EditLights_Init(void)
5787 Cvar_RegisterVariable(&r_editlights);
5788 Cvar_RegisterVariable(&r_editlights_cursordistance);
5789 Cvar_RegisterVariable(&r_editlights_cursorpushback);
5790 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
5791 Cvar_RegisterVariable(&r_editlights_cursorgrid);
5792 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
5793 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
5794 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
5795 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)");
5796 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
5797 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
5798 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
5799 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)");
5800 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
5801 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
5802 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
5803 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
5804 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
5805 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
5806 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)");
5812 =============================================================================
5816 =============================================================================
5819 void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, int dynamic)
5821 VectorClear(diffusecolor);
5822 VectorClear(diffusenormal);
5824 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
5826 ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_refdef.scene.ambient * (2.0f / 128.0f);
5827 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
5830 VectorSet(ambientcolor, 1, 1, 1);
5837 for (i = 0;i < r_refdef.scene.numlights;i++)
5839 light = r_refdef.scene.lights[i];
5840 Matrix4x4_Transform(&light->matrix_worldtolight, p, v);
5841 f = 1 - VectorLength2(v);
5842 if (f > 0 && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
5843 VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);