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_gloss2exponent = {0, "r_shadow_gloss2exponent", "32", "same as r_shadow_glossexponent but for forced gloss (gloss 2) surfaces"};
257 cvar_t r_shadow_glossexact = {0, "r_shadow_glossexact", "0", "use exact reflection math for gloss (slightly slower, but should look a tad better)"};
258 cvar_t r_shadow_lightattenuationdividebias = {0, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"};
259 cvar_t r_shadow_lightattenuationlinearscale = {0, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"};
260 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
261 cvar_t r_shadow_lightradiusscale = {0, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
262 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1", "use portal culling to exactly determine lit triangles when compiling world lights"};
263 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000", "how far to cast shadows"};
264 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)"};
265 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
266 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
267 cvar_t r_shadow_realtime_dlight_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
268 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
269 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)"};
270 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"};
271 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
272 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
273 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"};
274 cvar_t r_shadow_realtime_world_compilesvbsp = {0, "r_shadow_realtime_world_compilesvbsp", "1", "enables svbsp optimization during compilation"};
275 cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "1", "enables portal-based culling optimization during compilation"};
276 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)"};
277 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"};
278 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"};
279 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)"};
280 cvar_t r_shadow_shadowmapping_precision = {CVAR_SAVE, "r_shadow_shadowmapping_precision", "24", "requested minimum shadowmap texture precision"};
281 cvar_t r_shadow_shadowmapping_vsdct = {CVAR_SAVE, "r_shadow_shadowmapping_vsdct", "1", "enables use of virtual shadow depth cube texture"};
282 cvar_t r_shadow_shadowmapping_minsize = {CVAR_SAVE, "r_shadow_shadowmapping_minsize", "32", "shadowmap size limit"};
283 cvar_t r_shadow_shadowmapping_maxsize = {CVAR_SAVE, "r_shadow_shadowmapping_maxsize", "512", "shadowmap size limit"};
284 cvar_t r_shadow_shadowmapping_lod_bias = {CVAR_SAVE, "r_shadow_shadowmapping_lod_bias", "16", "shadowmap size bias"};
285 cvar_t r_shadow_shadowmapping_lod_scale = {CVAR_SAVE, "r_shadow_shadowmapping_lod_scale", "128", "shadowmap size scaling parameter"};
286 cvar_t r_shadow_shadowmapping_bordersize = {CVAR_SAVE, "r_shadow_shadowmapping_bordersize", "4", "shadowmap size bias for filtering"};
287 cvar_t r_shadow_shadowmapping_nearclip = {CVAR_SAVE, "r_shadow_shadowmapping_nearclip", "1", "shadowmap nearclip in world units"};
288 cvar_t r_shadow_shadowmapping_bias = {CVAR_SAVE, "r_shadow_shadowmapping_bias", "0.03", "shadowmap bias parameter (this is multiplied by nearclip * 1024 / lodsize)"};
289 cvar_t r_shadow_culltriangles = {0, "r_shadow_culltriangles", "1", "performs more expensive tests to remove unnecessary triangles of lit surfaces"};
290 cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
291 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)"};
292 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)"};
293 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "1", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
294 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"};
295 cvar_t r_coronas_occlusionquery = {CVAR_SAVE, "r_coronas_occlusionquery", "1", "use GL_ARB_occlusion_query extension if supported (fades coronas according to visibility)"};
296 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
297 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
298 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
299 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
300 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
301 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
302 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
303 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
304 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
306 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
307 #define ATTENTABLESIZE 256
308 // 1D gradient, 2D circle and 3D sphere attenuation textures
309 #define ATTEN1DSIZE 32
310 #define ATTEN2DSIZE 64
311 #define ATTEN3DSIZE 32
313 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
314 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
315 static float r_shadow_attentable[ATTENTABLESIZE+1];
317 rtlight_t *r_shadow_compilingrtlight;
318 static memexpandablearray_t r_shadow_worldlightsarray;
319 dlight_t *r_shadow_selectedlight;
320 dlight_t r_shadow_bufferlight;
321 vec3_t r_editlights_cursorlocation;
323 extern int con_vislines;
325 typedef struct cubemapinfo_s
332 #define MAX_CUBEMAPS 256
333 static int numcubemaps;
334 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
336 void R_Shadow_UncompileWorldLights(void);
337 void R_Shadow_ClearWorldLights(void);
338 void R_Shadow_SaveWorldLights(void);
339 void R_Shadow_LoadWorldLights(void);
340 void R_Shadow_LoadLightsFile(void);
341 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
342 void R_Shadow_EditLights_Reload_f(void);
343 void R_Shadow_ValidateCvars(void);
344 static void R_Shadow_MakeTextures(void);
346 // VorteX: custom editor light sprites
347 #define EDLIGHTSPRSIZE 8
348 cachepic_t *r_editlights_sprcursor;
349 cachepic_t *r_editlights_sprlight;
350 cachepic_t *r_editlights_sprnoshadowlight;
351 cachepic_t *r_editlights_sprcubemaplight;
352 cachepic_t *r_editlights_sprcubemapnoshadowlight;
353 cachepic_t *r_editlights_sprselection;
355 void R_Shadow_SetShadowMode(void)
357 r_shadow_shadowmapmaxsize = bound(1, r_shadow_shadowmapping_maxsize.integer, 2048);
358 r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer != 0;
359 r_shadow_shadowmapfilterquality = r_shadow_shadowmapping_filterquality.integer;
360 r_shadow_shadowmaptexturetype = r_shadow_shadowmapping_texturetype.integer;
361 r_shadow_shadowmapprecision = r_shadow_shadowmapping_precision.integer;
362 r_shadow_shadowmapborder = bound(0, r_shadow_shadowmapping_bordersize.integer, 16);
363 r_shadow_shadowmaplod = -1;
364 r_shadow_shadowmapsize = 0;
365 r_shadow_shadowmapsampler = false;
366 r_shadow_shadowmappcf = 0;
367 r_shadow_shadowmode = 0;
368 if(r_shadow_shadowmapping.integer)
370 if(r_shadow_shadowmapfilterquality < 0)
372 if(strstr(gl_vendor, "NVIDIA"))
374 r_shadow_shadowmapsampler = gl_support_arb_shadow;
375 r_shadow_shadowmappcf = 1;
377 else if(gl_support_amd_texture_texture4 || gl_support_arb_texture_gather)
378 r_shadow_shadowmappcf = 1;
379 else if(strstr(gl_vendor, "ATI"))
380 r_shadow_shadowmappcf = 1;
382 r_shadow_shadowmapsampler = gl_support_arb_shadow;
386 switch (r_shadow_shadowmapfilterquality)
389 r_shadow_shadowmapsampler = gl_support_arb_shadow;
392 r_shadow_shadowmapsampler = gl_support_arb_shadow;
393 r_shadow_shadowmappcf = 1;
396 r_shadow_shadowmappcf = 1;
399 r_shadow_shadowmappcf = 2;
403 r_shadow_shadowmode = r_shadow_shadowmaptexturetype;
404 if(r_shadow_shadowmode <= 0)
406 if((gl_support_amd_texture_texture4 || gl_support_arb_texture_gather) && r_shadow_shadowmappcf && !r_shadow_shadowmapsampler)
407 r_shadow_shadowmode = 1;
408 else if(gl_texturerectangle)
409 r_shadow_shadowmode = 2;
411 r_shadow_shadowmode = 1;
416 void R_Shadow_FreeShadowMaps(void)
420 R_Shadow_SetShadowMode();
422 if (r_shadow_fborectangle)
423 qglDeleteFramebuffersEXT(1, &r_shadow_fborectangle);
424 r_shadow_fborectangle = 0;
428 qglDeleteFramebuffersEXT(1, &r_shadow_fbo2d);
431 for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
432 if (r_shadow_fbocubeside[i][0])
433 qglDeleteFramebuffersEXT(6, r_shadow_fbocubeside[i]);
434 memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
437 if (r_shadow_shadowmaprectangletexture)
438 R_FreeTexture(r_shadow_shadowmaprectangletexture);
439 r_shadow_shadowmaprectangletexture = NULL;
441 if (r_shadow_shadowmap2dtexture)
442 R_FreeTexture(r_shadow_shadowmap2dtexture);
443 r_shadow_shadowmap2dtexture = NULL;
445 for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
446 if (r_shadow_shadowmapcubetexture[i])
447 R_FreeTexture(r_shadow_shadowmapcubetexture[i]);
448 memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
450 if (r_shadow_shadowmapvsdcttexture)
451 R_FreeTexture(r_shadow_shadowmapvsdcttexture);
452 r_shadow_shadowmapvsdcttexture = NULL;
457 void r_shadow_start(void)
459 // allocate vertex processing arrays
461 r_shadow_attenuationgradienttexture = NULL;
462 r_shadow_attenuation2dtexture = NULL;
463 r_shadow_attenuation3dtexture = NULL;
464 r_shadow_shadowmode = 0;
465 r_shadow_shadowmaprectangletexture = NULL;
466 r_shadow_shadowmap2dtexture = NULL;
467 memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
468 r_shadow_shadowmapvsdcttexture = NULL;
469 r_shadow_shadowmapmaxsize = 0;
470 r_shadow_shadowmapsize = 0;
471 r_shadow_shadowmaplod = 0;
472 r_shadow_shadowmapfilterquality = 0;
473 r_shadow_shadowmaptexturetype = 0;
474 r_shadow_shadowmapprecision = 0;
475 r_shadow_shadowmapvsdct = false;
476 r_shadow_shadowmapsampler = false;
477 r_shadow_shadowmappcf = 0;
478 r_shadow_fborectangle = 0;
480 memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
482 R_Shadow_FreeShadowMaps();
484 r_shadow_texturepool = NULL;
485 r_shadow_filters_texturepool = NULL;
486 R_Shadow_ValidateCvars();
487 R_Shadow_MakeTextures();
488 maxshadowtriangles = 0;
489 shadowelements = NULL;
490 maxshadowvertices = 0;
491 shadowvertex3f = NULL;
499 shadowmarklist = NULL;
504 shadowsideslist = NULL;
505 r_shadow_buffer_numleafpvsbytes = 0;
506 r_shadow_buffer_visitingleafpvs = NULL;
507 r_shadow_buffer_leafpvs = NULL;
508 r_shadow_buffer_leaflist = NULL;
509 r_shadow_buffer_numsurfacepvsbytes = 0;
510 r_shadow_buffer_surfacepvs = NULL;
511 r_shadow_buffer_surfacelist = NULL;
512 r_shadow_buffer_numshadowtrispvsbytes = 0;
513 r_shadow_buffer_shadowtrispvs = NULL;
514 r_shadow_buffer_numlighttrispvsbytes = 0;
515 r_shadow_buffer_lighttrispvs = NULL;
518 void r_shadow_shutdown(void)
521 R_Shadow_UncompileWorldLights();
523 R_Shadow_FreeShadowMaps();
527 r_shadow_attenuationgradienttexture = NULL;
528 r_shadow_attenuation2dtexture = NULL;
529 r_shadow_attenuation3dtexture = NULL;
530 R_FreeTexturePool(&r_shadow_texturepool);
531 R_FreeTexturePool(&r_shadow_filters_texturepool);
532 maxshadowtriangles = 0;
534 Mem_Free(shadowelements);
535 shadowelements = NULL;
537 Mem_Free(shadowvertex3f);
538 shadowvertex3f = NULL;
541 Mem_Free(vertexupdate);
544 Mem_Free(vertexremap);
550 Mem_Free(shadowmark);
553 Mem_Free(shadowmarklist);
554 shadowmarklist = NULL;
559 Mem_Free(shadowsides);
562 Mem_Free(shadowsideslist);
563 shadowsideslist = NULL;
564 r_shadow_buffer_numleafpvsbytes = 0;
565 if (r_shadow_buffer_visitingleafpvs)
566 Mem_Free(r_shadow_buffer_visitingleafpvs);
567 r_shadow_buffer_visitingleafpvs = NULL;
568 if (r_shadow_buffer_leafpvs)
569 Mem_Free(r_shadow_buffer_leafpvs);
570 r_shadow_buffer_leafpvs = NULL;
571 if (r_shadow_buffer_leaflist)
572 Mem_Free(r_shadow_buffer_leaflist);
573 r_shadow_buffer_leaflist = NULL;
574 r_shadow_buffer_numsurfacepvsbytes = 0;
575 if (r_shadow_buffer_surfacepvs)
576 Mem_Free(r_shadow_buffer_surfacepvs);
577 r_shadow_buffer_surfacepvs = NULL;
578 if (r_shadow_buffer_surfacelist)
579 Mem_Free(r_shadow_buffer_surfacelist);
580 r_shadow_buffer_surfacelist = NULL;
581 r_shadow_buffer_numshadowtrispvsbytes = 0;
582 if (r_shadow_buffer_shadowtrispvs)
583 Mem_Free(r_shadow_buffer_shadowtrispvs);
584 r_shadow_buffer_numlighttrispvsbytes = 0;
585 if (r_shadow_buffer_lighttrispvs)
586 Mem_Free(r_shadow_buffer_lighttrispvs);
589 void r_shadow_newmap(void)
591 if (cl.worldmodel && strncmp(cl.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
592 R_Shadow_EditLights_Reload_f();
595 void R_Shadow_Help_f(void)
598 "Documentation on r_shadow system:\n"
600 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
601 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
602 "r_shadow_debuglight : render only this light number (-1 = all)\n"
603 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
604 "r_shadow_gloss2intensity : brightness of forced gloss\n"
605 "r_shadow_glossintensity : brightness of textured gloss\n"
606 "r_shadow_lightattenuationlinearscale : used to generate attenuation texture\n"
607 "r_shadow_lightattenuationdividebias : used to generate attenuation texture\n"
608 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
609 "r_shadow_lightradiusscale : scale rendering radius of all lights\n"
610 "r_shadow_portallight : use portal visibility for static light precomputation\n"
611 "r_shadow_projectdistance : shadow volume projection distance\n"
612 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
613 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
614 "r_shadow_realtime_world : use high quality world lighting mode\n"
615 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
616 "r_shadow_realtime_world_shadows : cast shadows from world lights\n"
617 "r_shadow_realtime_world_compile : compile surface/visibility information\n"
618 "r_shadow_realtime_world_compileshadow : compile shadow geometry\n"
619 "r_shadow_scissor : use scissor optimization\n"
620 "r_shadow_polygonfactor : nudge shadow volumes closer/further\n"
621 "r_shadow_polygonoffset : nudge shadow volumes closer/further\n"
622 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
623 "r_showlighting : useful for performance testing; bright = slow!\n"
624 "r_showshadowvolumes : useful for performance testing; bright = slow!\n"
626 "r_shadow_help : this help\n"
630 void R_Shadow_Init(void)
632 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
633 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
634 Cvar_RegisterVariable(&r_shadow_usenormalmap);
635 Cvar_RegisterVariable(&r_shadow_debuglight);
636 Cvar_RegisterVariable(&r_shadow_gloss);
637 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
638 Cvar_RegisterVariable(&r_shadow_glossintensity);
639 Cvar_RegisterVariable(&r_shadow_glossexponent);
640 Cvar_RegisterVariable(&r_shadow_gloss2exponent);
641 Cvar_RegisterVariable(&r_shadow_glossexact);
642 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
643 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
644 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
645 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
646 Cvar_RegisterVariable(&r_shadow_portallight);
647 Cvar_RegisterVariable(&r_shadow_projectdistance);
648 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
649 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
650 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
651 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
652 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
653 Cvar_RegisterVariable(&r_shadow_realtime_world);
654 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
655 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
656 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
657 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
658 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
659 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
660 Cvar_RegisterVariable(&r_shadow_scissor);
661 Cvar_RegisterVariable(&r_shadow_shadowmapping);
662 Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
663 Cvar_RegisterVariable(&r_shadow_shadowmapping_texturetype);
664 Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
665 Cvar_RegisterVariable(&r_shadow_shadowmapping_precision);
666 Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
667 Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
668 Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
669 Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
670 Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
671 Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
672 Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
673 Cvar_RegisterVariable(&r_shadow_culltriangles);
674 Cvar_RegisterVariable(&r_shadow_polygonfactor);
675 Cvar_RegisterVariable(&r_shadow_polygonoffset);
676 Cvar_RegisterVariable(&r_shadow_texture3d);
677 Cvar_RegisterVariable(&r_coronas);
678 Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
679 Cvar_RegisterVariable(&r_coronas_occlusionquery);
680 Cvar_RegisterVariable(&gl_flashblend);
681 Cvar_RegisterVariable(&gl_ext_separatestencil);
682 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
683 if (gamemode == GAME_TENEBRAE)
685 Cvar_SetValue("r_shadow_gloss", 2);
686 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
688 Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f, "prints documentation on console commands and variables used by realtime lighting and shadowing system");
689 R_Shadow_EditLights_Init();
690 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
691 maxshadowtriangles = 0;
692 shadowelements = NULL;
693 maxshadowvertices = 0;
694 shadowvertex3f = NULL;
702 shadowmarklist = NULL;
707 shadowsideslist = NULL;
708 r_shadow_buffer_numleafpvsbytes = 0;
709 r_shadow_buffer_visitingleafpvs = NULL;
710 r_shadow_buffer_leafpvs = NULL;
711 r_shadow_buffer_leaflist = NULL;
712 r_shadow_buffer_numsurfacepvsbytes = 0;
713 r_shadow_buffer_surfacepvs = NULL;
714 r_shadow_buffer_surfacelist = NULL;
715 r_shadow_buffer_shadowtrispvs = NULL;
716 r_shadow_buffer_lighttrispvs = NULL;
717 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
720 matrix4x4_t matrix_attenuationxyz =
723 {0.5, 0.0, 0.0, 0.5},
724 {0.0, 0.5, 0.0, 0.5},
725 {0.0, 0.0, 0.5, 0.5},
730 matrix4x4_t matrix_attenuationz =
733 {0.0, 0.0, 0.5, 0.5},
734 {0.0, 0.0, 0.0, 0.5},
735 {0.0, 0.0, 0.0, 0.5},
740 void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles, int vertscale, int triscale)
742 numvertices = ((numvertices + 255) & ~255) * vertscale;
743 numtriangles = ((numtriangles + 255) & ~255) * triscale;
744 // make sure shadowelements is big enough for this volume
745 if (maxshadowtriangles < numtriangles)
747 maxshadowtriangles = numtriangles;
749 Mem_Free(shadowelements);
750 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[3]));
752 // make sure shadowvertex3f is big enough for this volume
753 if (maxshadowvertices < numvertices)
755 maxshadowvertices = numvertices;
757 Mem_Free(shadowvertex3f);
758 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[3]));
762 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
764 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
765 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
766 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
767 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
768 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
770 if (r_shadow_buffer_visitingleafpvs)
771 Mem_Free(r_shadow_buffer_visitingleafpvs);
772 if (r_shadow_buffer_leafpvs)
773 Mem_Free(r_shadow_buffer_leafpvs);
774 if (r_shadow_buffer_leaflist)
775 Mem_Free(r_shadow_buffer_leaflist);
776 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
777 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
778 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
779 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
781 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
783 if (r_shadow_buffer_surfacepvs)
784 Mem_Free(r_shadow_buffer_surfacepvs);
785 if (r_shadow_buffer_surfacelist)
786 Mem_Free(r_shadow_buffer_surfacelist);
787 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
788 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
789 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
791 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
793 if (r_shadow_buffer_shadowtrispvs)
794 Mem_Free(r_shadow_buffer_shadowtrispvs);
795 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
796 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
798 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
800 if (r_shadow_buffer_lighttrispvs)
801 Mem_Free(r_shadow_buffer_lighttrispvs);
802 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
803 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
807 void R_Shadow_PrepareShadowMark(int numtris)
809 // make sure shadowmark is big enough for this volume
810 if (maxshadowmark < numtris)
812 maxshadowmark = numtris;
814 Mem_Free(shadowmark);
816 Mem_Free(shadowmarklist);
817 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
818 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
822 // if shadowmarkcount wrapped we clear the array and adjust accordingly
823 if (shadowmarkcount == 0)
826 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
831 void R_Shadow_PrepareShadowSides(int numtris)
833 if (maxshadowsides < numtris)
835 maxshadowsides = numtris;
837 Mem_Free(shadowsides);
839 Mem_Free(shadowsideslist);
840 shadowsides = (unsigned char *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsides));
841 shadowsideslist = (int *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsideslist));
846 static int R_Shadow_ConstructShadowVolume_ZFail(int innumvertices, int innumtris, const int *inelement3i, const int *inneighbor3i, const float *invertex3f, int *outnumvertices, int *outelement3i, float *outvertex3f, const float *projectorigin, const float *projectdirection, float projectdistance, int numshadowmarktris, const int *shadowmarktris)
849 int outtriangles = 0, outvertices = 0;
852 float ratio, direction[3], projectvector[3];
854 if (projectdirection)
855 VectorScale(projectdirection, projectdistance, projectvector);
857 VectorClear(projectvector);
859 // create the vertices
860 if (projectdirection)
862 for (i = 0;i < numshadowmarktris;i++)
864 element = inelement3i + shadowmarktris[i] * 3;
865 for (j = 0;j < 3;j++)
867 if (vertexupdate[element[j]] != vertexupdatenum)
869 vertexupdate[element[j]] = vertexupdatenum;
870 vertexremap[element[j]] = outvertices;
871 vertex = invertex3f + element[j] * 3;
872 // project one copy of the vertex according to projectvector
873 VectorCopy(vertex, outvertex3f);
874 VectorAdd(vertex, projectvector, (outvertex3f + 3));
883 for (i = 0;i < numshadowmarktris;i++)
885 element = inelement3i + shadowmarktris[i] * 3;
886 for (j = 0;j < 3;j++)
888 if (vertexupdate[element[j]] != vertexupdatenum)
890 vertexupdate[element[j]] = vertexupdatenum;
891 vertexremap[element[j]] = outvertices;
892 vertex = invertex3f + element[j] * 3;
893 // project one copy of the vertex to the sphere radius of the light
894 // (FIXME: would projecting it to the light box be better?)
895 VectorSubtract(vertex, projectorigin, direction);
896 ratio = projectdistance / VectorLength(direction);
897 VectorCopy(vertex, outvertex3f);
898 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
906 if (r_shadow_frontsidecasting.integer)
908 for (i = 0;i < numshadowmarktris;i++)
910 int remappedelement[3];
912 const int *neighbortriangle;
914 markindex = shadowmarktris[i] * 3;
915 element = inelement3i + markindex;
916 neighbortriangle = inneighbor3i + markindex;
917 // output the front and back triangles
918 outelement3i[0] = vertexremap[element[0]];
919 outelement3i[1] = vertexremap[element[1]];
920 outelement3i[2] = vertexremap[element[2]];
921 outelement3i[3] = vertexremap[element[2]] + 1;
922 outelement3i[4] = vertexremap[element[1]] + 1;
923 outelement3i[5] = vertexremap[element[0]] + 1;
927 // output the sides (facing outward from this triangle)
928 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
930 remappedelement[0] = vertexremap[element[0]];
931 remappedelement[1] = vertexremap[element[1]];
932 outelement3i[0] = remappedelement[1];
933 outelement3i[1] = remappedelement[0];
934 outelement3i[2] = remappedelement[0] + 1;
935 outelement3i[3] = remappedelement[1];
936 outelement3i[4] = remappedelement[0] + 1;
937 outelement3i[5] = remappedelement[1] + 1;
942 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
944 remappedelement[1] = vertexremap[element[1]];
945 remappedelement[2] = vertexremap[element[2]];
946 outelement3i[0] = remappedelement[2];
947 outelement3i[1] = remappedelement[1];
948 outelement3i[2] = remappedelement[1] + 1;
949 outelement3i[3] = remappedelement[2];
950 outelement3i[4] = remappedelement[1] + 1;
951 outelement3i[5] = remappedelement[2] + 1;
956 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
958 remappedelement[0] = vertexremap[element[0]];
959 remappedelement[2] = vertexremap[element[2]];
960 outelement3i[0] = remappedelement[0];
961 outelement3i[1] = remappedelement[2];
962 outelement3i[2] = remappedelement[2] + 1;
963 outelement3i[3] = remappedelement[0];
964 outelement3i[4] = remappedelement[2] + 1;
965 outelement3i[5] = remappedelement[0] + 1;
974 for (i = 0;i < numshadowmarktris;i++)
976 int remappedelement[3];
978 const int *neighbortriangle;
980 markindex = shadowmarktris[i] * 3;
981 element = inelement3i + markindex;
982 neighbortriangle = inneighbor3i + markindex;
983 // output the front and back triangles
984 outelement3i[0] = vertexremap[element[2]];
985 outelement3i[1] = vertexremap[element[1]];
986 outelement3i[2] = vertexremap[element[0]];
987 outelement3i[3] = vertexremap[element[0]] + 1;
988 outelement3i[4] = vertexremap[element[1]] + 1;
989 outelement3i[5] = vertexremap[element[2]] + 1;
993 // output the sides (facing outward from this triangle)
994 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
996 remappedelement[0] = vertexremap[element[0]];
997 remappedelement[1] = vertexremap[element[1]];
998 outelement3i[0] = remappedelement[0];
999 outelement3i[1] = remappedelement[1];
1000 outelement3i[2] = remappedelement[1] + 1;
1001 outelement3i[3] = remappedelement[0];
1002 outelement3i[4] = remappedelement[1] + 1;
1003 outelement3i[5] = remappedelement[0] + 1;
1008 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1010 remappedelement[1] = vertexremap[element[1]];
1011 remappedelement[2] = vertexremap[element[2]];
1012 outelement3i[0] = remappedelement[1];
1013 outelement3i[1] = remappedelement[2];
1014 outelement3i[2] = remappedelement[2] + 1;
1015 outelement3i[3] = remappedelement[1];
1016 outelement3i[4] = remappedelement[2] + 1;
1017 outelement3i[5] = remappedelement[1] + 1;
1022 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1024 remappedelement[0] = vertexremap[element[0]];
1025 remappedelement[2] = vertexremap[element[2]];
1026 outelement3i[0] = remappedelement[2];
1027 outelement3i[1] = remappedelement[0];
1028 outelement3i[2] = remappedelement[0] + 1;
1029 outelement3i[3] = remappedelement[2];
1030 outelement3i[4] = remappedelement[0] + 1;
1031 outelement3i[5] = remappedelement[2] + 1;
1039 *outnumvertices = outvertices;
1040 return outtriangles;
1043 static int R_Shadow_ConstructShadowVolume_ZPass(int innumvertices, int innumtris, const int *inelement3i, const int *inneighbor3i, const float *invertex3f, int *outnumvertices, int *outelement3i, float *outvertex3f, const float *projectorigin, const float *projectdirection, float projectdistance, int numshadowmarktris, const int *shadowmarktris)
1046 int outtriangles = 0, outvertices = 0;
1048 const float *vertex;
1049 float ratio, direction[3], projectvector[3];
1052 if (projectdirection)
1053 VectorScale(projectdirection, projectdistance, projectvector);
1055 VectorClear(projectvector);
1057 for (i = 0;i < numshadowmarktris;i++)
1059 int remappedelement[3];
1061 const int *neighbortriangle;
1063 markindex = shadowmarktris[i] * 3;
1064 neighbortriangle = inneighbor3i + markindex;
1065 side[0] = shadowmark[neighbortriangle[0]] == shadowmarkcount;
1066 side[1] = shadowmark[neighbortriangle[1]] == shadowmarkcount;
1067 side[2] = shadowmark[neighbortriangle[2]] == shadowmarkcount;
1068 if (side[0] + side[1] + side[2] == 0)
1072 element = inelement3i + markindex;
1074 // create the vertices
1075 for (j = 0;j < 3;j++)
1077 if (side[j] + side[j+1] == 0)
1080 if (vertexupdate[k] != vertexupdatenum)
1082 vertexupdate[k] = vertexupdatenum;
1083 vertexremap[k] = outvertices;
1084 vertex = invertex3f + k * 3;
1085 VectorCopy(vertex, outvertex3f);
1086 if (projectdirection)
1088 // project one copy of the vertex according to projectvector
1089 VectorAdd(vertex, projectvector, (outvertex3f + 3));
1093 // project one copy of the vertex to the sphere radius of the light
1094 // (FIXME: would projecting it to the light box be better?)
1095 VectorSubtract(vertex, projectorigin, direction);
1096 ratio = projectdistance / VectorLength(direction);
1097 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1104 // output the sides (facing outward from this triangle)
1107 remappedelement[0] = vertexremap[element[0]];
1108 remappedelement[1] = vertexremap[element[1]];
1109 outelement3i[0] = remappedelement[1];
1110 outelement3i[1] = remappedelement[0];
1111 outelement3i[2] = remappedelement[0] + 1;
1112 outelement3i[3] = remappedelement[1];
1113 outelement3i[4] = remappedelement[0] + 1;
1114 outelement3i[5] = remappedelement[1] + 1;
1121 remappedelement[1] = vertexremap[element[1]];
1122 remappedelement[2] = vertexremap[element[2]];
1123 outelement3i[0] = remappedelement[2];
1124 outelement3i[1] = remappedelement[1];
1125 outelement3i[2] = remappedelement[1] + 1;
1126 outelement3i[3] = remappedelement[2];
1127 outelement3i[4] = remappedelement[1] + 1;
1128 outelement3i[5] = remappedelement[2] + 1;
1135 remappedelement[0] = vertexremap[element[0]];
1136 remappedelement[2] = vertexremap[element[2]];
1137 outelement3i[0] = remappedelement[0];
1138 outelement3i[1] = remappedelement[2];
1139 outelement3i[2] = remappedelement[2] + 1;
1140 outelement3i[3] = remappedelement[0];
1141 outelement3i[4] = remappedelement[2] + 1;
1142 outelement3i[5] = remappedelement[0] + 1;
1149 *outnumvertices = outvertices;
1150 return outtriangles;
1153 void R_Shadow_MarkVolumeFromBox(int firsttriangle, int numtris, const float *invertex3f, const int *elements, const vec3_t projectorigin, const vec3_t projectdirection, const vec3_t lightmins, const vec3_t lightmaxs, const vec3_t surfacemins, const vec3_t surfacemaxs)
1159 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1161 tend = firsttriangle + numtris;
1162 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1164 // surface box entirely inside light box, no box cull
1165 if (projectdirection)
1167 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1169 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
1170 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1171 shadowmarklist[numshadowmark++] = t;
1176 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1177 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
1178 shadowmarklist[numshadowmark++] = t;
1183 // surface box not entirely inside light box, cull each triangle
1184 if (projectdirection)
1186 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1188 v[0] = invertex3f + e[0] * 3;
1189 v[1] = invertex3f + e[1] * 3;
1190 v[2] = invertex3f + e[2] * 3;
1191 TriangleNormal(v[0], v[1], v[2], normal);
1192 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1193 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1194 shadowmarklist[numshadowmark++] = t;
1199 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1201 v[0] = invertex3f + e[0] * 3;
1202 v[1] = invertex3f + e[1] * 3;
1203 v[2] = invertex3f + e[2] * 3;
1204 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1205 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1206 shadowmarklist[numshadowmark++] = t;
1212 qboolean R_Shadow_UseZPass(vec3_t mins, vec3_t maxs)
1217 if (r_shadow_compilingrtlight || !r_shadow_frontsidecasting.integer || !r_shadow_usezpassifpossible.integer)
1219 // check if the shadow volume intersects the near plane
1221 // a ray between the eye and light origin may intersect the caster,
1222 // indicating that the shadow may touch the eye location, however we must
1223 // test the near plane (a polygon), not merely the eye location, so it is
1224 // easiest to enlarge the caster bounding shape slightly for this.
1230 void R_Shadow_VolumeFromList(int numverts, int numtris, const float *invertex3f, const int *elements, const int *neighbors, const vec3_t projectorigin, const vec3_t projectdirection, float projectdistance, int nummarktris, const int *marktris, vec3_t trismins, vec3_t trismaxs)
1232 int i, tris, outverts;
1233 if (projectdistance < 0.1)
1235 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
1238 if (!numverts || !nummarktris)
1240 // make sure shadowelements is big enough for this volume
1241 if (maxshadowtriangles < nummarktris*8 || maxshadowvertices < numverts*2)
1242 R_Shadow_ResizeShadowArrays(numverts, nummarktris, 2, 8);
1244 if (maxvertexupdate < numverts)
1246 maxvertexupdate = numverts;
1248 Mem_Free(vertexupdate);
1250 Mem_Free(vertexremap);
1251 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1252 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1253 vertexupdatenum = 0;
1256 if (vertexupdatenum == 0)
1258 vertexupdatenum = 1;
1259 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
1260 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
1263 for (i = 0;i < nummarktris;i++)
1264 shadowmark[marktris[i]] = shadowmarkcount;
1266 if (r_shadow_compilingrtlight)
1268 // if we're compiling an rtlight, capture the mesh
1269 //tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1270 //Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zpass, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1271 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1272 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zfail, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1276 // decide which type of shadow to generate and set stencil mode
1277 R_Shadow_RenderMode_StencilShadowVolumes(R_Shadow_UseZPass(trismins, trismaxs));
1278 // generate the sides or a solid volume, depending on type
1279 if (r_shadow_rendermode >= R_SHADOW_RENDERMODE_ZPASS_STENCIL && r_shadow_rendermode <= R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE)
1280 tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1282 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1283 r_refdef.stats.lights_dynamicshadowtriangles += tris;
1284 r_refdef.stats.lights_shadowtriangles += tris;
1286 R_Mesh_VertexPointer(shadowvertex3f, 0, 0);
1287 GL_LockArrays(0, outverts);
1288 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
1290 // increment stencil if frontface is infront of depthbuffer
1291 GL_CullFace(r_refdef.view.cullface_front);
1292 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1293 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1294 // decrement stencil if backface is infront of depthbuffer
1295 GL_CullFace(r_refdef.view.cullface_back);
1296 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1298 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
1300 // decrement stencil if backface is behind depthbuffer
1301 GL_CullFace(r_refdef.view.cullface_front);
1302 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1303 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1304 // increment stencil if frontface is behind depthbuffer
1305 GL_CullFace(r_refdef.view.cullface_back);
1306 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1308 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1309 GL_LockArrays(0, 0);
1314 int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias)
1316 // p1, p2, p3 are in the cubemap's local coordinate system
1317 // bias = border/(size - border)
1320 float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1321 dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2),
1322 dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3);
1323 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1325 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1326 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1327 | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1328 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1330 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1331 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1332 | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1334 dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1335 dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2),
1336 dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3);
1337 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1339 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1340 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1341 | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1342 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1344 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1345 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1346 | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1348 dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1349 dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2),
1350 dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3);
1351 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1353 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1354 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1355 | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1356 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1358 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1359 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1360 | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1365 int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
1367 // p is in the cubemap's local coordinate system
1368 // bias = border/(size - border)
1369 float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn);
1370 float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn);
1371 float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn);
1373 if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
1374 if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
1375 if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
1376 if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
1377 if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
1378 if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
1382 int R_Shadow_FrustumCullSides(rtlight_t *rtlight, float size, float border)
1384 static const vec3_t lightnormals[6] = { { 1, 0, 0 }, { -1, 0, 0 }, { 0, 1, 0 }, { 0, -1, 0 }, { 0, 0, 1 }, { 0, 0, -1 } };
1389 float scale = 0.707106781186548*size/(size - 2*border);
1390 for (i = 0;i < 5;i++)
1392 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) > -0.03125)
1394 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[i].normal, frustumdir);
1395 VectorNormalize(frustumdir);
1396 for (j = 0;j < 6;j++)
1397 if(DotProduct(frustumdir, lightnormals[j]) < -scale)
1400 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[4]) > r_refdef.farclip - r_refdef.nearclip + 0.03125)
1402 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[4].normal, frustumdir);
1403 VectorNormalize(frustumdir);
1404 for (j = 0;j < 6;j++)
1405 if (DotProduct(frustumdir, lightnormals[j]) > scale)
1411 int R_Shadow_ChooseSidesFromBox(int firsttriangle, int numtris, const float *invertex3f, const int *elements, const matrix4x4_t *worldtolight, const vec3_t projectorigin, const vec3_t projectdirection, const vec3_t lightmins, const vec3_t lightmaxs, const vec3_t surfacemins, const vec3_t surfacemaxs, int *totals)
1419 int mask, surfacemask = 0;
1420 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1422 bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
1423 tend = firsttriangle + numtris;
1424 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1426 // surface box entirely inside light box, no box cull
1427 if (projectdirection)
1429 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1431 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1432 TriangleNormal(v[0], v[1], v[2], normal);
1433 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1435 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1436 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1437 surfacemask |= mask;
1440 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;
1441 shadowsides[numshadowsides] = mask;
1442 shadowsideslist[numshadowsides++] = t;
1449 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1451 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1452 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]))
1454 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1455 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1456 surfacemask |= mask;
1459 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;
1460 shadowsides[numshadowsides] = mask;
1461 shadowsideslist[numshadowsides++] = t;
1469 // surface box not entirely inside light box, cull each triangle
1470 if (projectdirection)
1472 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1474 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1475 TriangleNormal(v[0], v[1], v[2], normal);
1476 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1477 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1479 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1480 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1481 surfacemask |= mask;
1484 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;
1485 shadowsides[numshadowsides] = mask;
1486 shadowsideslist[numshadowsides++] = t;
1493 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1495 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1496 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1497 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1499 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1500 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1501 surfacemask |= mask;
1504 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;
1505 shadowsides[numshadowsides] = mask;
1506 shadowsideslist[numshadowsides++] = t;
1515 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)
1517 int i, j, outtriangles = 0;
1518 int *outelement3i[6];
1519 if (!numverts || !numsidetris || !r_shadow_compilingrtlight)
1521 outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5];
1522 // make sure shadowelements is big enough for this mesh
1523 if (maxshadowtriangles < outtriangles)
1524 R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1);
1526 // compute the offset and size of the separate index lists for each cubemap side
1528 for (i = 0;i < 6;i++)
1530 outelement3i[i] = shadowelements + outtriangles * 3;
1531 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles;
1532 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i];
1533 outtriangles += sidetotals[i];
1536 // gather up the (sparse) triangles into separate index lists for each cubemap side
1537 for (i = 0;i < numsidetris;i++)
1539 const int *element = elements + sidetris[i] * 3;
1540 for (j = 0;j < 6;j++)
1542 if (sides[i] & (1 << j))
1544 outelement3i[j][0] = element[0];
1545 outelement3i[j][1] = element[1];
1546 outelement3i[j][2] = element[2];
1547 outelement3i[j] += 3;
1552 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, outtriangles, shadowelements);
1555 static void R_Shadow_MakeTextures_MakeCorona(void)
1559 unsigned char pixels[32][32][4];
1560 for (y = 0;y < 32;y++)
1562 dy = (y - 15.5f) * (1.0f / 16.0f);
1563 for (x = 0;x < 32;x++)
1565 dx = (x - 15.5f) * (1.0f / 16.0f);
1566 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1567 a = bound(0, a, 255);
1568 pixels[y][x][0] = a;
1569 pixels[y][x][1] = a;
1570 pixels[y][x][2] = a;
1571 pixels[y][x][3] = 255;
1574 r_shadow_lightcorona = R_LoadTexture2D(r_shadow_texturepool, "lightcorona", 32, 32, &pixels[0][0][0], TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_FORCELINEAR, NULL);
1577 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1579 float dist = sqrt(x*x+y*y+z*z);
1580 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1581 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1582 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1585 static void R_Shadow_MakeTextures(void)
1588 float intensity, dist;
1590 R_FreeTexturePool(&r_shadow_texturepool);
1591 r_shadow_texturepool = R_AllocTexturePool();
1592 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1593 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1594 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1595 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1596 for (x = 0;x <= ATTENTABLESIZE;x++)
1598 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1599 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1600 r_shadow_attentable[x] = bound(0, intensity, 1);
1602 // 1D gradient texture
1603 for (x = 0;x < ATTEN1DSIZE;x++)
1604 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1605 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);
1606 // 2D circle texture
1607 for (y = 0;y < ATTEN2DSIZE;y++)
1608 for (x = 0;x < ATTEN2DSIZE;x++)
1609 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);
1610 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);
1611 // 3D sphere texture
1612 if (r_shadow_texture3d.integer && gl_texture3d)
1614 for (z = 0;z < ATTEN3DSIZE;z++)
1615 for (y = 0;y < ATTEN3DSIZE;y++)
1616 for (x = 0;x < ATTEN3DSIZE;x++)
1617 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));
1618 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);
1621 r_shadow_attenuation3dtexture = NULL;
1624 R_Shadow_MakeTextures_MakeCorona();
1626 // Editor light sprites
1627 r_editlights_sprcursor = Draw_CachePic ("gfx/editlights/cursor");
1628 r_editlights_sprlight = Draw_CachePic ("gfx/editlights/light");
1629 r_editlights_sprnoshadowlight = Draw_CachePic ("gfx/editlights/noshadow");
1630 r_editlights_sprcubemaplight = Draw_CachePic ("gfx/editlights/cubemaplight");
1631 r_editlights_sprcubemapnoshadowlight = Draw_CachePic ("gfx/editlights/cubemapnoshadowlight");
1632 r_editlights_sprselection = Draw_CachePic ("gfx/editlights/selection");
1635 void R_Shadow_ValidateCvars(void)
1637 if (r_shadow_texture3d.integer && !gl_texture3d)
1638 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1639 if (gl_ext_separatestencil.integer && !gl_support_separatestencil)
1640 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
1641 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
1642 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1645 void R_Shadow_RenderMode_Begin(void)
1649 R_Shadow_ValidateCvars();
1651 if (!r_shadow_attenuation2dtexture
1652 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1653 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1654 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1655 R_Shadow_MakeTextures();
1658 R_Mesh_ColorPointer(NULL, 0, 0);
1659 R_Mesh_ResetTextureState();
1660 GL_BlendFunc(GL_ONE, GL_ZERO);
1661 GL_DepthRange(0, 1);
1662 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1664 GL_DepthMask(false);
1665 GL_Color(0, 0, 0, 1);
1666 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1668 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1670 if (gl_ext_separatestencil.integer)
1672 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
1673 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
1675 else if (gl_ext_stenciltwoside.integer)
1677 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
1678 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
1682 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
1683 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
1686 if (r_glsl.integer && gl_support_fragment_shader)
1687 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1688 else if (gl_dot3arb && gl_texturecubemap && r_textureunits.integer >= 2 && gl_combine.integer && gl_stencil)
1689 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_DOT3;
1691 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1694 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
1695 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
1696 r_shadow_drawbuffer = drawbuffer;
1697 r_shadow_readbuffer = readbuffer;
1698 r_shadow_cullface = r_refdef.view.cullface_back;
1701 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
1703 rsurface.rtlight = rtlight;
1706 void R_Shadow_RenderMode_Reset(void)
1709 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE)
1711 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1713 if (gl_support_ext_framebuffer_object)
1715 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);CHECKGLERROR
1717 qglDrawBuffer(r_shadow_drawbuffer);CHECKGLERROR
1718 qglReadBuffer(r_shadow_readbuffer);CHECKGLERROR
1719 R_SetViewport(&r_refdef.view.viewport);
1720 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
1721 R_Mesh_ColorPointer(NULL, 0, 0);
1722 R_Mesh_ResetTextureState();
1723 GL_DepthRange(0, 1);
1725 GL_DepthMask(false);
1726 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1727 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1728 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
1729 qglStencilMask(~0);CHECKGLERROR
1730 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
1731 qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
1732 r_refdef.view.cullface_back = r_shadow_cullface;
1733 GL_CullFace(r_refdef.view.cullface_back);
1734 GL_Color(1, 1, 1, 1);
1735 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
1736 GL_BlendFunc(GL_ONE, GL_ZERO);
1737 R_SetupGenericShader(false);
1738 r_shadow_usingshadowmaprect = false;
1739 r_shadow_usingshadowmapcube = false;
1740 r_shadow_usingshadowmap2d = false;
1744 void R_Shadow_ClearStencil(void)
1747 GL_Clear(GL_STENCIL_BUFFER_BIT);
1748 r_refdef.stats.lights_clears++;
1751 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
1753 r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
1754 if (r_shadow_rendermode == mode)
1757 R_Shadow_RenderMode_Reset();
1758 GL_ColorMask(0, 0, 0, 0);
1759 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1760 R_SetupDepthOrShadowShader();
1761 qglDepthFunc(GL_LESS);CHECKGLERROR
1762 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1763 r_shadow_rendermode = mode;
1768 case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
1769 GL_CullFace(GL_NONE);
1770 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1771 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1773 case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
1774 GL_CullFace(GL_NONE);
1775 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1776 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1778 case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
1779 GL_CullFace(GL_NONE);
1780 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1781 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
1782 qglStencilMask(~0);CHECKGLERROR
1783 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1784 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
1785 qglStencilMask(~0);CHECKGLERROR
1786 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1788 case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
1789 GL_CullFace(GL_NONE);
1790 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1791 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
1792 qglStencilMask(~0);CHECKGLERROR
1793 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1794 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
1795 qglStencilMask(~0);CHECKGLERROR
1796 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1801 static void R_Shadow_MakeVSDCT(void)
1803 // maps to a 2x3 texture rectangle with normalized coordinates
1808 // stores abs(dir.xy), offset.xy/2.5
1809 unsigned char data[4*6] =
1811 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
1812 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
1813 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
1814 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
1815 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
1816 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
1818 r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_ALWAYSPRECACHE | TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, NULL);
1821 void R_Shadow_RenderMode_ShadowMap(int side, qboolean clear, int size)
1826 float nearclip, farclip, bias;
1827 r_viewport_t viewport;
1829 maxsize = r_shadow_shadowmapmaxsize;
1830 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
1832 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
1833 r_shadow_shadowmap_parameters[2] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
1834 r_shadow_shadowmap_parameters[3] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
1835 r_shadow_shadowmapside = side;
1836 r_shadow_shadowmapsize = size;
1837 if (r_shadow_shadowmode == 1)
1839 // complex unrolled cube approach (more flexible)
1840 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
1841 R_Shadow_MakeVSDCT();
1842 if (!r_shadow_shadowmap2dtexture)
1845 int w = maxsize*2, h = gl_support_arb_texture_non_power_of_two ? maxsize*3 : maxsize*4;
1846 r_shadow_shadowmap2dtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "shadowmap", w, h, r_shadow_shadowmapprecision, r_shadow_shadowmapsampler);
1847 qglGenFramebuffersEXT(1, &r_shadow_fbo2d);CHECKGLERROR
1848 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbo2d);CHECKGLERROR
1849 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_shadowmap2dtexture), 0);CHECKGLERROR
1853 R_Shadow_RenderMode_Reset();
1854 if (r_shadow_shadowmap2dtexture)
1856 // render depth into the fbo, do not render color at all
1857 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbo2d);CHECKGLERROR
1858 qglDrawBuffer(GL_NONE);CHECKGLERROR
1859 qglReadBuffer(GL_NONE);CHECKGLERROR
1860 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
1861 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
1863 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
1864 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
1866 R_SetupDepthOrShadowShader();
1870 R_SetupShowDepthShader();
1871 qglClearColor(1,1,1,1);CHECKGLERROR
1873 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
1874 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
1875 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
1876 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
1877 r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
1878 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
1880 else if (r_shadow_shadowmode == 2)
1882 // complex unrolled cube approach (more flexible)
1883 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
1884 R_Shadow_MakeVSDCT();
1885 if (!r_shadow_shadowmaprectangletexture)
1888 r_shadow_shadowmaprectangletexture = R_LoadTextureShadowMapRectangle(r_shadow_texturepool, "shadowmap", maxsize*2, maxsize*3, r_shadow_shadowmapprecision, r_shadow_shadowmapsampler);
1889 qglGenFramebuffersEXT(1, &r_shadow_fborectangle);CHECKGLERROR
1890 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fborectangle);CHECKGLERROR
1891 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, R_GetTexture(r_shadow_shadowmaprectangletexture), 0);CHECKGLERROR
1895 R_Shadow_RenderMode_Reset();
1896 if (r_shadow_shadowmaprectangletexture)
1898 // render depth into the fbo, do not render color at all
1899 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fborectangle);CHECKGLERROR
1900 qglDrawBuffer(GL_NONE);CHECKGLERROR
1901 qglReadBuffer(GL_NONE);CHECKGLERROR
1902 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
1903 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
1905 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
1906 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
1908 R_SetupDepthOrShadowShader();
1912 R_SetupShowDepthShader();
1913 qglClearColor(1,1,1,1);CHECKGLERROR
1915 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
1916 r_shadow_shadowmap_texturescale[0] = 1.0f;
1917 r_shadow_shadowmap_texturescale[1] = 1.0f;
1918 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
1919 r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
1920 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE;
1922 else if (r_shadow_shadowmode == 3)
1924 // simple cube approach
1925 if (!r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod])
1928 r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod] = R_LoadTextureShadowMapCube(r_shadow_texturepool, "shadowmapcube", size, r_shadow_shadowmapprecision, r_shadow_shadowmapsampler);
1929 qglGenFramebuffersEXT(6, r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR
1930 for (i = 0;i < 6;i++)
1932 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbocubeside[r_shadow_shadowmaplod][i]);CHECKGLERROR
1933 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
1938 R_Shadow_RenderMode_Reset();
1939 if (r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod])
1941 // render depth into the fbo, do not render color at all
1942 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbocubeside[r_shadow_shadowmaplod][side]);CHECKGLERROR
1943 qglDrawBuffer(GL_NONE);CHECKGLERROR
1944 qglReadBuffer(GL_NONE);CHECKGLERROR
1945 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
1946 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
1948 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
1949 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
1951 R_SetupDepthOrShadowShader();
1955 R_SetupShowDepthShader();
1956 qglClearColor(1,1,1,1);CHECKGLERROR
1958 R_Viewport_InitCubeSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, nearclip, farclip, NULL);
1959 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]);
1960 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureWidth(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]);
1961 r_shadow_shadowmap_parameters[0] = 1.0f;
1962 r_shadow_shadowmap_parameters[1] = 1.0f;
1963 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE;
1966 R_SetViewport(&viewport);
1967 GL_PolygonOffset(0, 0);
1968 if(r_shadow_shadowmode >= 1 && r_shadow_shadowmode <= 2)
1970 static qboolean cullfront[6] = { false, true, false, true, true, false };
1971 if(cullfront[side]) r_refdef.view.cullface_back = r_refdef.view.cullface_front;
1973 GL_CullFace(r_refdef.view.cullface_back);
1974 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
1977 qglClearDepth(1);CHECKGLERROR
1980 qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
1984 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
1987 R_Shadow_RenderMode_Reset();
1988 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1991 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1995 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1996 // only draw light where this geometry was already rendered AND the
1997 // stencil is 128 (values other than this mean shadow)
1998 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
2000 r_shadow_rendermode = r_shadow_lightingrendermode;
2001 // do global setup needed for the chosen lighting mode
2002 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2004 R_Mesh_TexBindCubeMap(GL20TU_CUBE, R_GetTexture(rsurface.rtlight->currentcubemap)); // light filter
2005 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2009 if (r_shadow_shadowmode == 1)
2011 r_shadow_usingshadowmap2d = true;
2012 R_Mesh_TexBind(GL20TU_SHADOWMAP2D, R_GetTexture(r_shadow_shadowmap2dtexture));
2015 else if (r_shadow_shadowmode == 2)
2017 r_shadow_usingshadowmaprect = true;
2018 R_Mesh_TexBindRectangle(GL20TU_SHADOWMAPRECT, R_GetTexture(r_shadow_shadowmaprectangletexture));
2021 else if (r_shadow_shadowmode == 3)
2023 r_shadow_usingshadowmapcube = true;
2024 R_Mesh_TexBindCubeMap(GL20TU_SHADOWMAPCUBE, R_GetTexture(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]));
2028 if (r_shadow_shadowmapvsdct && (r_shadow_usingshadowmap2d || r_shadow_usingshadowmaprect))
2030 R_Mesh_TexBindCubeMap(GL20TU_CUBEPROJECTION, R_GetTexture(r_shadow_shadowmapvsdcttexture));
2035 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_VERTEX)
2036 R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
2037 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2041 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
2044 R_Shadow_RenderMode_Reset();
2045 GL_BlendFunc(GL_ONE, GL_ONE);
2046 GL_DepthRange(0, 1);
2047 GL_DepthTest(r_showshadowvolumes.integer < 2);
2048 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
2049 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2050 GL_CullFace(GL_NONE);
2051 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
2054 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
2057 R_Shadow_RenderMode_Reset();
2058 GL_BlendFunc(GL_ONE, GL_ONE);
2059 GL_DepthRange(0, 1);
2060 GL_DepthTest(r_showlighting.integer < 2);
2061 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2064 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2068 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2069 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
2071 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2074 void R_Shadow_RenderMode_End(void)
2077 R_Shadow_RenderMode_Reset();
2078 R_Shadow_RenderMode_ActiveLight(NULL);
2080 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2081 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2084 int bboxedges[12][2] =
2103 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2105 int i, ix1, iy1, ix2, iy2;
2106 float x1, y1, x2, y2;
2108 float vertex[20][3];
2117 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2118 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2119 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2120 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2122 if (!r_shadow_scissor.integer)
2125 // if view is inside the light box, just say yes it's visible
2126 if (BoxesOverlap(r_refdef.view.origin, r_refdef.view.origin, mins, maxs))
2129 x1 = y1 = x2 = y2 = 0;
2131 // transform all corners that are infront of the nearclip plane
2132 VectorNegate(r_refdef.view.frustum[4].normal, plane4f);
2133 plane4f[3] = r_refdef.view.frustum[4].dist;
2135 for (i = 0;i < 8;i++)
2137 Vector4Set(corner[i], (i & 1) ? maxs[0] : mins[0], (i & 2) ? maxs[1] : mins[1], (i & 4) ? maxs[2] : mins[2], 1);
2138 dist[i] = DotProduct4(corner[i], plane4f);
2139 sign[i] = dist[i] > 0;
2142 VectorCopy(corner[i], vertex[numvertices]);
2146 // if some points are behind the nearclip, add clipped edge points to make
2147 // sure that the scissor boundary is complete
2148 if (numvertices > 0 && numvertices < 8)
2150 // add clipped edge points
2151 for (i = 0;i < 12;i++)
2153 j = bboxedges[i][0];
2154 k = bboxedges[i][1];
2155 if (sign[j] != sign[k])
2157 f = dist[j] / (dist[j] - dist[k]);
2158 VectorLerp(corner[j], f, corner[k], vertex[numvertices]);
2164 // if we have no points to check, the light is behind the view plane
2168 // if we have some points to transform, check what screen area is covered
2169 x1 = y1 = x2 = y2 = 0;
2171 //Con_Printf("%i vertices to transform...\n", numvertices);
2172 for (i = 0;i < numvertices;i++)
2174 VectorCopy(vertex[i], v);
2175 R_Viewport_TransformToScreen(&r_refdef.view.viewport, v, v2);
2176 //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]);
2179 if (x1 > v2[0]) x1 = v2[0];
2180 if (x2 < v2[0]) x2 = v2[0];
2181 if (y1 > v2[1]) y1 = v2[1];
2182 if (y2 < v2[1]) y2 = v2[1];
2191 // now convert the scissor rectangle to integer screen coordinates
2192 ix1 = (int)(x1 - 1.0f);
2193 iy1 = vid.height - (int)(y2 - 1.0f);
2194 ix2 = (int)(x2 + 1.0f);
2195 iy2 = vid.height - (int)(y1 + 1.0f);
2196 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
2198 // clamp it to the screen
2199 if (ix1 < r_refdef.view.viewport.x) ix1 = r_refdef.view.viewport.x;
2200 if (iy1 < r_refdef.view.viewport.y) iy1 = r_refdef.view.viewport.y;
2201 if (ix2 > r_refdef.view.viewport.x + r_refdef.view.viewport.width) ix2 = r_refdef.view.viewport.x + r_refdef.view.viewport.width;
2202 if (iy2 > r_refdef.view.viewport.y + r_refdef.view.viewport.height) iy2 = r_refdef.view.viewport.y + r_refdef.view.viewport.height;
2204 // if it is inside out, it's not visible
2205 if (ix2 <= ix1 || iy2 <= iy1)
2208 // the light area is visible, set up the scissor rectangle
2209 r_shadow_lightscissor[0] = ix1;
2210 r_shadow_lightscissor[1] = iy1;
2211 r_shadow_lightscissor[2] = ix2 - ix1;
2212 r_shadow_lightscissor[3] = iy2 - iy1;
2214 r_refdef.stats.lights_scissored++;
2218 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, int numtriangles, const int *element3i, const float *diffusecolor, const float *ambientcolor)
2220 float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
2221 float *normal3f = rsurface.normal3f + 3 * firstvertex;
2222 float *color4f = rsurface.array_color4f + 4 * firstvertex;
2223 float dist, dot, distintensity, shadeintensity, v[3], n[3];
2224 if (r_textureunits.integer >= 3)
2226 if (VectorLength2(diffusecolor) > 0)
2228 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2230 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2231 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2232 if ((dot = DotProduct(n, v)) < 0)
2234 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2235 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
2238 VectorCopy(ambientcolor, color4f);
2239 if (r_refdef.fogenabled)
2242 f = FogPoint_Model(vertex3f);
2243 VectorScale(color4f, f, color4f);
2250 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2252 VectorCopy(ambientcolor, color4f);
2253 if (r_refdef.fogenabled)
2256 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2257 f = FogPoint_Model(vertex3f);
2258 VectorScale(color4f, f, color4f);
2264 else if (r_textureunits.integer >= 2)
2266 if (VectorLength2(diffusecolor) > 0)
2268 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2270 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2271 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2273 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2274 if ((dot = DotProduct(n, v)) < 0)
2276 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2277 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2278 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2279 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2283 color4f[0] = ambientcolor[0] * distintensity;
2284 color4f[1] = ambientcolor[1] * distintensity;
2285 color4f[2] = ambientcolor[2] * distintensity;
2287 if (r_refdef.fogenabled)
2290 f = FogPoint_Model(vertex3f);
2291 VectorScale(color4f, f, color4f);
2295 VectorClear(color4f);
2301 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2303 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2304 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2306 color4f[0] = ambientcolor[0] * distintensity;
2307 color4f[1] = ambientcolor[1] * distintensity;
2308 color4f[2] = ambientcolor[2] * distintensity;
2309 if (r_refdef.fogenabled)
2312 f = FogPoint_Model(vertex3f);
2313 VectorScale(color4f, f, color4f);
2317 VectorClear(color4f);
2324 if (VectorLength2(diffusecolor) > 0)
2326 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2328 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2329 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2331 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2332 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2333 if ((dot = DotProduct(n, v)) < 0)
2335 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2336 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2337 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2338 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2342 color4f[0] = ambientcolor[0] * distintensity;
2343 color4f[1] = ambientcolor[1] * distintensity;
2344 color4f[2] = ambientcolor[2] * distintensity;
2346 if (r_refdef.fogenabled)
2349 f = FogPoint_Model(vertex3f);
2350 VectorScale(color4f, f, color4f);
2354 VectorClear(color4f);
2360 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2362 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2363 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2365 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2366 color4f[0] = ambientcolor[0] * distintensity;
2367 color4f[1] = ambientcolor[1] * distintensity;
2368 color4f[2] = ambientcolor[2] * distintensity;
2369 if (r_refdef.fogenabled)
2372 f = FogPoint_Model(vertex3f);
2373 VectorScale(color4f, f, color4f);
2377 VectorClear(color4f);
2384 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
2386 static void R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
2389 float *out3f = rsurface.array_texcoord3f + 3 * firstvertex;
2390 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
2391 const float *svector3f = rsurface.svector3f + 3 * firstvertex;
2392 const float *tvector3f = rsurface.tvector3f + 3 * firstvertex;
2393 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
2395 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
2397 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
2398 // the cubemap normalizes this for us
2399 out3f[0] = DotProduct(svector3f, lightdir);
2400 out3f[1] = DotProduct(tvector3f, lightdir);
2401 out3f[2] = DotProduct(normal3f, lightdir);
2405 static void R_Shadow_GenTexCoords_Specular_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
2408 float *out3f = rsurface.array_texcoord3f + 3 * firstvertex;
2409 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
2410 const float *svector3f = rsurface.svector3f + 3 * firstvertex;
2411 const float *tvector3f = rsurface.tvector3f + 3 * firstvertex;
2412 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
2413 float lightdir[3], eyedir[3], halfdir[3];
2414 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
2416 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
2417 VectorNormalize(lightdir);
2418 VectorSubtract(rsurface.modelorg, vertex3f, eyedir);
2419 VectorNormalize(eyedir);
2420 VectorAdd(lightdir, eyedir, halfdir);
2421 // the cubemap normalizes this for us
2422 out3f[0] = DotProduct(svector3f, halfdir);
2423 out3f[1] = DotProduct(tvector3f, halfdir);
2424 out3f[2] = DotProduct(normal3f, halfdir);
2428 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)
2430 // used to display how many times a surface is lit for level design purposes
2431 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2434 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)
2436 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2437 R_SetupSurfaceShader(lightcolorbase, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT);
2438 if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND))
2439 R_Mesh_ColorPointer(rsurface.modellightmapcolor4f, rsurface.modellightmapcolor4f_bufferobject, rsurface.modellightmapcolor4f_bufferoffset);
2441 R_Mesh_ColorPointer(NULL, 0, 0);
2442 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
2443 R_Mesh_TexMatrix(1, &rsurface.texture->currentbackgroundtexmatrix);
2444 R_Mesh_TexBind(GL20TU_NORMAL, R_GetTexture(rsurface.texture->currentskinframe->nmap));
2445 R_Mesh_TexBind(GL20TU_COLOR, R_GetTexture(rsurface.texture->basetexture));
2446 R_Mesh_TexBind(GL20TU_GLOSS, R_GetTexture(rsurface.texture->glosstexture));
2447 if (rsurface.texture->backgroundcurrentskinframe)
2449 R_Mesh_TexBind(GL20TU_SECONDARY_NORMAL, R_GetTexture(rsurface.texture->backgroundcurrentskinframe->nmap));
2450 R_Mesh_TexBind(GL20TU_SECONDARY_COLOR, R_GetTexture(rsurface.texture->backgroundbasetexture));
2451 R_Mesh_TexBind(GL20TU_SECONDARY_GLOSS, R_GetTexture(rsurface.texture->backgroundglosstexture));
2452 R_Mesh_TexBind(GL20TU_SECONDARY_GLOW, R_GetTexture(rsurface.texture->backgroundcurrentskinframe->glow));
2454 //R_Mesh_TexBindCubeMap(GL20TU_CUBE, R_GetTexture(rsurface.rtlight->currentcubemap));
2455 R_Mesh_TexBind(GL20TU_FOGMASK, R_GetTexture(r_texture_fogattenuation));
2456 if(rsurface.texture->colormapping)
2458 R_Mesh_TexBind(GL20TU_PANTS, R_GetTexture(rsurface.texture->currentskinframe->pants));
2459 R_Mesh_TexBind(GL20TU_SHIRT, R_GetTexture(rsurface.texture->currentskinframe->shirt));
2461 R_Mesh_TexBind(GL20TU_ATTENUATION, R_GetTexture(r_shadow_attenuationgradienttexture));
2462 R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
2463 R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset);
2464 R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset);
2465 R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset);
2466 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2468 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2470 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2471 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2473 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
2477 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)
2479 // shared final code for all the dot3 layers
2481 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2482 for (renders = 0;renders < 64 && (r > 0 || g > 0 || b > 0);renders++, r--, g--, b--)
2484 GL_Color(bound(0, r, 1), bound(0, g, 1), bound(0, b, 1), 1);
2485 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2489 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)
2492 // colorscale accounts for how much we multiply the brightness
2495 // mult is how many times the final pass of the lighting will be
2496 // performed to get more brightness than otherwise possible.
2498 // Limit mult to 64 for sanity sake.
2500 if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
2502 // 3 3D combine path (Geforce3, Radeon 8500)
2503 memset(&m, 0, sizeof(m));
2504 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2505 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2506 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2507 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2508 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2509 m.tex[1] = R_GetTexture(basetexture);
2510 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
2511 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
2512 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
2513 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
2514 m.texcubemap[2] = R_GetTexture(rsurface.rtlight->currentcubemap);
2515 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2516 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2517 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2518 m.texmatrix[2] = rsurface.entitytolight;
2519 GL_BlendFunc(GL_ONE, GL_ONE);
2521 else if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
2523 // 2 3D combine path (Geforce3, original Radeon)
2524 memset(&m, 0, sizeof(m));
2525 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2526 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2527 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2528 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2529 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2530 m.tex[1] = R_GetTexture(basetexture);
2531 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
2532 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
2533 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
2534 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
2535 GL_BlendFunc(GL_ONE, GL_ONE);
2537 else if (r_textureunits.integer >= 4 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2539 // 4 2D combine path (Geforce3, Radeon 8500)
2540 memset(&m, 0, sizeof(m));
2541 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2542 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2543 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2544 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2545 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2546 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2547 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2548 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2549 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2550 m.texmatrix[1] = rsurface.entitytoattenuationz;
2551 m.tex[2] = R_GetTexture(basetexture);
2552 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
2553 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
2554 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
2555 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
2556 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2558 m.texcubemap[3] = R_GetTexture(rsurface.rtlight->currentcubemap);
2559 m.pointer_texcoord3f[3] = rsurface.vertex3f;
2560 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
2561 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
2562 m.texmatrix[3] = rsurface.entitytolight;
2564 GL_BlendFunc(GL_ONE, GL_ONE);
2566 else if (r_textureunits.integer >= 3 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
2568 // 3 2D combine path (Geforce3, original Radeon)
2569 memset(&m, 0, sizeof(m));
2570 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2571 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2572 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2573 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2574 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2575 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2576 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2577 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2578 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2579 m.texmatrix[1] = rsurface.entitytoattenuationz;
2580 m.tex[2] = R_GetTexture(basetexture);
2581 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
2582 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
2583 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
2584 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
2585 GL_BlendFunc(GL_ONE, GL_ONE);
2589 // 2/2/2 2D combine path (any dot3 card)
2590 memset(&m, 0, sizeof(m));
2591 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2592 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2593 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2594 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2595 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2596 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2597 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2598 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2599 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2600 m.texmatrix[1] = rsurface.entitytoattenuationz;
2601 R_Mesh_TextureState(&m);
2602 GL_ColorMask(0,0,0,1);
2603 GL_BlendFunc(GL_ONE, GL_ZERO);
2604 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2607 memset(&m, 0, sizeof(m));
2608 m.tex[0] = R_GetTexture(basetexture);
2609 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2610 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2611 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2612 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2613 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2615 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2616 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2617 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2618 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2619 m.texmatrix[1] = rsurface.entitytolight;
2621 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2623 // this final code is shared
2624 R_Mesh_TextureState(&m);
2625 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);
2628 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)
2631 // colorscale accounts for how much we multiply the brightness
2634 // mult is how many times the final pass of the lighting will be
2635 // performed to get more brightness than otherwise possible.
2637 // Limit mult to 64 for sanity sake.
2639 // generate normalization cubemap texcoords
2640 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
2641 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
2643 // 3/2 3D combine path (Geforce3, Radeon 8500)
2644 memset(&m, 0, sizeof(m));
2645 m.tex[0] = R_GetTexture(normalmaptexture);
2646 m.texcombinergb[0] = GL_REPLACE;
2647 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2648 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2649 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2650 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2651 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2652 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2653 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2654 m.pointer_texcoord_bufferobject[1] = 0;
2655 m.pointer_texcoord_bufferoffset[1] = 0;
2656 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
2657 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2658 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2659 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2660 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
2661 R_Mesh_TextureState(&m);
2662 GL_ColorMask(0,0,0,1);
2663 GL_BlendFunc(GL_ONE, 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 // 1/2/2 3D combine path (original Radeon)
2686 memset(&m, 0, sizeof(m));
2687 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2688 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2689 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2690 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2691 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2692 R_Mesh_TextureState(&m);
2693 GL_ColorMask(0,0,0,1);
2694 GL_BlendFunc(GL_ONE, GL_ZERO);
2695 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2698 memset(&m, 0, sizeof(m));
2699 m.tex[0] = R_GetTexture(normalmaptexture);
2700 m.texcombinergb[0] = GL_REPLACE;
2701 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2702 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2703 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2704 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2705 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2706 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2707 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2708 m.pointer_texcoord_bufferobject[1] = 0;
2709 m.pointer_texcoord_bufferoffset[1] = 0;
2710 R_Mesh_TextureState(&m);
2711 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2712 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2715 memset(&m, 0, sizeof(m));
2716 m.tex[0] = R_GetTexture(basetexture);
2717 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2718 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2719 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2720 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2721 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2723 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2724 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2725 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2726 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2727 m.texmatrix[1] = rsurface.entitytolight;
2729 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2731 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
2733 // 2/2 3D combine path (original Radeon)
2734 memset(&m, 0, sizeof(m));
2735 m.tex[0] = R_GetTexture(normalmaptexture);
2736 m.texcombinergb[0] = GL_REPLACE;
2737 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2738 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2739 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2740 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2741 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2742 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2743 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2744 m.pointer_texcoord_bufferobject[1] = 0;
2745 m.pointer_texcoord_bufferoffset[1] = 0;
2746 R_Mesh_TextureState(&m);
2747 GL_ColorMask(0,0,0,1);
2748 GL_BlendFunc(GL_ONE, GL_ZERO);
2749 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2752 memset(&m, 0, sizeof(m));
2753 m.tex[0] = R_GetTexture(basetexture);
2754 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2755 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2756 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2757 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2758 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2759 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2760 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2761 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2762 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2763 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2765 else if (r_textureunits.integer >= 4)
2767 // 4/2 2D combine path (Geforce3, Radeon 8500)
2768 memset(&m, 0, sizeof(m));
2769 m.tex[0] = R_GetTexture(normalmaptexture);
2770 m.texcombinergb[0] = GL_REPLACE;
2771 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2772 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2773 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2774 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2775 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2776 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2777 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2778 m.pointer_texcoord_bufferobject[1] = 0;
2779 m.pointer_texcoord_bufferoffset[1] = 0;
2780 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2781 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2782 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2783 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2784 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
2785 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
2786 m.pointer_texcoord3f[3] = rsurface.vertex3f;
2787 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
2788 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
2789 m.texmatrix[3] = rsurface.entitytoattenuationz;
2790 R_Mesh_TextureState(&m);
2791 GL_ColorMask(0,0,0,1);
2792 GL_BlendFunc(GL_ONE, GL_ZERO);
2793 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2796 memset(&m, 0, sizeof(m));
2797 m.tex[0] = R_GetTexture(basetexture);
2798 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2799 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2800 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2801 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2802 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2804 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2805 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2806 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2807 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2808 m.texmatrix[1] = rsurface.entitytolight;
2810 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2814 // 2/2/2 2D combine path (any dot3 card)
2815 memset(&m, 0, sizeof(m));
2816 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2817 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2818 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2819 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2820 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2821 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2822 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2823 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2824 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2825 m.texmatrix[1] = rsurface.entitytoattenuationz;
2826 R_Mesh_TextureState(&m);
2827 GL_ColorMask(0,0,0,1);
2828 GL_BlendFunc(GL_ONE, GL_ZERO);
2829 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2832 memset(&m, 0, sizeof(m));
2833 m.tex[0] = R_GetTexture(normalmaptexture);
2834 m.texcombinergb[0] = GL_REPLACE;
2835 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2836 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2837 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2838 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2839 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2840 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2841 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2842 m.pointer_texcoord_bufferobject[1] = 0;
2843 m.pointer_texcoord_bufferoffset[1] = 0;
2844 R_Mesh_TextureState(&m);
2845 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2846 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2849 memset(&m, 0, sizeof(m));
2850 m.tex[0] = R_GetTexture(basetexture);
2851 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2852 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2853 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2854 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2855 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2857 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2858 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2859 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2860 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2861 m.texmatrix[1] = rsurface.entitytolight;
2863 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2865 // this final code is shared
2866 R_Mesh_TextureState(&m);
2867 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);
2870 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)
2872 float glossexponent;
2874 // FIXME: detect blendsquare!
2875 //if (!gl_support_blendsquare)
2878 // generate normalization cubemap texcoords
2879 R_Shadow_GenTexCoords_Specular_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
2880 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2882 // 2/0/0/1/2 3D combine blendsquare path
2883 memset(&m, 0, sizeof(m));
2884 m.tex[0] = R_GetTexture(normalmaptexture);
2885 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2886 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2887 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2888 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2889 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2890 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2891 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2892 m.pointer_texcoord_bufferobject[1] = 0;
2893 m.pointer_texcoord_bufferoffset[1] = 0;
2894 R_Mesh_TextureState(&m);
2895 GL_ColorMask(0,0,0,1);
2896 // this squares the result
2897 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2898 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2900 // second and third pass
2901 R_Mesh_ResetTextureState();
2902 // square alpha in framebuffer a few times to make it shiny
2903 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2904 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2905 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2908 memset(&m, 0, sizeof(m));
2909 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2910 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2911 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2912 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2913 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2914 R_Mesh_TextureState(&m);
2915 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2916 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2919 memset(&m, 0, sizeof(m));
2920 m.tex[0] = R_GetTexture(glosstexture);
2921 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2922 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2923 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2924 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2925 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2927 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2928 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2929 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2930 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2931 m.texmatrix[1] = rsurface.entitytolight;
2933 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2935 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
2937 // 2/0/0/2 3D combine blendsquare path
2938 memset(&m, 0, sizeof(m));
2939 m.tex[0] = R_GetTexture(normalmaptexture);
2940 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2941 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2942 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2943 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2944 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2945 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2946 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2947 m.pointer_texcoord_bufferobject[1] = 0;
2948 m.pointer_texcoord_bufferoffset[1] = 0;
2949 R_Mesh_TextureState(&m);
2950 GL_ColorMask(0,0,0,1);
2951 // this squares the result
2952 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2953 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2955 // second and third pass
2956 R_Mesh_ResetTextureState();
2957 // square alpha in framebuffer a few times to make it shiny
2958 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2959 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2960 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2963 memset(&m, 0, sizeof(m));
2964 m.tex[0] = R_GetTexture(glosstexture);
2965 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2966 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2967 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2968 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2969 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2970 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2971 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2972 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2973 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2974 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2978 // 2/0/0/2/2 2D combine blendsquare path
2979 memset(&m, 0, sizeof(m));
2980 m.tex[0] = R_GetTexture(normalmaptexture);
2981 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2982 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2983 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2984 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2985 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2986 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2987 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2988 m.pointer_texcoord_bufferobject[1] = 0;
2989 m.pointer_texcoord_bufferoffset[1] = 0;
2990 R_Mesh_TextureState(&m);
2991 GL_ColorMask(0,0,0,1);
2992 // this squares the result
2993 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2994 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2996 // second and third pass
2997 R_Mesh_ResetTextureState();
2998 // square alpha in framebuffer a few times to make it shiny
2999 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
3000 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
3001 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3004 memset(&m, 0, sizeof(m));
3005 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
3006 m.pointer_texcoord3f[0] = rsurface.vertex3f;
3007 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
3008 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
3009 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
3010 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
3011 m.pointer_texcoord3f[1] = rsurface.vertex3f;
3012 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
3013 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
3014 m.texmatrix[1] = rsurface.entitytoattenuationz;
3015 R_Mesh_TextureState(&m);
3016 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
3017 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3020 memset(&m, 0, sizeof(m));
3021 m.tex[0] = R_GetTexture(glosstexture);
3022 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3023 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3024 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3025 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3026 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
3028 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
3029 m.pointer_texcoord3f[1] = rsurface.vertex3f;
3030 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
3031 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
3032 m.texmatrix[1] = rsurface.entitytolight;
3034 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
3036 // this final code is shared
3037 R_Mesh_TextureState(&m);
3038 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);
3041 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)
3043 // ARB path (any Geforce, any Radeon)
3044 qboolean doambient = ambientscale > 0;
3045 qboolean dodiffuse = diffusescale > 0;
3046 qboolean dospecular = specularscale > 0;
3047 if (!doambient && !dodiffuse && !dospecular)
3049 R_Mesh_ColorPointer(NULL, 0, 0);
3051 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, basetexture, ambientscale * r_refdef.view.colorscale);
3053 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, basetexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
3057 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorpants, pantstexture, ambientscale * r_refdef.view.colorscale);
3059 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorpants, pantstexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
3064 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorshirt, shirttexture, ambientscale * r_refdef.view.colorscale);
3066 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorshirt, shirttexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
3069 R_Shadow_RenderLighting_Light_Dot3_SpecularPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, glosstexture, normalmaptexture, specularscale * r_refdef.view.colorscale);
3072 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
3079 int newnumtriangles;
3083 int maxtriangles = 4096;
3084 int newelements[4096*3];
3085 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, numtriangles, element3i, diffusecolor2, ambientcolor2);
3086 for (renders = 0;renders < 64;renders++)
3091 newnumtriangles = 0;
3093 // due to low fillrate on the cards this vertex lighting path is
3094 // designed for, we manually cull all triangles that do not
3095 // contain a lit vertex
3096 // this builds batches of triangles from multiple surfaces and
3097 // renders them at once
3098 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
3100 if (VectorLength2(rsurface.array_color4f + e[0] * 4) + VectorLength2(rsurface.array_color4f + e[1] * 4) + VectorLength2(rsurface.array_color4f + e[2] * 4) >= 0.01)
3102 if (newnumtriangles)
3104 newfirstvertex = min(newfirstvertex, e[0]);
3105 newlastvertex = max(newlastvertex, e[0]);
3109 newfirstvertex = e[0];
3110 newlastvertex = e[0];
3112 newfirstvertex = min(newfirstvertex, e[1]);
3113 newlastvertex = max(newlastvertex, e[1]);
3114 newfirstvertex = min(newfirstvertex, e[2]);
3115 newlastvertex = max(newlastvertex, e[2]);
3121 if (newnumtriangles >= maxtriangles)
3123 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
3124 newnumtriangles = 0;
3130 if (newnumtriangles >= 1)
3132 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
3135 // if we couldn't find any lit triangles, exit early
3138 // now reduce the intensity for the next overbright pass
3139 // we have to clamp to 0 here incase the drivers have improper
3140 // handling of negative colors
3141 // (some old drivers even have improper handling of >1 color)
3143 for (i = 0, c = rsurface.array_color4f + 4 * firstvertex;i < numvertices;i++, c += 4)
3145 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
3147 c[0] = max(0, c[0] - 1);
3148 c[1] = max(0, c[1] - 1);
3149 c[2] = max(0, c[2] - 1);
3161 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)
3163 // OpenGL 1.1 path (anything)
3164 float ambientcolorbase[3], diffusecolorbase[3];
3165 float ambientcolorpants[3], diffusecolorpants[3];
3166 float ambientcolorshirt[3], diffusecolorshirt[3];
3168 VectorScale(lightcolorbase, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorbase);
3169 VectorScale(lightcolorbase, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorbase);
3170 VectorScale(lightcolorpants, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorpants);
3171 VectorScale(lightcolorpants, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorpants);
3172 VectorScale(lightcolorshirt, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorshirt);
3173 VectorScale(lightcolorshirt, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorshirt);
3174 memset(&m, 0, sizeof(m));
3175 m.tex[0] = R_GetTexture(basetexture);
3176 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3177 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3178 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3179 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3180 if (r_textureunits.integer >= 2)
3183 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
3184 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
3185 m.pointer_texcoord3f[1] = rsurface.vertex3f;
3186 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
3187 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
3188 if (r_textureunits.integer >= 3)
3190 // Voodoo4 or Kyro (or Geforce3/Radeon with gl_combine off)
3191 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
3192 m.texmatrix[2] = rsurface.entitytoattenuationz;
3193 m.pointer_texcoord3f[2] = rsurface.vertex3f;
3194 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
3195 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
3198 R_Mesh_TextureState(&m);
3199 //R_Mesh_TexBind(0, R_GetTexture(basetexture));
3200 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorbase, ambientcolorbase);
3203 R_Mesh_TexBind(0, R_GetTexture(pantstexture));
3204 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorpants, ambientcolorpants);
3208 R_Mesh_TexBind(0, R_GetTexture(shirttexture));
3209 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorshirt, ambientcolorshirt);
3213 extern cvar_t gl_lightmaps;
3214 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)
3216 float ambientscale, diffusescale, specularscale;
3217 vec3_t lightcolorbase, lightcolorpants, lightcolorshirt;
3219 // calculate colors to render this texture with
3220 lightcolorbase[0] = rsurface.rtlight->currentcolor[0] * rsurface.texture->dlightcolor[0];
3221 lightcolorbase[1] = rsurface.rtlight->currentcolor[1] * rsurface.texture->dlightcolor[1];
3222 lightcolorbase[2] = rsurface.rtlight->currentcolor[2] * rsurface.texture->dlightcolor[2];
3223 ambientscale = rsurface.rtlight->ambientscale;
3224 diffusescale = rsurface.rtlight->diffusescale;
3225 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
3226 if (!r_shadow_usenormalmap.integer)
3228 ambientscale += 1.0f * diffusescale;
3232 if ((ambientscale + diffusescale) * VectorLength2(lightcolorbase) + specularscale * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
3234 RSurf_SetupDepthAndCulling();
3235 nmap = rsurface.texture->currentskinframe->nmap;
3236 if (gl_lightmaps.integer)
3237 nmap = r_texture_blanknormalmap;
3238 if (rsurface.texture->colormapping && !gl_lightmaps.integer)
3240 qboolean dopants = rsurface.texture->currentskinframe->pants != NULL && VectorLength2(rsurface.colormap_pantscolor) >= (1.0f / 1048576.0f);
3241 qboolean doshirt = rsurface.texture->currentskinframe->shirt != NULL && VectorLength2(rsurface.colormap_shirtcolor) >= (1.0f / 1048576.0f);
3244 lightcolorpants[0] = lightcolorbase[0] * rsurface.colormap_pantscolor[0];
3245 lightcolorpants[1] = lightcolorbase[1] * rsurface.colormap_pantscolor[1];
3246 lightcolorpants[2] = lightcolorbase[2] * rsurface.colormap_pantscolor[2];
3249 VectorClear(lightcolorpants);
3252 lightcolorshirt[0] = lightcolorbase[0] * rsurface.colormap_shirtcolor[0];
3253 lightcolorshirt[1] = lightcolorbase[1] * rsurface.colormap_shirtcolor[1];
3254 lightcolorshirt[2] = lightcolorbase[2] * rsurface.colormap_shirtcolor[2];
3257 VectorClear(lightcolorshirt);
3258 switch (r_shadow_rendermode)
3260 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
3261 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
3262 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);
3264 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
3265 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);
3267 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
3268 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);
3270 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3271 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);
3274 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
3280 switch (r_shadow_rendermode)
3282 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
3283 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
3284 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);
3286 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
3287 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);
3289 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
3290 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);
3292 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3293 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);
3296 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
3302 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)
3304 matrix4x4_t tempmatrix = *matrix;
3305 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
3307 // if this light has been compiled before, free the associated data
3308 R_RTLight_Uncompile(rtlight);
3310 // clear it completely to avoid any lingering data
3311 memset(rtlight, 0, sizeof(*rtlight));
3313 // copy the properties
3314 rtlight->matrix_lighttoworld = tempmatrix;
3315 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
3316 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
3317 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
3318 VectorCopy(color, rtlight->color);
3319 rtlight->cubemapname[0] = 0;
3320 if (cubemapname && cubemapname[0])
3321 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
3322 rtlight->shadow = shadow;
3323 rtlight->corona = corona;
3324 rtlight->style = style;
3325 rtlight->isstatic = isstatic;
3326 rtlight->coronasizescale = coronasizescale;
3327 rtlight->ambientscale = ambientscale;
3328 rtlight->diffusescale = diffusescale;
3329 rtlight->specularscale = specularscale;
3330 rtlight->flags = flags;
3332 // compute derived data
3333 //rtlight->cullradius = rtlight->radius;
3334 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
3335 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3336 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3337 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3338 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3339 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3340 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3343 // compiles rtlight geometry
3344 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
3345 void R_RTLight_Compile(rtlight_t *rtlight)
3348 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
3349 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
3350 entity_render_t *ent = r_refdef.scene.worldentity;
3351 dp_model_t *model = r_refdef.scene.worldmodel;
3352 unsigned char *data;
3355 // compile the light
3356 rtlight->compiled = true;
3357 rtlight->shadowmode = rtlight->shadow ? r_shadow_shadowmode : -1;
3358 rtlight->static_numleafs = 0;
3359 rtlight->static_numleafpvsbytes = 0;
3360 rtlight->static_leaflist = NULL;
3361 rtlight->static_leafpvs = NULL;
3362 rtlight->static_numsurfaces = 0;
3363 rtlight->static_surfacelist = NULL;
3364 rtlight->static_shadowmap_receivers = 0x3F;
3365 rtlight->static_shadowmap_casters = 0x3F;
3366 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3367 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3368 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3369 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3370 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3371 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3373 if (model && model->GetLightInfo)
3375 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
3376 r_shadow_compilingrtlight = rtlight;
3377 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);
3378 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);
3379 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
3380 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
3381 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3382 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
3383 rtlight->static_numsurfaces = numsurfaces;
3384 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
3385 rtlight->static_numleafs = numleafs;
3386 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
3387 rtlight->static_numleafpvsbytes = numleafpvsbytes;
3388 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
3389 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
3390 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
3391 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
3392 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3393 if (rtlight->static_numsurfaces)
3394 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3395 if (rtlight->static_numleafs)
3396 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3397 if (rtlight->static_numleafpvsbytes)
3398 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3399 if (rtlight->static_numshadowtrispvsbytes)
3400 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3401 if (rtlight->static_numlighttrispvsbytes)
3402 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3403 if (rtlight->shadowmode <= 0)
3405 if (model->CompileShadowVolume && rtlight->shadow)
3406 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3410 if (model->CompileShadowMap && rtlight->shadow)
3411 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3413 // now we're done compiling the rtlight
3414 r_shadow_compilingrtlight = NULL;
3418 // use smallest available cullradius - box radius or light radius
3419 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3420 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3422 shadowzpasstris = 0;
3423 if (rtlight->static_meshchain_shadow_zpass)
3424 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
3425 shadowzpasstris += mesh->numtriangles;
3427 shadowzfailtris = 0;
3428 if (rtlight->static_meshchain_shadow_zfail)
3429 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
3430 shadowzfailtris += mesh->numtriangles;
3433 if (rtlight->static_numlighttrispvsbytes)
3434 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3435 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3439 if (rtlight->static_numlighttrispvsbytes)
3440 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3441 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3444 if (developer.integer >= 10)
3445 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);
3448 void R_RTLight_Uncompile(rtlight_t *rtlight)
3450 if (rtlight->compiled)
3452 if (rtlight->static_meshchain_shadow_zpass)
3453 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
3454 rtlight->static_meshchain_shadow_zpass = NULL;
3455 if (rtlight->static_meshchain_shadow_zfail)
3456 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
3457 rtlight->static_meshchain_shadow_zfail = NULL;
3458 if (rtlight->static_meshchain_shadow_shadowmap)
3459 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
3460 rtlight->static_meshchain_shadow_shadowmap = NULL;
3461 // these allocations are grouped
3462 if (rtlight->static_surfacelist)
3463 Mem_Free(rtlight->static_surfacelist);
3464 rtlight->static_numleafs = 0;
3465 rtlight->static_numleafpvsbytes = 0;
3466 rtlight->static_leaflist = NULL;
3467 rtlight->static_leafpvs = NULL;
3468 rtlight->static_numsurfaces = 0;
3469 rtlight->static_surfacelist = NULL;
3470 rtlight->static_numshadowtrispvsbytes = 0;
3471 rtlight->static_shadowtrispvs = NULL;
3472 rtlight->static_numlighttrispvsbytes = 0;
3473 rtlight->static_lighttrispvs = NULL;
3474 rtlight->compiled = false;
3478 void R_Shadow_UncompileWorldLights(void)
3482 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3483 for (lightindex = 0;lightindex < range;lightindex++)
3485 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3488 R_RTLight_Uncompile(&light->rtlight);
3492 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3496 // reset the count of frustum planes
3497 // see rsurface.rtlight_frustumplanes definition for how much this array
3499 rsurface.rtlight_numfrustumplanes = 0;
3501 // haven't implemented a culling path for ortho rendering
3502 if (!r_refdef.view.useperspective)
3504 // check if the light is on screen and copy the 4 planes if it is
3505 for (i = 0;i < 4;i++)
3506 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3509 for (i = 0;i < 4;i++)
3510 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_refdef.view.frustum[i];
3515 // generate a deformed frustum that includes the light origin, this is
3516 // used to cull shadow casting surfaces that can not possibly cast a
3517 // shadow onto the visible light-receiving surfaces, which can be a
3520 // if the light origin is onscreen the result will be 4 planes exactly
3521 // if the light origin is offscreen on only one axis the result will
3522 // be exactly 5 planes (split-side case)
3523 // if the light origin is offscreen on two axes the result will be
3524 // exactly 4 planes (stretched corner case)
3525 for (i = 0;i < 4;i++)
3527 // quickly reject standard frustum planes that put the light
3528 // origin outside the frustum
3529 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3532 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_refdef.view.frustum[i];
3534 // if all the standard frustum planes were accepted, the light is onscreen
3535 // otherwise we need to generate some more planes below...
3536 if (rsurface.rtlight_numfrustumplanes < 4)
3538 // at least one of the stock frustum planes failed, so we need to
3539 // create one or two custom planes to enclose the light origin
3540 for (i = 0;i < 4;i++)
3542 // create a plane using the view origin and light origin, and a
3543 // single point from the frustum corner set
3544 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3545 VectorNormalize(plane.normal);
3546 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3547 // see if this plane is backwards and flip it if so
3548 for (j = 0;j < 4;j++)
3549 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3553 VectorNegate(plane.normal, plane.normal);
3555 // flipped plane, test again to see if it is now valid
3556 for (j = 0;j < 4;j++)
3557 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3559 // if the plane is still not valid, then it is dividing the
3560 // frustum and has to be rejected
3564 // we have created a valid plane, compute extra info
3565 PlaneClassify(&plane);
3567 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3569 // if we've found 5 frustum planes then we have constructed a
3570 // proper split-side case and do not need to keep searching for
3571 // planes to enclose the light origin
3572 if (rsurface.rtlight_numfrustumplanes == 5)
3580 for (i = 0;i < rsurface.rtlight_numfrustumplanes;i++)
3582 plane = rsurface.rtlight_frustumplanes[i];
3583 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));
3588 // now add the light-space box planes if the light box is rotated, as any
3589 // caster outside the oriented light box is irrelevant (even if it passed
3590 // the worldspace light box, which is axial)
3591 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3593 for (i = 0;i < 6;i++)
3597 v[i >> 1] = (i & 1) ? -1 : 1;
3598 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3599 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3600 plane.dist = VectorNormalizeLength(plane.normal);
3601 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3602 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3608 // add the world-space reduced box planes
3609 for (i = 0;i < 6;i++)
3611 VectorClear(plane.normal);
3612 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3613 plane.dist = (i & 1) ? -rsurface.rtlight_cullmaxs[i >> 1] : rsurface.rtlight_cullmins[i >> 1];
3614 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3623 // reduce all plane distances to tightly fit the rtlight cull box, which
3625 VectorSet(points[0], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
3626 VectorSet(points[1], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
3627 VectorSet(points[2], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
3628 VectorSet(points[3], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
3629 VectorSet(points[4], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
3630 VectorSet(points[5], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
3631 VectorSet(points[6], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
3632 VectorSet(points[7], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
3633 oldnum = rsurface.rtlight_numfrustumplanes;
3634 rsurface.rtlight_numfrustumplanes = 0;
3635 for (j = 0;j < oldnum;j++)
3637 // find the nearest point on the box to this plane
3638 bestdist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[0]);
3639 for (i = 1;i < 8;i++)
3641 dist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[i]);
3642 if (bestdist > dist)
3645 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);
3646 // if the nearest point is near or behind the plane, we want this
3647 // plane, otherwise the plane is useless as it won't cull anything
3648 if (rsurface.rtlight_frustumplanes[j].dist < bestdist + 0.03125)
3650 PlaneClassify(&rsurface.rtlight_frustumplanes[j]);
3651 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = rsurface.rtlight_frustumplanes[j];
3658 void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3662 RSurf_ActiveWorldEntity();
3664 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3667 GL_CullFace(GL_NONE);
3668 mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3669 for (;mesh;mesh = mesh->next)
3671 if (!mesh->sidetotals[r_shadow_shadowmapside])
3673 r_refdef.stats.lights_shadowtriangles += mesh->sidetotals[r_shadow_shadowmapside];
3674 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
3675 R_Mesh_Draw(0, mesh->numverts, mesh->sideoffsets[r_shadow_shadowmapside], mesh->sidetotals[r_shadow_shadowmapside], mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3679 else if (r_refdef.scene.worldentity->model)
3680 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);
3682 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3685 void R_Shadow_DrawWorldShadow(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3690 int surfacelistindex;
3691 msurface_t *surface;
3693 RSurf_ActiveWorldEntity();
3695 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3698 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
3699 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
3700 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
3701 for (;mesh;mesh = mesh->next)
3703 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
3704 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
3705 GL_LockArrays(0, mesh->numverts);
3706 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
3708 // increment stencil if frontface is infront of depthbuffer
3709 GL_CullFace(r_refdef.view.cullface_back);
3710 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
3711 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3712 // decrement stencil if backface is infront of depthbuffer
3713 GL_CullFace(r_refdef.view.cullface_front);
3714 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
3716 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
3718 // decrement stencil if backface is behind depthbuffer
3719 GL_CullFace(r_refdef.view.cullface_front);
3720 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
3721 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3722 // increment stencil if frontface is behind depthbuffer
3723 GL_CullFace(r_refdef.view.cullface_back);
3724 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
3726 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3727 GL_LockArrays(0, 0);
3731 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh && r_shadow_culltriangles.integer)
3733 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
3734 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
3736 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
3737 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
3738 if (CHECKPVSBIT(trispvs, t))
3739 shadowmarklist[numshadowmark++] = t;
3741 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);
3743 else if (numsurfaces)
3744 r_refdef.scene.worldmodel->DrawShadowVolume(r_refdef.scene.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs);
3746 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3749 static int R_Shadow_CalcEntitySideMask(rtlight_t *rtlight, entity_render_t *ent, float borderbias)
3751 vec3_t radius, worldorigin, lightorigin;
3752 VectorSubtract(ent->maxs, ent->mins, radius);
3753 VectorScale(radius, 0.5f, radius);
3754 VectorAdd(ent->mins, radius, worldorigin);
3755 Matrix4x4_Transform(&rtlight->matrix_worldtolight, worldorigin, lightorigin);
3756 return R_Shadow_CalcSphereSideMask(lightorigin, VectorLength(radius) / rtlight->radius, borderbias);
3759 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3761 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3762 vec_t relativeshadowradius;
3763 RSurf_ActiveModelEntity(ent, false, false);
3764 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3765 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3766 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3767 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3768 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3769 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3770 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3771 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3772 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D)
3774 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3777 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3778 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3781 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3783 // set up properties for rendering light onto this entity
3784 RSurf_ActiveModelEntity(ent, true, true);
3785 GL_AlphaTest(false);
3786 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3787 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3788 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3789 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3790 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
3791 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
3794 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3796 if (!r_refdef.scene.worldmodel->DrawLight)
3799 // set up properties for rendering light onto this entity
3800 RSurf_ActiveWorldEntity();
3801 GL_AlphaTest(false);
3802 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3803 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3804 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3805 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3806 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
3807 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
3809 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, trispvs);
3811 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3814 void R_Shadow_DrawEntityLight(entity_render_t *ent)
3816 dp_model_t *model = ent->model;
3817 if (!model->DrawLight)
3820 R_Shadow_SetupEntityLight(ent);
3822 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3824 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3827 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
3831 int numleafs, numsurfaces;
3832 int *leaflist, *surfacelist;
3833 unsigned char *leafpvs, *shadowtrispvs, *lighttrispvs;
3834 int numlightentities;
3835 int numlightentities_noselfshadow;
3836 int numshadowentities;
3837 int numshadowentities_noselfshadow;
3838 static entity_render_t *lightentities[MAX_EDICTS];
3839 static entity_render_t *shadowentities[MAX_EDICTS];
3840 static unsigned char entitysides[MAX_EDICTS];
3841 int lightentities_noselfshadow;
3842 int shadowentities_noselfshadow;
3843 vec3_t nearestpoint;
3845 qboolean castshadows;
3848 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3849 // skip lights that are basically invisible (color 0 0 0)
3850 if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
3853 // loading is done before visibility checks because loading should happen
3854 // all at once at the start of a level, not when it stalls gameplay.
3855 // (especially important to benchmarks)
3857 if (rtlight->isstatic && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
3859 if (rtlight->compiled)
3860 R_RTLight_Uncompile(rtlight);
3861 R_RTLight_Compile(rtlight);
3865 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
3867 // look up the light style value at this time
3868 f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3869 VectorScale(rtlight->color, f, rtlight->currentcolor);
3871 if (rtlight->selected)
3873 f = 2 + sin(realtime * M_PI * 4.0);
3874 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3878 // if lightstyle is currently off, don't draw the light
3879 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3882 // if the light box is offscreen, skip it
3883 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3886 VectorCopy(rtlight->cullmins, rsurface.rtlight_cullmins);
3887 VectorCopy(rtlight->cullmaxs, rsurface.rtlight_cullmaxs);
3889 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3891 // compiled light, world available and can receive realtime lighting
3892 // retrieve leaf information
3893 numleafs = rtlight->static_numleafs;
3894 leaflist = rtlight->static_leaflist;
3895 leafpvs = rtlight->static_leafpvs;
3896 numsurfaces = rtlight->static_numsurfaces;
3897 surfacelist = rtlight->static_surfacelist;
3898 shadowtrispvs = rtlight->static_shadowtrispvs;
3899 lighttrispvs = rtlight->static_lighttrispvs;
3901 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3903 // dynamic light, world available and can receive realtime lighting
3904 // calculate lit surfaces and leafs
3905 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);
3906 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);
3907 leaflist = r_shadow_buffer_leaflist;
3908 leafpvs = r_shadow_buffer_leafpvs;
3909 surfacelist = r_shadow_buffer_surfacelist;
3910 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3911 lighttrispvs = r_shadow_buffer_lighttrispvs;
3912 // if the reduced leaf bounds are offscreen, skip it
3913 if (R_CullBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
3924 shadowtrispvs = NULL;
3925 lighttrispvs = NULL;
3927 // check if light is illuminating any visible leafs
3930 for (i = 0;i < numleafs;i++)
3931 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3936 // set up a scissor rectangle for this light
3937 if (R_Shadow_ScissorForBBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
3940 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3942 // make a list of lit entities and shadow casting entities
3943 numlightentities = 0;
3944 numlightentities_noselfshadow = 0;
3945 lightentities_noselfshadow = sizeof(lightentities)/sizeof(lightentities[0]) - 1;
3946 numshadowentities = 0;
3947 numshadowentities_noselfshadow = 0;
3948 shadowentities_noselfshadow = sizeof(shadowentities)/sizeof(shadowentities[0]) - 1;
3950 // add dynamic entities that are lit by the light
3951 if (r_drawentities.integer)
3953 for (i = 0;i < r_refdef.scene.numentities;i++)
3956 entity_render_t *ent = r_refdef.scene.entities[i];
3958 if (!BoxesOverlap(ent->mins, ent->maxs, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
3960 // skip the object entirely if it is not within the valid
3961 // shadow-casting region (which includes the lit region)
3962 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rsurface.rtlight_numfrustumplanes, rsurface.rtlight_frustumplanes))
3964 if (!(model = ent->model))
3966 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
3968 // this entity wants to receive light, is visible, and is
3969 // inside the light box
3970 // TODO: check if the surfaces in the model can receive light
3971 // so now check if it's in a leaf seen by the light
3972 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))
3974 if (ent->flags & RENDER_NOSELFSHADOW)
3975 lightentities[lightentities_noselfshadow - numlightentities_noselfshadow++] = ent;
3977 lightentities[numlightentities++] = ent;
3978 // since it is lit, it probably also casts a shadow...
3979 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3980 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3981 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3983 // note: exterior models without the RENDER_NOSELFSHADOW
3984 // flag still create a RENDER_NOSELFSHADOW shadow but
3985 // are lit normally, this means that they are
3986 // self-shadowing but do not shadow other
3987 // RENDER_NOSELFSHADOW entities such as the gun
3988 // (very weird, but keeps the player shadow off the gun)
3989 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3990 shadowentities[shadowentities_noselfshadow - numshadowentities_noselfshadow++] = ent;
3992 shadowentities[numshadowentities++] = ent;
3995 else if (ent->flags & RENDER_SHADOW)
3997 // this entity is not receiving light, but may still need to
3999 // TODO: check if the surfaces in the model can cast shadow
4000 // now check if it is in a leaf seen by the light
4001 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))
4003 // about the VectorDistance2 - light emitting entities should not cast their own shadow
4004 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
4005 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
4007 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
4008 shadowentities[shadowentities_noselfshadow - numshadowentities_noselfshadow++] = ent;
4010 shadowentities[numshadowentities++] = ent;
4016 // return if there's nothing at all to light
4017 if (!numlightentities && !numsurfaces)
4020 // don't let sound skip if going slow
4021 if (r_refdef.scene.extraupdate)
4024 // make this the active rtlight for rendering purposes
4025 R_Shadow_RenderMode_ActiveLight(rtlight);
4026 // count this light in the r_speeds
4027 r_refdef.stats.lights++;
4029 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
4031 // optionally draw visible shape of the shadow volumes
4032 // for performance analysis by level designers
4033 R_Shadow_RenderMode_VisibleShadowVolumes();
4035 R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
4036 for (i = 0;i < numshadowentities;i++)
4037 R_Shadow_DrawEntityShadow(shadowentities[i]);
4038 for (i = 0;i < numshadowentities_noselfshadow;i++)
4039 R_Shadow_DrawEntityShadow(shadowentities[shadowentities_noselfshadow - i]);
4042 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
4044 // optionally draw the illuminated areas
4045 // for performance analysis by level designers
4046 R_Shadow_RenderMode_VisibleLighting(false, false);
4048 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4049 for (i = 0;i < numlightentities;i++)
4050 R_Shadow_DrawEntityLight(lightentities[i]);
4051 for (i = 0;i < numlightentities_noselfshadow;i++)
4052 R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
4055 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
4057 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
4058 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
4059 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
4060 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
4061 lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
4062 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapping_maxsize.integer);
4064 if (castshadows && r_shadow_shadowmode >= 1 && r_shadow_shadowmode <= 3 && r_glsl.integer && gl_support_fragment_shader)
4070 int receivermask = 0;
4072 r_shadow_shadowmaplod = 0;
4073 for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
4074 if ((r_shadow_shadowmapping_maxsize.integer >> i) > lodlinear)
4075 r_shadow_shadowmaplod = i;
4077 size = r_shadow_shadowmode == 3 ? r_shadow_shadowmapping_maxsize.integer >> r_shadow_shadowmaplod : lodlinear;
4078 size = bound(1, size, 2048);
4079 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
4084 receivermask = 0x3F;
4085 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
4087 castermask &= rtlight->static_shadowmap_casters;
4088 receivermask &= rtlight->static_shadowmap_receivers;
4091 if (receivermask < 0x3F)
4093 for (i = 0;i < numlightentities;i++)
4094 receivermask |= R_Shadow_CalcEntitySideMask(rtlight, lightentities[i], borderbias);
4095 if (receivermask < 0x3F)
4096 for(i = 0; i < numlightentities_noselfshadow;i++)
4097 receivermask |= R_Shadow_CalcEntitySideMask(rtlight, lightentities[lightentities_noselfshadow - i], borderbias);
4100 receivermask &= R_Shadow_FrustumCullSides(rtlight, size, r_shadow_shadowmapborder);
4104 for (i = 0;i < numshadowentities;i++)
4105 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(rtlight, shadowentities[i], borderbias));
4106 for (i = 0;i < numshadowentities_noselfshadow;i++)
4107 castermask |= (entitysides[shadowentities_noselfshadow - i] = R_Shadow_CalcEntitySideMask(rtlight, shadowentities[shadowentities_noselfshadow - i], borderbias));
4110 //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
4112 // render shadow casters into 6 sided depth texture
4113 for (side = 0;side < 6;side++) if (receivermask & (1 << side))
4115 R_Shadow_RenderMode_ShadowMap(side, true, size);
4116 if (! (castermask & (1 << side))) continue;
4118 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs);
4119 for (i = 0;i < numshadowentities;i++) if (entitysides[i] & (1 << side))
4120 R_Shadow_DrawEntityShadow(shadowentities[i]);
4123 if (numlightentities_noselfshadow)
4125 // render lighting using the depth texture as shadowmap
4126 // draw lighting in the unmasked areas
4127 R_Shadow_RenderMode_Lighting(false, false, true);
4128 for (i = 0;i < numlightentities_noselfshadow;i++)
4129 R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
4132 // render shadow casters into 6 sided depth texture
4133 if (numshadowentities_noselfshadow)
4135 for (side = 0;side < 6;side++) if ((receivermask & castermask) & (1 << side))
4137 R_Shadow_RenderMode_ShadowMap(side, false, size);
4138 for (i = 0;i < numshadowentities_noselfshadow;i++) if (entitysides[shadowentities_noselfshadow - i] && (1 << side))
4139 R_Shadow_DrawEntityShadow(shadowentities[shadowentities_noselfshadow - i]);
4143 // render lighting using the depth texture as shadowmap
4144 // draw lighting in the unmasked areas
4145 R_Shadow_RenderMode_Lighting(false, false, true);
4146 // draw lighting in the unmasked areas
4148 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4149 for (i = 0;i < numlightentities;i++)
4150 R_Shadow_DrawEntityLight(lightentities[i]);
4152 else if (castshadows && gl_stencil)
4154 // draw stencil shadow volumes to mask off pixels that are in shadow
4155 // so that they won't receive lighting
4156 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
4157 R_Shadow_ClearStencil();
4159 R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
4160 for (i = 0;i < numshadowentities;i++)
4161 R_Shadow_DrawEntityShadow(shadowentities[i]);
4162 if (numlightentities_noselfshadow)
4164 // draw lighting in the unmasked areas
4165 R_Shadow_RenderMode_Lighting(true, false, false);
4166 for (i = 0;i < numlightentities_noselfshadow;i++)
4167 R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
4169 // optionally draw the illuminated areas
4170 // for performance analysis by level designers
4171 if (r_showlighting.integer && r_refdef.view.showdebug)
4173 R_Shadow_RenderMode_VisibleLighting(!r_showdisabledepthtest.integer, false);
4174 for (i = 0;i < numlightentities_noselfshadow;i++)
4175 R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
4178 for (i = 0;i < numshadowentities_noselfshadow;i++)
4179 R_Shadow_DrawEntityShadow(shadowentities[shadowentities_noselfshadow - i]);
4181 if (numsurfaces + numlightentities)
4183 // draw lighting in the unmasked areas
4184 R_Shadow_RenderMode_Lighting(true, false, false);
4186 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4187 for (i = 0;i < numlightentities;i++)
4188 R_Shadow_DrawEntityLight(lightentities[i]);
4193 if (numsurfaces + numlightentities)
4195 // draw lighting in the unmasked areas
4196 R_Shadow_RenderMode_Lighting(false, false, false);
4198 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4199 for (i = 0;i < numlightentities;i++)
4200 R_Shadow_DrawEntityLight(lightentities[i]);
4201 for (i = 0;i < numlightentities_noselfshadow;i++)
4202 R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
4207 void R_Shadow_DrawLightSprites(void);
4208 void R_ShadowVolumeLighting(qboolean visible)
4216 if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, 2048) ||
4217 (r_shadow_shadowmode != 0) != (r_shadow_shadowmapping.integer != 0) ||
4218 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0) ||
4219 r_shadow_shadowmaptexturetype != r_shadow_shadowmapping_texturetype.integer ||
4220 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
4221 r_shadow_shadowmapprecision != r_shadow_shadowmapping_precision.integer ||
4222 r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
4223 R_Shadow_FreeShadowMaps();
4225 if (r_editlights.integer)
4226 R_Shadow_DrawLightSprites();
4228 R_Shadow_RenderMode_Begin();
4230 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4231 if (r_shadow_debuglight.integer >= 0)
4233 lightindex = r_shadow_debuglight.integer;
4234 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4235 if (light && (light->flags & flag))
4236 R_DrawRTLight(&light->rtlight, visible);
4240 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4241 for (lightindex = 0;lightindex < range;lightindex++)
4243 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4244 if (light && (light->flags & flag))
4245 R_DrawRTLight(&light->rtlight, visible);
4248 if (r_refdef.scene.rtdlight)
4249 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4250 R_DrawRTLight(r_refdef.scene.lights[lnum], visible);
4252 R_Shadow_RenderMode_End();
4255 extern const float r_screenvertex3f[12];
4256 extern void R_SetupView(qboolean allowwaterclippingplane);
4257 extern void R_ResetViewRendering3D(void);
4258 extern void R_ResetViewRendering2D(void);
4259 extern cvar_t r_shadows;
4260 extern cvar_t r_shadows_darken;
4261 extern cvar_t r_shadows_drawafterrtlighting;
4262 extern cvar_t r_shadows_castfrombmodels;
4263 extern cvar_t r_shadows_throwdistance;
4264 extern cvar_t r_shadows_throwdirection;
4265 void R_DrawModelShadows(void)
4268 float relativethrowdistance;
4269 entity_render_t *ent;
4270 vec3_t relativelightorigin;
4271 vec3_t relativelightdirection;
4272 vec3_t relativeshadowmins, relativeshadowmaxs;
4273 vec3_t tmp, shadowdir;
4275 if (!r_drawentities.integer || !gl_stencil)
4279 R_ResetViewRendering3D();
4280 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4281 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4282 R_Shadow_RenderMode_Begin();
4283 R_Shadow_RenderMode_ActiveLight(NULL);
4284 r_shadow_lightscissor[0] = r_refdef.view.x;
4285 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
4286 r_shadow_lightscissor[2] = r_refdef.view.width;
4287 r_shadow_lightscissor[3] = r_refdef.view.height;
4288 R_Shadow_RenderMode_StencilShadowVolumes(false);
4291 if (r_shadows.integer == 2)
4293 Math_atov(r_shadows_throwdirection.string, shadowdir);
4294 VectorNormalize(shadowdir);
4297 R_Shadow_ClearStencil();
4299 for (i = 0;i < r_refdef.scene.numentities;i++)
4301 ent = r_refdef.scene.entities[i];
4303 // cast shadows from anything of the map (submodels are optional)
4304 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4306 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4307 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
4308 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
4309 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
4310 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4313 if(ent->entitynumber != 0)
4315 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
4316 int entnum, entnum2, recursion;
4317 entnum = entnum2 = ent->entitynumber;
4318 for(recursion = 32; recursion > 0; --recursion)
4320 entnum2 = cl.entities[entnum].state_current.tagentity;
4321 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
4326 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
4328 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
4329 // transform into modelspace of OUR entity
4330 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
4331 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
4334 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4337 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4340 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
4341 RSurf_ActiveModelEntity(ent, false, false);
4342 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4343 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4347 // not really the right mode, but this will disable any silly stencil features
4348 R_Shadow_RenderMode_End();
4350 // set up ortho view for rendering this pass
4351 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4352 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4353 //GL_ScissorTest(true);
4354 //R_Mesh_Matrix(&identitymatrix);
4355 //R_Mesh_ResetTextureState();
4356 R_ResetViewRendering2D();
4357 R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
4358 R_Mesh_ColorPointer(NULL, 0, 0);
4359 R_SetupGenericShader(false);
4361 // set up a darkening blend on shadowed areas
4362 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4363 //GL_DepthRange(0, 1);
4364 //GL_DepthTest(false);
4365 //GL_DepthMask(false);
4366 //GL_PolygonOffset(0, 0);CHECKGLERROR
4367 GL_Color(0, 0, 0, r_shadows_darken.value);
4368 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4369 //qglDepthFunc(GL_ALWAYS);CHECKGLERROR
4370 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
4371 qglStencilMask(~0);CHECKGLERROR
4372 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
4373 qglStencilFunc(GL_NOTEQUAL, 128, ~0);CHECKGLERROR
4375 // apply the blend to the shadowed areas
4376 R_Mesh_Draw(0, 4, 0, 2, NULL, polygonelements, 0, 0);
4378 // restore the viewport
4379 R_SetViewport(&r_refdef.view.viewport);
4381 // restore other state to normal
4382 //R_Shadow_RenderMode_End();
4385 void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4388 vec3_t centerorigin;
4389 // if it's too close, skip it
4390 if (VectorLength(rtlight->color) < (1.0f / 256.0f))
4392 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4395 if (usequery && r_numqueries + 2 <= r_maxqueries)
4397 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4398 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4399 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4402 // 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
4403 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
4404 qglDepthFunc(GL_ALWAYS);
4405 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);
4406 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4407 qglDepthFunc(GL_LEQUAL);
4408 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
4409 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);
4410 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4413 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4416 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4419 GLint allpixels = 0, visiblepixels = 0;
4420 // now we have to check the query result
4421 if (rtlight->corona_queryindex_visiblepixels)
4424 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
4425 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
4427 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
4428 if (visiblepixels < 1 || allpixels < 1)
4430 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
4431 cscale *= rtlight->corona_visibility;
4435 // FIXME: these traces should scan all render entities instead of cl.world
4436 if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
4439 VectorScale(rtlight->color, cscale, color);
4440 if (VectorLength(color) > (1.0f / 256.0f))
4441 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);
4444 void R_DrawCoronas(void)
4452 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4454 if (r_waterstate.renderingscene)
4456 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4457 R_Mesh_Matrix(&identitymatrix);
4459 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4461 // check occlusion of coronas
4462 // use GL_ARB_occlusion_query if available
4463 // otherwise use raytraces
4465 usequery = gl_support_arb_occlusion_query && r_coronas_occlusionquery.integer;
4468 GL_ColorMask(0,0,0,0);
4469 if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
4470 if (r_maxqueries < R_MAX_OCCLUSION_QUERIES)
4473 r_maxqueries = (range + r_refdef.scene.numlights) * 4;
4474 r_maxqueries = min(r_maxqueries, R_MAX_OCCLUSION_QUERIES);
4476 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
4480 for (lightindex = 0;lightindex < range;lightindex++)
4482 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4485 rtlight = &light->rtlight;
4486 rtlight->corona_visibility = 0;
4487 rtlight->corona_queryindex_visiblepixels = 0;
4488 rtlight->corona_queryindex_allpixels = 0;
4489 if (!(rtlight->flags & flag))
4491 if (rtlight->corona <= 0)
4493 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4495 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4497 for (i = 0;i < r_refdef.scene.numlights;i++)
4499 rtlight = r_refdef.scene.lights[i];
4500 rtlight->corona_visibility = 0;
4501 rtlight->corona_queryindex_visiblepixels = 0;
4502 rtlight->corona_queryindex_allpixels = 0;
4503 if (!(rtlight->flags & flag))
4505 if (rtlight->corona <= 0)
4507 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4510 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4512 // now draw the coronas using the query data for intensity info
4513 for (lightindex = 0;lightindex < range;lightindex++)
4515 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4518 rtlight = &light->rtlight;
4519 if (rtlight->corona_visibility <= 0)
4521 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4523 for (i = 0;i < r_refdef.scene.numlights;i++)
4525 rtlight = r_refdef.scene.lights[i];
4526 if (rtlight->corona_visibility <= 0)
4528 if (gl_flashblend.integer)
4529 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4531 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4537 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
4538 typedef struct suffixinfo_s
4541 qboolean flipx, flipy, flipdiagonal;
4544 static suffixinfo_t suffix[3][6] =
4547 {"px", false, false, false},
4548 {"nx", false, false, false},
4549 {"py", false, false, false},
4550 {"ny", false, false, false},
4551 {"pz", false, false, false},
4552 {"nz", false, false, false}
4555 {"posx", false, false, false},
4556 {"negx", false, false, false},
4557 {"posy", false, false, false},
4558 {"negy", false, false, false},
4559 {"posz", false, false, false},
4560 {"negz", false, false, false}
4563 {"rt", true, false, true},
4564 {"lf", false, true, true},
4565 {"ft", true, true, false},
4566 {"bk", false, false, false},
4567 {"up", true, false, true},
4568 {"dn", true, false, true}
4572 static int componentorder[4] = {0, 1, 2, 3};
4574 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
4576 int i, j, cubemapsize;
4577 unsigned char *cubemappixels, *image_buffer;
4578 rtexture_t *cubemaptexture;
4580 // must start 0 so the first loadimagepixels has no requested width/height
4582 cubemappixels = NULL;
4583 cubemaptexture = NULL;
4584 // keep trying different suffix groups (posx, px, rt) until one loads
4585 for (j = 0;j < 3 && !cubemappixels;j++)
4587 // load the 6 images in the suffix group
4588 for (i = 0;i < 6;i++)
4590 // generate an image name based on the base and and suffix
4591 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
4593 if ((image_buffer = loadimagepixelsbgra(name, false, false)))
4595 // an image loaded, make sure width and height are equal
4596 if (image_width == image_height && (!cubemappixels || image_width == cubemapsize))
4598 // if this is the first image to load successfully, allocate the cubemap memory
4599 if (!cubemappixels && image_width >= 1)
4601 cubemapsize = image_width;
4602 // note this clears to black, so unavailable sides are black
4603 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
4605 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
4607 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);
4610 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
4612 Mem_Free(image_buffer);
4616 // if a cubemap loaded, upload it
4619 if (developer_loading.integer)
4620 Con_Printf("loading cubemap \"%s\"\n", basename);
4622 if (!r_shadow_filters_texturepool)
4623 r_shadow_filters_texturepool = R_AllocTexturePool();
4624 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_BGRA, TEXF_PRECACHE | (gl_texturecompression_lightcubemaps.integer ? TEXF_COMPRESS : 0) | TEXF_FORCELINEAR, NULL);
4625 Mem_Free(cubemappixels);
4629 Con_DPrintf("failed to load cubemap \"%s\"\n", basename);
4630 if (developer_loading.integer)
4632 Con_Printf("(tried tried images ");
4633 for (j = 0;j < 3;j++)
4634 for (i = 0;i < 6;i++)
4635 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
4636 Con_Print(" and was unable to find any of them).\n");
4639 return cubemaptexture;
4642 rtexture_t *R_Shadow_Cubemap(const char *basename)
4645 for (i = 0;i < numcubemaps;i++)
4646 if (!strcasecmp(cubemaps[i].basename, basename))
4647 return cubemaps[i].texture ? cubemaps[i].texture : r_texture_whitecube;
4648 if (i >= MAX_CUBEMAPS)
4649 return r_texture_whitecube;
4651 strlcpy(cubemaps[i].basename, basename, sizeof(cubemaps[i].basename));
4652 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
4653 return cubemaps[i].texture;
4656 void R_Shadow_FreeCubemaps(void)
4659 for (i = 0;i < numcubemaps;i++)
4661 if (developer_loading.integer)
4662 Con_Printf("unloading cubemap \"%s\"\n", cubemaps[i].basename);
4663 if (cubemaps[i].texture)
4664 R_FreeTexture(cubemaps[i].texture);
4668 R_FreeTexturePool(&r_shadow_filters_texturepool);
4671 dlight_t *R_Shadow_NewWorldLight(void)
4673 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4676 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)
4679 // validate parameters
4680 if (style < 0 || style >= MAX_LIGHTSTYLES)
4682 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
4688 // copy to light properties
4689 VectorCopy(origin, light->origin);
4690 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4691 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4692 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4693 light->color[0] = max(color[0], 0);
4694 light->color[1] = max(color[1], 0);
4695 light->color[2] = max(color[2], 0);
4696 light->radius = max(radius, 0);
4697 light->style = style;
4698 light->shadow = shadowenable;
4699 light->corona = corona;
4700 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4701 light->coronasizescale = coronasizescale;
4702 light->ambientscale = ambientscale;
4703 light->diffusescale = diffusescale;
4704 light->specularscale = specularscale;
4705 light->flags = flags;
4707 // update renderable light data
4708 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4709 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);
4712 void R_Shadow_FreeWorldLight(dlight_t *light)
4714 if (r_shadow_selectedlight == light)
4715 r_shadow_selectedlight = NULL;
4716 R_RTLight_Uncompile(&light->rtlight);
4717 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4720 void R_Shadow_ClearWorldLights(void)
4724 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4725 for (lightindex = 0;lightindex < range;lightindex++)
4727 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4729 R_Shadow_FreeWorldLight(light);
4731 r_shadow_selectedlight = NULL;
4732 R_Shadow_FreeCubemaps();
4735 void R_Shadow_SelectLight(dlight_t *light)
4737 if (r_shadow_selectedlight)
4738 r_shadow_selectedlight->selected = false;
4739 r_shadow_selectedlight = light;
4740 if (r_shadow_selectedlight)
4741 r_shadow_selectedlight->selected = true;
4744 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4746 // this is never batched (there can be only one)
4747 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);
4750 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4757 // this is never batched (due to the ent parameter changing every time)
4758 // so numsurfaces == 1 and surfacelist[0] == lightnumber
4759 const dlight_t *light = (dlight_t *)ent;
4762 VectorScale(light->color, intensity, spritecolor);
4763 if (VectorLength(spritecolor) < 0.1732f)
4764 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
4765 if (VectorLength(spritecolor) > 1.0f)
4766 VectorNormalize(spritecolor);
4768 // draw light sprite
4769 if (light->cubemapname[0] && !light->shadow)
4770 pic = r_editlights_sprcubemapnoshadowlight;
4771 else if (light->cubemapname[0])
4772 pic = r_editlights_sprcubemaplight;
4773 else if (!light->shadow)
4774 pic = r_editlights_sprnoshadowlight;
4776 pic = r_editlights_sprlight;
4777 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);
4778 // draw selection sprite if light is selected
4779 if (light->selected)
4780 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);
4781 // VorteX todo: add normalmode/realtime mode light overlay sprites?
4784 void R_Shadow_DrawLightSprites(void)
4788 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4789 for (lightindex = 0;lightindex < range;lightindex++)
4791 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4793 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
4795 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
4798 void R_Shadow_SelectLightInView(void)
4800 float bestrating, rating, temp[3];
4804 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4807 for (lightindex = 0;lightindex < range;lightindex++)
4809 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4812 VectorSubtract(light->origin, r_refdef.view.origin, temp);
4813 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
4816 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
4817 if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1.0f)
4819 bestrating = rating;
4824 R_Shadow_SelectLight(best);
4827 void R_Shadow_LoadWorldLights(void)
4829 int n, a, style, shadow, flags;
4830 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
4831 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
4832 if (cl.worldmodel == NULL)
4834 Con_Print("No map loaded.\n");
4837 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4838 strlcat (name, ".rtlights", sizeof (name));
4839 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4849 for (;COM_Parse(t, true) && strcmp(
4850 if (COM_Parse(t, true))
4852 if (com_token[0] == '!')
4855 origin[0] = atof(com_token+1);
4858 origin[0] = atof(com_token);
4863 while (*s && *s != '\n' && *s != '\r')
4869 // check for modifier flags
4876 #if _MSC_VER >= 1400
4877 #define sscanf sscanf_s
4879 cubemapname[sizeof(cubemapname)-1] = 0;
4880 #if MAX_QPATH != 128
4881 #error update this code if MAX_QPATH changes
4883 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
4884 #if _MSC_VER >= 1400
4885 , sizeof(cubemapname)
4887 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
4890 flags = LIGHTFLAG_REALTIMEMODE;
4898 coronasizescale = 0.25f;
4900 VectorClear(angles);
4903 if (a < 9 || !strcmp(cubemapname, "\"\""))
4905 // remove quotes on cubemapname
4906 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
4909 namelen = strlen(cubemapname) - 2;
4910 memmove(cubemapname, cubemapname + 1, namelen);
4911 cubemapname[namelen] = '\0';
4915 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);
4918 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4926 Con_Printf("invalid rtlights file \"%s\"\n", name);
4927 Mem_Free(lightsstring);
4931 void R_Shadow_SaveWorldLights(void)
4935 size_t bufchars, bufmaxchars;
4937 char name[MAX_QPATH];
4938 char line[MAX_INPUTLINE];
4939 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
4940 // I hate lines which are 3 times my screen size :( --blub
4943 if (cl.worldmodel == NULL)
4945 Con_Print("No map loaded.\n");
4948 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4949 strlcat (name, ".rtlights", sizeof (name));
4950 bufchars = bufmaxchars = 0;
4952 for (lightindex = 0;lightindex < range;lightindex++)
4954 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4957 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
4958 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);
4959 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
4960 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]);
4962 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);
4963 if (bufchars + strlen(line) > bufmaxchars)
4965 bufmaxchars = bufchars + strlen(line) + 2048;
4967 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
4971 memcpy(buf, oldbuf, bufchars);
4977 memcpy(buf + bufchars, line, strlen(line));
4978 bufchars += strlen(line);
4982 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
4987 void R_Shadow_LoadLightsFile(void)
4990 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
4991 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
4992 if (cl.worldmodel == NULL)
4994 Con_Print("No map loaded.\n");
4997 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4998 strlcat (name, ".lights", sizeof (name));
4999 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5007 while (*s && *s != '\n' && *s != '\r')
5013 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);
5017 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);
5020 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
5021 radius = bound(15, radius, 4096);
5022 VectorScale(color, (2.0f / (8388608.0f)), color);
5023 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5031 Con_Printf("invalid lights file \"%s\"\n", name);
5032 Mem_Free(lightsstring);
5036 // tyrlite/hmap2 light types in the delay field
5037 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
5039 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
5041 int entnum, style, islight, skin, pflags, effects, type, n;
5044 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
5045 char key[256], value[MAX_INPUTLINE];
5047 if (cl.worldmodel == NULL)
5049 Con_Print("No map loaded.\n");
5052 // try to load a .ent file first
5053 FS_StripExtension (cl.worldmodel->name, key, sizeof (key));
5054 strlcat (key, ".ent", sizeof (key));
5055 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
5056 // and if that is not found, fall back to the bsp file entity string
5058 data = cl.worldmodel->brush.entities;
5061 for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
5063 type = LIGHTTYPE_MINUSX;
5064 origin[0] = origin[1] = origin[2] = 0;
5065 originhack[0] = originhack[1] = originhack[2] = 0;
5066 angles[0] = angles[1] = angles[2] = 0;
5067 color[0] = color[1] = color[2] = 1;
5068 light[0] = light[1] = light[2] = 1;light[3] = 300;
5069 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
5079 if (!COM_ParseToken_Simple(&data, false, false))
5081 if (com_token[0] == '}')
5082 break; // end of entity
5083 if (com_token[0] == '_')
5084 strlcpy(key, com_token + 1, sizeof(key));
5086 strlcpy(key, com_token, sizeof(key));
5087 while (key[strlen(key)-1] == ' ') // remove trailing spaces
5088 key[strlen(key)-1] = 0;
5089 if (!COM_ParseToken_Simple(&data, false, false))
5091 strlcpy(value, com_token, sizeof(value));
5093 // now that we have the key pair worked out...
5094 if (!strcmp("light", key))
5096 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5100 light[0] = vec[0] * (1.0f / 256.0f);
5101 light[1] = vec[0] * (1.0f / 256.0f);
5102 light[2] = vec[0] * (1.0f / 256.0f);
5108 light[0] = vec[0] * (1.0f / 255.0f);
5109 light[1] = vec[1] * (1.0f / 255.0f);
5110 light[2] = vec[2] * (1.0f / 255.0f);
5114 else if (!strcmp("delay", key))
5116 else if (!strcmp("origin", key))
5117 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5118 else if (!strcmp("angle", key))
5119 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5120 else if (!strcmp("angles", key))
5121 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5122 else if (!strcmp("color", key))
5123 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5124 else if (!strcmp("wait", key))
5125 fadescale = atof(value);
5126 else if (!strcmp("classname", key))
5128 if (!strncmp(value, "light", 5))
5131 if (!strcmp(value, "light_fluoro"))
5136 overridecolor[0] = 1;
5137 overridecolor[1] = 1;
5138 overridecolor[2] = 1;
5140 if (!strcmp(value, "light_fluorospark"))
5145 overridecolor[0] = 1;
5146 overridecolor[1] = 1;
5147 overridecolor[2] = 1;
5149 if (!strcmp(value, "light_globe"))
5154 overridecolor[0] = 1;
5155 overridecolor[1] = 0.8;
5156 overridecolor[2] = 0.4;
5158 if (!strcmp(value, "light_flame_large_yellow"))
5163 overridecolor[0] = 1;
5164 overridecolor[1] = 0.5;
5165 overridecolor[2] = 0.1;
5167 if (!strcmp(value, "light_flame_small_yellow"))
5172 overridecolor[0] = 1;
5173 overridecolor[1] = 0.5;
5174 overridecolor[2] = 0.1;
5176 if (!strcmp(value, "light_torch_small_white"))
5181 overridecolor[0] = 1;
5182 overridecolor[1] = 0.5;
5183 overridecolor[2] = 0.1;
5185 if (!strcmp(value, "light_torch_small_walltorch"))
5190 overridecolor[0] = 1;
5191 overridecolor[1] = 0.5;
5192 overridecolor[2] = 0.1;
5196 else if (!strcmp("style", key))
5197 style = atoi(value);
5198 else if (!strcmp("skin", key))
5199 skin = (int)atof(value);
5200 else if (!strcmp("pflags", key))
5201 pflags = (int)atof(value);
5202 else if (!strcmp("effects", key))
5203 effects = (int)atof(value);
5204 else if (cl.worldmodel->type == mod_brushq3)
5206 if (!strcmp("scale", key))
5207 lightscale = atof(value);
5208 if (!strcmp("fade", key))
5209 fadescale = atof(value);
5214 if (lightscale <= 0)
5218 if (color[0] == color[1] && color[0] == color[2])
5220 color[0] *= overridecolor[0];
5221 color[1] *= overridecolor[1];
5222 color[2] *= overridecolor[2];
5224 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5225 color[0] = color[0] * light[0];
5226 color[1] = color[1] * light[1];
5227 color[2] = color[2] * light[2];
5230 case LIGHTTYPE_MINUSX:
5232 case LIGHTTYPE_RECIPX:
5234 VectorScale(color, (1.0f / 16.0f), color);
5236 case LIGHTTYPE_RECIPXX:
5238 VectorScale(color, (1.0f / 16.0f), color);
5241 case LIGHTTYPE_NONE:
5245 case LIGHTTYPE_MINUSXX:
5248 VectorAdd(origin, originhack, origin);
5250 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);
5253 Mem_Free(entfiledata);
5257 void R_Shadow_SetCursorLocationForView(void)
5260 vec3_t dest, endpos;
5262 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5263 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
5264 if (trace.fraction < 1)
5266 dist = trace.fraction * r_editlights_cursordistance.value;
5267 push = r_editlights_cursorpushback.value;
5271 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5272 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5276 VectorClear( endpos );
5278 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5279 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5280 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5283 void R_Shadow_UpdateWorldLightSelection(void)
5285 if (r_editlights.integer)
5287 R_Shadow_SetCursorLocationForView();
5288 R_Shadow_SelectLightInView();
5291 R_Shadow_SelectLight(NULL);
5294 void R_Shadow_EditLights_Clear_f(void)
5296 R_Shadow_ClearWorldLights();
5299 void R_Shadow_EditLights_Reload_f(void)
5303 strlcpy(r_shadow_mapname, cl.worldmodel->name, sizeof(r_shadow_mapname));
5304 R_Shadow_ClearWorldLights();
5305 R_Shadow_LoadWorldLights();
5306 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5308 R_Shadow_LoadLightsFile();
5309 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5310 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5314 void R_Shadow_EditLights_Save_f(void)
5318 R_Shadow_SaveWorldLights();
5321 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
5323 R_Shadow_ClearWorldLights();
5324 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5327 void R_Shadow_EditLights_ImportLightsFile_f(void)
5329 R_Shadow_ClearWorldLights();
5330 R_Shadow_LoadLightsFile();
5333 void R_Shadow_EditLights_Spawn_f(void)
5336 if (!r_editlights.integer)
5338 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5341 if (Cmd_Argc() != 1)
5343 Con_Print("r_editlights_spawn does not take parameters\n");
5346 color[0] = color[1] = color[2] = 1;
5347 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5350 void R_Shadow_EditLights_Edit_f(void)
5352 vec3_t origin, angles, color;
5353 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5354 int style, shadows, flags, normalmode, realtimemode;
5355 char cubemapname[MAX_INPUTLINE];
5356 if (!r_editlights.integer)
5358 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5361 if (!r_shadow_selectedlight)
5363 Con_Print("No selected light.\n");
5366 VectorCopy(r_shadow_selectedlight->origin, origin);
5367 VectorCopy(r_shadow_selectedlight->angles, angles);
5368 VectorCopy(r_shadow_selectedlight->color, color);
5369 radius = r_shadow_selectedlight->radius;
5370 style = r_shadow_selectedlight->style;
5371 if (r_shadow_selectedlight->cubemapname)
5372 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5375 shadows = r_shadow_selectedlight->shadow;
5376 corona = r_shadow_selectedlight->corona;
5377 coronasizescale = r_shadow_selectedlight->coronasizescale;
5378 ambientscale = r_shadow_selectedlight->ambientscale;
5379 diffusescale = r_shadow_selectedlight->diffusescale;
5380 specularscale = r_shadow_selectedlight->specularscale;
5381 flags = r_shadow_selectedlight->flags;
5382 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5383 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5384 if (!strcmp(Cmd_Argv(1), "origin"))
5386 if (Cmd_Argc() != 5)
5388 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5391 origin[0] = atof(Cmd_Argv(2));
5392 origin[1] = atof(Cmd_Argv(3));
5393 origin[2] = atof(Cmd_Argv(4));
5395 else if (!strcmp(Cmd_Argv(1), "originx"))
5397 if (Cmd_Argc() != 3)
5399 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5402 origin[0] = atof(Cmd_Argv(2));
5404 else if (!strcmp(Cmd_Argv(1), "originy"))
5406 if (Cmd_Argc() != 3)
5408 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5411 origin[1] = atof(Cmd_Argv(2));
5413 else if (!strcmp(Cmd_Argv(1), "originz"))
5415 if (Cmd_Argc() != 3)
5417 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5420 origin[2] = atof(Cmd_Argv(2));
5422 else if (!strcmp(Cmd_Argv(1), "move"))
5424 if (Cmd_Argc() != 5)
5426 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5429 origin[0] += atof(Cmd_Argv(2));
5430 origin[1] += atof(Cmd_Argv(3));
5431 origin[2] += atof(Cmd_Argv(4));
5433 else if (!strcmp(Cmd_Argv(1), "movex"))
5435 if (Cmd_Argc() != 3)
5437 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5440 origin[0] += atof(Cmd_Argv(2));
5442 else if (!strcmp(Cmd_Argv(1), "movey"))
5444 if (Cmd_Argc() != 3)
5446 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5449 origin[1] += atof(Cmd_Argv(2));
5451 else if (!strcmp(Cmd_Argv(1), "movez"))
5453 if (Cmd_Argc() != 3)
5455 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5458 origin[2] += atof(Cmd_Argv(2));
5460 else if (!strcmp(Cmd_Argv(1), "angles"))
5462 if (Cmd_Argc() != 5)
5464 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5467 angles[0] = atof(Cmd_Argv(2));
5468 angles[1] = atof(Cmd_Argv(3));
5469 angles[2] = atof(Cmd_Argv(4));
5471 else if (!strcmp(Cmd_Argv(1), "anglesx"))
5473 if (Cmd_Argc() != 3)
5475 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5478 angles[0] = atof(Cmd_Argv(2));
5480 else if (!strcmp(Cmd_Argv(1), "anglesy"))
5482 if (Cmd_Argc() != 3)
5484 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5487 angles[1] = atof(Cmd_Argv(2));
5489 else if (!strcmp(Cmd_Argv(1), "anglesz"))
5491 if (Cmd_Argc() != 3)
5493 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5496 angles[2] = atof(Cmd_Argv(2));
5498 else if (!strcmp(Cmd_Argv(1), "color"))
5500 if (Cmd_Argc() != 5)
5502 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
5505 color[0] = atof(Cmd_Argv(2));
5506 color[1] = atof(Cmd_Argv(3));
5507 color[2] = atof(Cmd_Argv(4));
5509 else if (!strcmp(Cmd_Argv(1), "radius"))
5511 if (Cmd_Argc() != 3)
5513 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5516 radius = atof(Cmd_Argv(2));
5518 else if (!strcmp(Cmd_Argv(1), "colorscale"))
5520 if (Cmd_Argc() == 3)
5522 double scale = atof(Cmd_Argv(2));
5529 if (Cmd_Argc() != 5)
5531 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
5534 color[0] *= atof(Cmd_Argv(2));
5535 color[1] *= atof(Cmd_Argv(3));
5536 color[2] *= atof(Cmd_Argv(4));
5539 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
5541 if (Cmd_Argc() != 3)
5543 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5546 radius *= atof(Cmd_Argv(2));
5548 else if (!strcmp(Cmd_Argv(1), "style"))
5550 if (Cmd_Argc() != 3)
5552 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5555 style = atoi(Cmd_Argv(2));
5557 else if (!strcmp(Cmd_Argv(1), "cubemap"))
5561 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5564 if (Cmd_Argc() == 3)
5565 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
5569 else if (!strcmp(Cmd_Argv(1), "shadows"))
5571 if (Cmd_Argc() != 3)
5573 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5576 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5578 else if (!strcmp(Cmd_Argv(1), "corona"))
5580 if (Cmd_Argc() != 3)
5582 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5585 corona = atof(Cmd_Argv(2));
5587 else if (!strcmp(Cmd_Argv(1), "coronasize"))
5589 if (Cmd_Argc() != 3)
5591 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5594 coronasizescale = atof(Cmd_Argv(2));
5596 else if (!strcmp(Cmd_Argv(1), "ambient"))
5598 if (Cmd_Argc() != 3)
5600 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5603 ambientscale = atof(Cmd_Argv(2));
5605 else if (!strcmp(Cmd_Argv(1), "diffuse"))
5607 if (Cmd_Argc() != 3)
5609 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5612 diffusescale = atof(Cmd_Argv(2));
5614 else if (!strcmp(Cmd_Argv(1), "specular"))
5616 if (Cmd_Argc() != 3)
5618 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5621 specularscale = atof(Cmd_Argv(2));
5623 else if (!strcmp(Cmd_Argv(1), "normalmode"))
5625 if (Cmd_Argc() != 3)
5627 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5630 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5632 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
5634 if (Cmd_Argc() != 3)
5636 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5639 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5643 Con_Print("usage: r_editlights_edit [property] [value]\n");
5644 Con_Print("Selected light's properties:\n");
5645 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5646 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5647 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5648 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
5649 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
5650 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
5651 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5652 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
5653 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
5654 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
5655 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
5656 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
5657 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5658 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5661 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5662 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5665 void R_Shadow_EditLights_EditAll_f(void)
5671 if (!r_editlights.integer)
5673 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5677 // EditLights doesn't seem to have a "remove" command or something so:
5678 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5679 for (lightindex = 0;lightindex < range;lightindex++)
5681 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5684 R_Shadow_SelectLight(light);
5685 R_Shadow_EditLights_Edit_f();
5689 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
5691 int lightnumber, lightcount;
5692 size_t lightindex, range;
5696 if (!r_editlights.integer)
5698 x = vid_conwidth.value - 240;
5700 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
5703 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5704 for (lightindex = 0;lightindex < range;lightindex++)
5706 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5709 if (light == r_shadow_selectedlight)
5710 lightnumber = lightindex;
5713 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;
5714 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;
5716 if (r_shadow_selectedlight == NULL)
5718 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;
5719 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;
5720 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;
5721 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;
5722 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;
5723 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;
5724 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;
5725 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;
5726 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;
5727 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;
5728 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;
5729 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;
5730 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;
5731 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;
5732 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;
5735 void R_Shadow_EditLights_ToggleShadow_f(void)
5737 if (!r_editlights.integer)
5739 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5742 if (!r_shadow_selectedlight)
5744 Con_Print("No selected light.\n");
5747 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);
5750 void R_Shadow_EditLights_ToggleCorona_f(void)
5752 if (!r_editlights.integer)
5754 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5757 if (!r_shadow_selectedlight)
5759 Con_Print("No selected light.\n");
5762 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);
5765 void R_Shadow_EditLights_Remove_f(void)
5767 if (!r_editlights.integer)
5769 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
5772 if (!r_shadow_selectedlight)
5774 Con_Print("No selected light.\n");
5777 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
5778 r_shadow_selectedlight = NULL;
5781 void R_Shadow_EditLights_Help_f(void)
5784 "Documentation on r_editlights system:\n"
5786 "r_editlights : enable/disable editing mode\n"
5787 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
5788 "r_editlights_cursorpushback : push back cursor this far from surface\n"
5789 "r_editlights_cursorpushoff : push cursor off surface this far\n"
5790 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
5791 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
5793 "r_editlights_help : this help\n"
5794 "r_editlights_clear : remove all lights\n"
5795 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
5796 "r_editlights_save : save to .rtlights file\n"
5797 "r_editlights_spawn : create a light with default settings\n"
5798 "r_editlights_edit command : edit selected light - more documentation below\n"
5799 "r_editlights_remove : remove selected light\n"
5800 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
5801 "r_editlights_importlightentitiesfrommap : reload light entities\n"
5802 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
5804 "origin x y z : set light location\n"
5805 "originx x: set x component of light location\n"
5806 "originy y: set y component of light location\n"
5807 "originz z: set z component of light location\n"
5808 "move x y z : adjust light location\n"
5809 "movex x: adjust x component of light location\n"
5810 "movey y: adjust y component of light location\n"
5811 "movez z: adjust z component of light location\n"
5812 "angles x y z : set light angles\n"
5813 "anglesx x: set x component of light angles\n"
5814 "anglesy y: set y component of light angles\n"
5815 "anglesz z: set z component of light angles\n"
5816 "color r g b : set color of light (can be brighter than 1 1 1)\n"
5817 "radius radius : set radius (size) of light\n"
5818 "colorscale grey : multiply color of light (1 does nothing)\n"
5819 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
5820 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
5821 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
5822 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
5823 "cubemap basename : set filter cubemap of light (not yet supported)\n"
5824 "shadows 1/0 : turn on/off shadows\n"
5825 "corona n : set corona intensity\n"
5826 "coronasize n : set corona size (0-1)\n"
5827 "ambient n : set ambient intensity (0-1)\n"
5828 "diffuse n : set diffuse intensity (0-1)\n"
5829 "specular n : set specular intensity (0-1)\n"
5830 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
5831 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
5832 "<nothing> : print light properties to console\n"
5836 void R_Shadow_EditLights_CopyInfo_f(void)
5838 if (!r_editlights.integer)
5840 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
5843 if (!r_shadow_selectedlight)
5845 Con_Print("No selected light.\n");
5848 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
5849 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
5850 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
5851 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
5852 if (r_shadow_selectedlight->cubemapname)
5853 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
5855 r_shadow_bufferlight.cubemapname[0] = 0;
5856 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
5857 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
5858 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
5859 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
5860 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
5861 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
5862 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
5865 void R_Shadow_EditLights_PasteInfo_f(void)
5867 if (!r_editlights.integer)
5869 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
5872 if (!r_shadow_selectedlight)
5874 Con_Print("No selected light.\n");
5877 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);
5880 void R_Shadow_EditLights_Init(void)
5882 Cvar_RegisterVariable(&r_editlights);
5883 Cvar_RegisterVariable(&r_editlights_cursordistance);
5884 Cvar_RegisterVariable(&r_editlights_cursorpushback);
5885 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
5886 Cvar_RegisterVariable(&r_editlights_cursorgrid);
5887 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
5888 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
5889 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
5890 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)");
5891 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
5892 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
5893 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
5894 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)");
5895 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
5896 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
5897 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
5898 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
5899 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
5900 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
5901 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)");
5907 =============================================================================
5911 =============================================================================
5914 void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, int dynamic)
5916 VectorClear(diffusecolor);
5917 VectorClear(diffusenormal);
5919 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
5921 ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_refdef.scene.ambient * (2.0f / 128.0f);
5922 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
5925 VectorSet(ambientcolor, 1, 1, 1);
5932 for (i = 0;i < r_refdef.scene.numlights;i++)
5934 light = r_refdef.scene.lights[i];
5935 Matrix4x4_Transform(&light->matrix_worldtolight, p, v);
5936 f = 1 - VectorLength2(v);
5937 if (f > 0 && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
5938 VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);