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;
224 unsigned char *r_shadow_buffer_surfacesides;
226 int r_shadow_buffer_numshadowtrispvsbytes;
227 unsigned char *r_shadow_buffer_shadowtrispvs;
228 int r_shadow_buffer_numlighttrispvsbytes;
229 unsigned char *r_shadow_buffer_lighttrispvs;
231 rtexturepool_t *r_shadow_texturepool;
232 rtexture_t *r_shadow_attenuationgradienttexture;
233 rtexture_t *r_shadow_attenuation2dtexture;
234 rtexture_t *r_shadow_attenuation3dtexture;
235 rtexture_t *r_shadow_lightcorona;
236 rtexture_t *r_shadow_shadowmaprectangletexture;
237 rtexture_t *r_shadow_shadowmap2dtexture;
238 rtexture_t *r_shadow_shadowmapcubetexture[R_SHADOW_SHADOWMAP_NUMCUBEMAPS];
239 rtexture_t *r_shadow_shadowmapvsdcttexture;
240 int r_shadow_shadowmapsize; // changes for each light based on distance
241 int r_shadow_shadowmaplod; // changes for each light based on distance
243 // lights are reloaded when this changes
244 char r_shadow_mapname[MAX_QPATH];
246 // used only for light filters (cubemaps)
247 rtexturepool_t *r_shadow_filters_texturepool;
249 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"};
250 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"};
251 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
252 cvar_t r_shadow_usenormalmap = {CVAR_SAVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"};
253 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)"};
254 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"};
255 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
256 cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
257 cvar_t r_shadow_gloss2exponent = {0, "r_shadow_gloss2exponent", "32", "same as r_shadow_glossexponent but for forced gloss (gloss 2) surfaces"};
258 cvar_t r_shadow_glossexact = {0, "r_shadow_glossexact", "0", "use exact reflection math for gloss (slightly slower, but should look a tad better)"};
259 cvar_t r_shadow_lightattenuationdividebias = {0, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"};
260 cvar_t r_shadow_lightattenuationlinearscale = {0, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"};
261 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
262 cvar_t r_shadow_lightradiusscale = {0, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
263 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1", "use portal culling to exactly determine lit triangles when compiling world lights"};
264 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000", "how far to cast shadows"};
265 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)"};
266 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
267 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
268 cvar_t r_shadow_realtime_dlight_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
269 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
270 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)"};
271 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"};
272 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
273 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
274 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"};
275 cvar_t r_shadow_realtime_world_compilesvbsp = {0, "r_shadow_realtime_world_compilesvbsp", "1", "enables svbsp optimization during compilation"};
276 cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "1", "enables portal-based culling optimization during compilation"};
277 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)"};
278 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"};
279 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"};
280 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)"};
281 cvar_t r_shadow_shadowmapping_precision = {CVAR_SAVE, "r_shadow_shadowmapping_precision", "24", "requested minimum shadowmap texture precision"};
282 cvar_t r_shadow_shadowmapping_vsdct = {CVAR_SAVE, "r_shadow_shadowmapping_vsdct", "1", "enables use of virtual shadow depth cube texture"};
283 cvar_t r_shadow_shadowmapping_minsize = {CVAR_SAVE, "r_shadow_shadowmapping_minsize", "32", "shadowmap size limit"};
284 cvar_t r_shadow_shadowmapping_maxsize = {CVAR_SAVE, "r_shadow_shadowmapping_maxsize", "512", "shadowmap size limit"};
285 cvar_t r_shadow_shadowmapping_lod_bias = {CVAR_SAVE, "r_shadow_shadowmapping_lod_bias", "16", "shadowmap size bias"};
286 cvar_t r_shadow_shadowmapping_lod_scale = {CVAR_SAVE, "r_shadow_shadowmapping_lod_scale", "128", "shadowmap size scaling parameter"};
287 cvar_t r_shadow_shadowmapping_bordersize = {CVAR_SAVE, "r_shadow_shadowmapping_bordersize", "4", "shadowmap size bias for filtering"};
288 cvar_t r_shadow_shadowmapping_nearclip = {CVAR_SAVE, "r_shadow_shadowmapping_nearclip", "1", "shadowmap nearclip in world units"};
289 cvar_t r_shadow_shadowmapping_bias = {CVAR_SAVE, "r_shadow_shadowmapping_bias", "0.03", "shadowmap bias parameter (this is multiplied by nearclip * 1024 / lodsize)"};
290 cvar_t r_shadow_culltriangles = {0, "r_shadow_culltriangles", "1", "performs more expensive tests to remove unnecessary triangles of lit surfaces"};
291 cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
292 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)"};
293 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)"};
294 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "1", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
295 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"};
296 cvar_t r_coronas_occlusionquery = {CVAR_SAVE, "r_coronas_occlusionquery", "1", "use GL_ARB_occlusion_query extension if supported (fades coronas according to visibility)"};
297 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
298 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
299 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
300 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
301 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
302 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
303 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
304 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
305 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
307 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
308 #define ATTENTABLESIZE 256
309 // 1D gradient, 2D circle and 3D sphere attenuation textures
310 #define ATTEN1DSIZE 32
311 #define ATTEN2DSIZE 64
312 #define ATTEN3DSIZE 32
314 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
315 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
316 static float r_shadow_attentable[ATTENTABLESIZE+1];
318 rtlight_t *r_shadow_compilingrtlight;
319 static memexpandablearray_t r_shadow_worldlightsarray;
320 dlight_t *r_shadow_selectedlight;
321 dlight_t r_shadow_bufferlight;
322 vec3_t r_editlights_cursorlocation;
324 extern int con_vislines;
326 typedef struct cubemapinfo_s
333 #define MAX_CUBEMAPS 256
334 static int numcubemaps;
335 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
337 void R_Shadow_UncompileWorldLights(void);
338 void R_Shadow_ClearWorldLights(void);
339 void R_Shadow_SaveWorldLights(void);
340 void R_Shadow_LoadWorldLights(void);
341 void R_Shadow_LoadLightsFile(void);
342 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
343 void R_Shadow_EditLights_Reload_f(void);
344 void R_Shadow_ValidateCvars(void);
345 static void R_Shadow_MakeTextures(void);
347 // VorteX: custom editor light sprites
348 #define EDLIGHTSPRSIZE 8
349 cachepic_t *r_editlights_sprcursor;
350 cachepic_t *r_editlights_sprlight;
351 cachepic_t *r_editlights_sprnoshadowlight;
352 cachepic_t *r_editlights_sprcubemaplight;
353 cachepic_t *r_editlights_sprcubemapnoshadowlight;
354 cachepic_t *r_editlights_sprselection;
356 void R_Shadow_SetShadowMode(void)
358 r_shadow_shadowmapmaxsize = bound(1, r_shadow_shadowmapping_maxsize.integer, 2048);
359 r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer != 0;
360 r_shadow_shadowmapfilterquality = r_shadow_shadowmapping_filterquality.integer;
361 r_shadow_shadowmaptexturetype = r_shadow_shadowmapping_texturetype.integer;
362 r_shadow_shadowmapprecision = r_shadow_shadowmapping_precision.integer;
363 r_shadow_shadowmapborder = bound(0, r_shadow_shadowmapping_bordersize.integer, 16);
364 r_shadow_shadowmaplod = -1;
365 r_shadow_shadowmapsize = 0;
366 r_shadow_shadowmapsampler = false;
367 r_shadow_shadowmappcf = 0;
368 r_shadow_shadowmode = 0;
369 if(r_shadow_shadowmapping.integer)
371 if(r_shadow_shadowmapfilterquality < 0)
373 if(strstr(gl_vendor, "NVIDIA"))
375 r_shadow_shadowmapsampler = gl_support_arb_shadow;
376 r_shadow_shadowmappcf = 1;
378 else if(gl_support_amd_texture_texture4 || gl_support_arb_texture_gather)
379 r_shadow_shadowmappcf = 1;
380 else if(strstr(gl_vendor, "ATI"))
381 r_shadow_shadowmappcf = 1;
383 r_shadow_shadowmapsampler = gl_support_arb_shadow;
387 switch (r_shadow_shadowmapfilterquality)
390 r_shadow_shadowmapsampler = gl_support_arb_shadow;
393 r_shadow_shadowmapsampler = gl_support_arb_shadow;
394 r_shadow_shadowmappcf = 1;
397 r_shadow_shadowmappcf = 1;
400 r_shadow_shadowmappcf = 2;
404 r_shadow_shadowmode = r_shadow_shadowmaptexturetype;
405 if(r_shadow_shadowmode <= 0)
407 if((gl_support_amd_texture_texture4 || gl_support_arb_texture_gather) && r_shadow_shadowmappcf && !r_shadow_shadowmapsampler)
408 r_shadow_shadowmode = 1;
409 else if(gl_texturerectangle)
410 r_shadow_shadowmode = 2;
412 r_shadow_shadowmode = 1;
417 void R_Shadow_FreeShadowMaps(void)
421 R_Shadow_SetShadowMode();
423 if (r_shadow_fborectangle)
424 qglDeleteFramebuffersEXT(1, &r_shadow_fborectangle);
425 r_shadow_fborectangle = 0;
429 qglDeleteFramebuffersEXT(1, &r_shadow_fbo2d);
432 for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
433 if (r_shadow_fbocubeside[i][0])
434 qglDeleteFramebuffersEXT(6, r_shadow_fbocubeside[i]);
435 memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
438 if (r_shadow_shadowmaprectangletexture)
439 R_FreeTexture(r_shadow_shadowmaprectangletexture);
440 r_shadow_shadowmaprectangletexture = NULL;
442 if (r_shadow_shadowmap2dtexture)
443 R_FreeTexture(r_shadow_shadowmap2dtexture);
444 r_shadow_shadowmap2dtexture = NULL;
446 for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
447 if (r_shadow_shadowmapcubetexture[i])
448 R_FreeTexture(r_shadow_shadowmapcubetexture[i]);
449 memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
451 if (r_shadow_shadowmapvsdcttexture)
452 R_FreeTexture(r_shadow_shadowmapvsdcttexture);
453 r_shadow_shadowmapvsdcttexture = NULL;
458 void r_shadow_start(void)
460 // allocate vertex processing arrays
462 r_shadow_attenuationgradienttexture = NULL;
463 r_shadow_attenuation2dtexture = NULL;
464 r_shadow_attenuation3dtexture = NULL;
465 r_shadow_shadowmode = 0;
466 r_shadow_shadowmaprectangletexture = NULL;
467 r_shadow_shadowmap2dtexture = NULL;
468 memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
469 r_shadow_shadowmapvsdcttexture = NULL;
470 r_shadow_shadowmapmaxsize = 0;
471 r_shadow_shadowmapsize = 0;
472 r_shadow_shadowmaplod = 0;
473 r_shadow_shadowmapfilterquality = 0;
474 r_shadow_shadowmaptexturetype = 0;
475 r_shadow_shadowmapprecision = 0;
476 r_shadow_shadowmapvsdct = false;
477 r_shadow_shadowmapsampler = false;
478 r_shadow_shadowmappcf = 0;
479 r_shadow_fborectangle = 0;
481 memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
483 R_Shadow_FreeShadowMaps();
485 r_shadow_texturepool = NULL;
486 r_shadow_filters_texturepool = NULL;
487 R_Shadow_ValidateCvars();
488 R_Shadow_MakeTextures();
489 maxshadowtriangles = 0;
490 shadowelements = NULL;
491 maxshadowvertices = 0;
492 shadowvertex3f = NULL;
500 shadowmarklist = NULL;
505 shadowsideslist = NULL;
506 r_shadow_buffer_numleafpvsbytes = 0;
507 r_shadow_buffer_visitingleafpvs = NULL;
508 r_shadow_buffer_leafpvs = NULL;
509 r_shadow_buffer_leaflist = NULL;
510 r_shadow_buffer_numsurfacepvsbytes = 0;
511 r_shadow_buffer_surfacepvs = NULL;
512 r_shadow_buffer_surfacelist = NULL;
513 r_shadow_buffer_surfacesides = NULL;
514 r_shadow_buffer_numshadowtrispvsbytes = 0;
515 r_shadow_buffer_shadowtrispvs = NULL;
516 r_shadow_buffer_numlighttrispvsbytes = 0;
517 r_shadow_buffer_lighttrispvs = NULL;
520 void r_shadow_shutdown(void)
523 R_Shadow_UncompileWorldLights();
525 R_Shadow_FreeShadowMaps();
529 r_shadow_attenuationgradienttexture = NULL;
530 r_shadow_attenuation2dtexture = NULL;
531 r_shadow_attenuation3dtexture = NULL;
532 R_FreeTexturePool(&r_shadow_texturepool);
533 R_FreeTexturePool(&r_shadow_filters_texturepool);
534 maxshadowtriangles = 0;
536 Mem_Free(shadowelements);
537 shadowelements = NULL;
539 Mem_Free(shadowvertex3f);
540 shadowvertex3f = NULL;
543 Mem_Free(vertexupdate);
546 Mem_Free(vertexremap);
552 Mem_Free(shadowmark);
555 Mem_Free(shadowmarklist);
556 shadowmarklist = NULL;
561 Mem_Free(shadowsides);
564 Mem_Free(shadowsideslist);
565 shadowsideslist = NULL;
566 r_shadow_buffer_numleafpvsbytes = 0;
567 if (r_shadow_buffer_visitingleafpvs)
568 Mem_Free(r_shadow_buffer_visitingleafpvs);
569 r_shadow_buffer_visitingleafpvs = NULL;
570 if (r_shadow_buffer_leafpvs)
571 Mem_Free(r_shadow_buffer_leafpvs);
572 r_shadow_buffer_leafpvs = NULL;
573 if (r_shadow_buffer_leaflist)
574 Mem_Free(r_shadow_buffer_leaflist);
575 r_shadow_buffer_leaflist = NULL;
576 r_shadow_buffer_numsurfacepvsbytes = 0;
577 if (r_shadow_buffer_surfacepvs)
578 Mem_Free(r_shadow_buffer_surfacepvs);
579 r_shadow_buffer_surfacepvs = NULL;
580 if (r_shadow_buffer_surfacelist)
581 Mem_Free(r_shadow_buffer_surfacelist);
582 r_shadow_buffer_surfacelist = NULL;
583 if (r_shadow_buffer_surfacesides)
584 Mem_Free(r_shadow_buffer_surfacesides);
585 r_shadow_buffer_surfacesides = NULL;
586 r_shadow_buffer_numshadowtrispvsbytes = 0;
587 if (r_shadow_buffer_shadowtrispvs)
588 Mem_Free(r_shadow_buffer_shadowtrispvs);
589 r_shadow_buffer_numlighttrispvsbytes = 0;
590 if (r_shadow_buffer_lighttrispvs)
591 Mem_Free(r_shadow_buffer_lighttrispvs);
594 void r_shadow_newmap(void)
596 if (cl.worldmodel && strncmp(cl.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
597 R_Shadow_EditLights_Reload_f();
600 void R_Shadow_Help_f(void)
603 "Documentation on r_shadow system:\n"
605 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
606 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
607 "r_shadow_debuglight : render only this light number (-1 = all)\n"
608 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
609 "r_shadow_gloss2intensity : brightness of forced gloss\n"
610 "r_shadow_glossintensity : brightness of textured gloss\n"
611 "r_shadow_lightattenuationlinearscale : used to generate attenuation texture\n"
612 "r_shadow_lightattenuationdividebias : used to generate attenuation texture\n"
613 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
614 "r_shadow_lightradiusscale : scale rendering radius of all lights\n"
615 "r_shadow_portallight : use portal visibility for static light precomputation\n"
616 "r_shadow_projectdistance : shadow volume projection distance\n"
617 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
618 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
619 "r_shadow_realtime_world : use high quality world lighting mode\n"
620 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
621 "r_shadow_realtime_world_shadows : cast shadows from world lights\n"
622 "r_shadow_realtime_world_compile : compile surface/visibility information\n"
623 "r_shadow_realtime_world_compileshadow : compile shadow geometry\n"
624 "r_shadow_scissor : use scissor optimization\n"
625 "r_shadow_polygonfactor : nudge shadow volumes closer/further\n"
626 "r_shadow_polygonoffset : nudge shadow volumes closer/further\n"
627 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
628 "r_showlighting : useful for performance testing; bright = slow!\n"
629 "r_showshadowvolumes : useful for performance testing; bright = slow!\n"
631 "r_shadow_help : this help\n"
635 void R_Shadow_Init(void)
637 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
638 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
639 Cvar_RegisterVariable(&r_shadow_usenormalmap);
640 Cvar_RegisterVariable(&r_shadow_debuglight);
641 Cvar_RegisterVariable(&r_shadow_gloss);
642 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
643 Cvar_RegisterVariable(&r_shadow_glossintensity);
644 Cvar_RegisterVariable(&r_shadow_glossexponent);
645 Cvar_RegisterVariable(&r_shadow_gloss2exponent);
646 Cvar_RegisterVariable(&r_shadow_glossexact);
647 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
648 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
649 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
650 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
651 Cvar_RegisterVariable(&r_shadow_portallight);
652 Cvar_RegisterVariable(&r_shadow_projectdistance);
653 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
654 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
655 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
656 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
657 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
658 Cvar_RegisterVariable(&r_shadow_realtime_world);
659 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
660 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
661 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
662 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
663 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
664 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
665 Cvar_RegisterVariable(&r_shadow_scissor);
666 Cvar_RegisterVariable(&r_shadow_shadowmapping);
667 Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
668 Cvar_RegisterVariable(&r_shadow_shadowmapping_texturetype);
669 Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
670 Cvar_RegisterVariable(&r_shadow_shadowmapping_precision);
671 Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
672 Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
673 Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
674 Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
675 Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
676 Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
677 Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
678 Cvar_RegisterVariable(&r_shadow_culltriangles);
679 Cvar_RegisterVariable(&r_shadow_polygonfactor);
680 Cvar_RegisterVariable(&r_shadow_polygonoffset);
681 Cvar_RegisterVariable(&r_shadow_texture3d);
682 Cvar_RegisterVariable(&r_coronas);
683 Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
684 Cvar_RegisterVariable(&r_coronas_occlusionquery);
685 Cvar_RegisterVariable(&gl_flashblend);
686 Cvar_RegisterVariable(&gl_ext_separatestencil);
687 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
688 if (gamemode == GAME_TENEBRAE)
690 Cvar_SetValue("r_shadow_gloss", 2);
691 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
693 Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f, "prints documentation on console commands and variables used by realtime lighting and shadowing system");
694 R_Shadow_EditLights_Init();
695 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
696 maxshadowtriangles = 0;
697 shadowelements = NULL;
698 maxshadowvertices = 0;
699 shadowvertex3f = NULL;
707 shadowmarklist = NULL;
712 shadowsideslist = NULL;
713 r_shadow_buffer_numleafpvsbytes = 0;
714 r_shadow_buffer_visitingleafpvs = NULL;
715 r_shadow_buffer_leafpvs = NULL;
716 r_shadow_buffer_leaflist = NULL;
717 r_shadow_buffer_numsurfacepvsbytes = 0;
718 r_shadow_buffer_surfacepvs = NULL;
719 r_shadow_buffer_surfacelist = NULL;
720 r_shadow_buffer_surfacesides = NULL;
721 r_shadow_buffer_shadowtrispvs = NULL;
722 r_shadow_buffer_lighttrispvs = NULL;
723 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
726 matrix4x4_t matrix_attenuationxyz =
729 {0.5, 0.0, 0.0, 0.5},
730 {0.0, 0.5, 0.0, 0.5},
731 {0.0, 0.0, 0.5, 0.5},
736 matrix4x4_t matrix_attenuationz =
739 {0.0, 0.0, 0.5, 0.5},
740 {0.0, 0.0, 0.0, 0.5},
741 {0.0, 0.0, 0.0, 0.5},
746 void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles, int vertscale, int triscale)
748 numvertices = ((numvertices + 255) & ~255) * vertscale;
749 numtriangles = ((numtriangles + 255) & ~255) * triscale;
750 // make sure shadowelements is big enough for this volume
751 if (maxshadowtriangles < numtriangles)
753 maxshadowtriangles = numtriangles;
755 Mem_Free(shadowelements);
756 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[3]));
758 // make sure shadowvertex3f is big enough for this volume
759 if (maxshadowvertices < numvertices)
761 maxshadowvertices = numvertices;
763 Mem_Free(shadowvertex3f);
764 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[3]));
768 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
770 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
771 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
772 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
773 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
774 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
776 if (r_shadow_buffer_visitingleafpvs)
777 Mem_Free(r_shadow_buffer_visitingleafpvs);
778 if (r_shadow_buffer_leafpvs)
779 Mem_Free(r_shadow_buffer_leafpvs);
780 if (r_shadow_buffer_leaflist)
781 Mem_Free(r_shadow_buffer_leaflist);
782 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
783 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
784 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
785 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
787 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
789 if (r_shadow_buffer_surfacepvs)
790 Mem_Free(r_shadow_buffer_surfacepvs);
791 if (r_shadow_buffer_surfacelist)
792 Mem_Free(r_shadow_buffer_surfacelist);
793 if (r_shadow_buffer_surfacesides)
794 Mem_Free(r_shadow_buffer_surfacesides);
795 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
796 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
797 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
798 r_shadow_buffer_surfacesides = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
800 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
802 if (r_shadow_buffer_shadowtrispvs)
803 Mem_Free(r_shadow_buffer_shadowtrispvs);
804 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
805 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
807 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
809 if (r_shadow_buffer_lighttrispvs)
810 Mem_Free(r_shadow_buffer_lighttrispvs);
811 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
812 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
816 void R_Shadow_PrepareShadowMark(int numtris)
818 // make sure shadowmark is big enough for this volume
819 if (maxshadowmark < numtris)
821 maxshadowmark = numtris;
823 Mem_Free(shadowmark);
825 Mem_Free(shadowmarklist);
826 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
827 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
831 // if shadowmarkcount wrapped we clear the array and adjust accordingly
832 if (shadowmarkcount == 0)
835 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
840 void R_Shadow_PrepareShadowSides(int numtris)
842 if (maxshadowsides < numtris)
844 maxshadowsides = numtris;
846 Mem_Free(shadowsides);
848 Mem_Free(shadowsideslist);
849 shadowsides = (unsigned char *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsides));
850 shadowsideslist = (int *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsideslist));
855 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)
858 int outtriangles = 0, outvertices = 0;
861 float ratio, direction[3], projectvector[3];
863 if (projectdirection)
864 VectorScale(projectdirection, projectdistance, projectvector);
866 VectorClear(projectvector);
868 // create the vertices
869 if (projectdirection)
871 for (i = 0;i < numshadowmarktris;i++)
873 element = inelement3i + shadowmarktris[i] * 3;
874 for (j = 0;j < 3;j++)
876 if (vertexupdate[element[j]] != vertexupdatenum)
878 vertexupdate[element[j]] = vertexupdatenum;
879 vertexremap[element[j]] = outvertices;
880 vertex = invertex3f + element[j] * 3;
881 // project one copy of the vertex according to projectvector
882 VectorCopy(vertex, outvertex3f);
883 VectorAdd(vertex, projectvector, (outvertex3f + 3));
892 for (i = 0;i < numshadowmarktris;i++)
894 element = inelement3i + shadowmarktris[i] * 3;
895 for (j = 0;j < 3;j++)
897 if (vertexupdate[element[j]] != vertexupdatenum)
899 vertexupdate[element[j]] = vertexupdatenum;
900 vertexremap[element[j]] = outvertices;
901 vertex = invertex3f + element[j] * 3;
902 // project one copy of the vertex to the sphere radius of the light
903 // (FIXME: would projecting it to the light box be better?)
904 VectorSubtract(vertex, projectorigin, direction);
905 ratio = projectdistance / VectorLength(direction);
906 VectorCopy(vertex, outvertex3f);
907 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
915 if (r_shadow_frontsidecasting.integer)
917 for (i = 0;i < numshadowmarktris;i++)
919 int remappedelement[3];
921 const int *neighbortriangle;
923 markindex = shadowmarktris[i] * 3;
924 element = inelement3i + markindex;
925 neighbortriangle = inneighbor3i + markindex;
926 // output the front and back triangles
927 outelement3i[0] = vertexremap[element[0]];
928 outelement3i[1] = vertexremap[element[1]];
929 outelement3i[2] = vertexremap[element[2]];
930 outelement3i[3] = vertexremap[element[2]] + 1;
931 outelement3i[4] = vertexremap[element[1]] + 1;
932 outelement3i[5] = vertexremap[element[0]] + 1;
936 // output the sides (facing outward from this triangle)
937 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
939 remappedelement[0] = vertexremap[element[0]];
940 remappedelement[1] = vertexremap[element[1]];
941 outelement3i[0] = remappedelement[1];
942 outelement3i[1] = remappedelement[0];
943 outelement3i[2] = remappedelement[0] + 1;
944 outelement3i[3] = remappedelement[1];
945 outelement3i[4] = remappedelement[0] + 1;
946 outelement3i[5] = remappedelement[1] + 1;
951 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
953 remappedelement[1] = vertexremap[element[1]];
954 remappedelement[2] = vertexremap[element[2]];
955 outelement3i[0] = remappedelement[2];
956 outelement3i[1] = remappedelement[1];
957 outelement3i[2] = remappedelement[1] + 1;
958 outelement3i[3] = remappedelement[2];
959 outelement3i[4] = remappedelement[1] + 1;
960 outelement3i[5] = remappedelement[2] + 1;
965 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
967 remappedelement[0] = vertexremap[element[0]];
968 remappedelement[2] = vertexremap[element[2]];
969 outelement3i[0] = remappedelement[0];
970 outelement3i[1] = remappedelement[2];
971 outelement3i[2] = remappedelement[2] + 1;
972 outelement3i[3] = remappedelement[0];
973 outelement3i[4] = remappedelement[2] + 1;
974 outelement3i[5] = remappedelement[0] + 1;
983 for (i = 0;i < numshadowmarktris;i++)
985 int remappedelement[3];
987 const int *neighbortriangle;
989 markindex = shadowmarktris[i] * 3;
990 element = inelement3i + markindex;
991 neighbortriangle = inneighbor3i + markindex;
992 // output the front and back triangles
993 outelement3i[0] = vertexremap[element[2]];
994 outelement3i[1] = vertexremap[element[1]];
995 outelement3i[2] = vertexremap[element[0]];
996 outelement3i[3] = vertexremap[element[0]] + 1;
997 outelement3i[4] = vertexremap[element[1]] + 1;
998 outelement3i[5] = vertexremap[element[2]] + 1;
1002 // output the sides (facing outward from this triangle)
1003 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
1005 remappedelement[0] = vertexremap[element[0]];
1006 remappedelement[1] = vertexremap[element[1]];
1007 outelement3i[0] = remappedelement[0];
1008 outelement3i[1] = remappedelement[1];
1009 outelement3i[2] = remappedelement[1] + 1;
1010 outelement3i[3] = remappedelement[0];
1011 outelement3i[4] = remappedelement[1] + 1;
1012 outelement3i[5] = remappedelement[0] + 1;
1017 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1019 remappedelement[1] = vertexremap[element[1]];
1020 remappedelement[2] = vertexremap[element[2]];
1021 outelement3i[0] = remappedelement[1];
1022 outelement3i[1] = remappedelement[2];
1023 outelement3i[2] = remappedelement[2] + 1;
1024 outelement3i[3] = remappedelement[1];
1025 outelement3i[4] = remappedelement[2] + 1;
1026 outelement3i[5] = remappedelement[1] + 1;
1031 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1033 remappedelement[0] = vertexremap[element[0]];
1034 remappedelement[2] = vertexremap[element[2]];
1035 outelement3i[0] = remappedelement[2];
1036 outelement3i[1] = remappedelement[0];
1037 outelement3i[2] = remappedelement[0] + 1;
1038 outelement3i[3] = remappedelement[2];
1039 outelement3i[4] = remappedelement[0] + 1;
1040 outelement3i[5] = remappedelement[2] + 1;
1048 *outnumvertices = outvertices;
1049 return outtriangles;
1052 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)
1055 int outtriangles = 0, outvertices = 0;
1057 const float *vertex;
1058 float ratio, direction[3], projectvector[3];
1061 if (projectdirection)
1062 VectorScale(projectdirection, projectdistance, projectvector);
1064 VectorClear(projectvector);
1066 for (i = 0;i < numshadowmarktris;i++)
1068 int remappedelement[3];
1070 const int *neighbortriangle;
1072 markindex = shadowmarktris[i] * 3;
1073 neighbortriangle = inneighbor3i + markindex;
1074 side[0] = shadowmark[neighbortriangle[0]] == shadowmarkcount;
1075 side[1] = shadowmark[neighbortriangle[1]] == shadowmarkcount;
1076 side[2] = shadowmark[neighbortriangle[2]] == shadowmarkcount;
1077 if (side[0] + side[1] + side[2] == 0)
1081 element = inelement3i + markindex;
1083 // create the vertices
1084 for (j = 0;j < 3;j++)
1086 if (side[j] + side[j+1] == 0)
1089 if (vertexupdate[k] != vertexupdatenum)
1091 vertexupdate[k] = vertexupdatenum;
1092 vertexremap[k] = outvertices;
1093 vertex = invertex3f + k * 3;
1094 VectorCopy(vertex, outvertex3f);
1095 if (projectdirection)
1097 // project one copy of the vertex according to projectvector
1098 VectorAdd(vertex, projectvector, (outvertex3f + 3));
1102 // project one copy of the vertex to the sphere radius of the light
1103 // (FIXME: would projecting it to the light box be better?)
1104 VectorSubtract(vertex, projectorigin, direction);
1105 ratio = projectdistance / VectorLength(direction);
1106 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1113 // output the sides (facing outward from this triangle)
1116 remappedelement[0] = vertexremap[element[0]];
1117 remappedelement[1] = vertexremap[element[1]];
1118 outelement3i[0] = remappedelement[1];
1119 outelement3i[1] = remappedelement[0];
1120 outelement3i[2] = remappedelement[0] + 1;
1121 outelement3i[3] = remappedelement[1];
1122 outelement3i[4] = remappedelement[0] + 1;
1123 outelement3i[5] = remappedelement[1] + 1;
1130 remappedelement[1] = vertexremap[element[1]];
1131 remappedelement[2] = vertexremap[element[2]];
1132 outelement3i[0] = remappedelement[2];
1133 outelement3i[1] = remappedelement[1];
1134 outelement3i[2] = remappedelement[1] + 1;
1135 outelement3i[3] = remappedelement[2];
1136 outelement3i[4] = remappedelement[1] + 1;
1137 outelement3i[5] = remappedelement[2] + 1;
1144 remappedelement[0] = vertexremap[element[0]];
1145 remappedelement[2] = vertexremap[element[2]];
1146 outelement3i[0] = remappedelement[0];
1147 outelement3i[1] = remappedelement[2];
1148 outelement3i[2] = remappedelement[2] + 1;
1149 outelement3i[3] = remappedelement[0];
1150 outelement3i[4] = remappedelement[2] + 1;
1151 outelement3i[5] = remappedelement[0] + 1;
1158 *outnumvertices = outvertices;
1159 return outtriangles;
1162 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)
1168 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1170 tend = firsttriangle + numtris;
1171 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1173 // surface box entirely inside light box, no box cull
1174 if (projectdirection)
1176 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1178 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
1179 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1180 shadowmarklist[numshadowmark++] = t;
1185 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1186 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
1187 shadowmarklist[numshadowmark++] = t;
1192 // surface box not entirely inside light box, cull each triangle
1193 if (projectdirection)
1195 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1197 v[0] = invertex3f + e[0] * 3;
1198 v[1] = invertex3f + e[1] * 3;
1199 v[2] = invertex3f + e[2] * 3;
1200 TriangleNormal(v[0], v[1], v[2], normal);
1201 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1202 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1203 shadowmarklist[numshadowmark++] = t;
1208 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1210 v[0] = invertex3f + e[0] * 3;
1211 v[1] = invertex3f + e[1] * 3;
1212 v[2] = invertex3f + e[2] * 3;
1213 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1214 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1215 shadowmarklist[numshadowmark++] = t;
1221 qboolean R_Shadow_UseZPass(vec3_t mins, vec3_t maxs)
1226 if (r_shadow_compilingrtlight || !r_shadow_frontsidecasting.integer || !r_shadow_usezpassifpossible.integer)
1228 // check if the shadow volume intersects the near plane
1230 // a ray between the eye and light origin may intersect the caster,
1231 // indicating that the shadow may touch the eye location, however we must
1232 // test the near plane (a polygon), not merely the eye location, so it is
1233 // easiest to enlarge the caster bounding shape slightly for this.
1239 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)
1241 int i, tris, outverts;
1242 if (projectdistance < 0.1)
1244 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
1247 if (!numverts || !nummarktris)
1249 // make sure shadowelements is big enough for this volume
1250 if (maxshadowtriangles < nummarktris*8 || maxshadowvertices < numverts*2)
1251 R_Shadow_ResizeShadowArrays(numverts, nummarktris, 2, 8);
1253 if (maxvertexupdate < numverts)
1255 maxvertexupdate = numverts;
1257 Mem_Free(vertexupdate);
1259 Mem_Free(vertexremap);
1260 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1261 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1262 vertexupdatenum = 0;
1265 if (vertexupdatenum == 0)
1267 vertexupdatenum = 1;
1268 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
1269 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
1272 for (i = 0;i < nummarktris;i++)
1273 shadowmark[marktris[i]] = shadowmarkcount;
1275 if (r_shadow_compilingrtlight)
1277 // if we're compiling an rtlight, capture the mesh
1278 //tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1279 //Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zpass, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1280 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1281 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zfail, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1285 // decide which type of shadow to generate and set stencil mode
1286 R_Shadow_RenderMode_StencilShadowVolumes(R_Shadow_UseZPass(trismins, trismaxs));
1287 // generate the sides or a solid volume, depending on type
1288 if (r_shadow_rendermode >= R_SHADOW_RENDERMODE_ZPASS_STENCIL && r_shadow_rendermode <= R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE)
1289 tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1291 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1292 r_refdef.stats.lights_dynamicshadowtriangles += tris;
1293 r_refdef.stats.lights_shadowtriangles += tris;
1295 R_Mesh_VertexPointer(shadowvertex3f, 0, 0);
1296 GL_LockArrays(0, outverts);
1297 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
1299 // increment stencil if frontface is infront of depthbuffer
1300 GL_CullFace(r_refdef.view.cullface_front);
1301 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1302 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1303 // decrement stencil if backface is infront of depthbuffer
1304 GL_CullFace(r_refdef.view.cullface_back);
1305 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1307 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
1309 // decrement stencil if backface is behind depthbuffer
1310 GL_CullFace(r_refdef.view.cullface_front);
1311 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1312 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1313 // increment stencil if frontface is behind depthbuffer
1314 GL_CullFace(r_refdef.view.cullface_back);
1315 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1317 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1318 GL_LockArrays(0, 0);
1323 int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias)
1325 // p1, p2, p3 are in the cubemap's local coordinate system
1326 // bias = border/(size - border)
1329 float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1330 dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2),
1331 dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3);
1332 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1334 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1335 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1336 | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1337 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1339 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1340 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1341 | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1343 dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1344 dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2),
1345 dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3);
1346 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1348 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1349 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1350 | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1351 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1353 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1354 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1355 | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1357 dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1358 dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2),
1359 dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3);
1360 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1362 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1363 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1364 | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1365 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1367 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1368 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1369 | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1374 int R_Shadow_CalcBBoxSideMask(const vec3_t mins, const vec3_t maxs, const matrix4x4_t *worldtolight, const matrix4x4_t *radiustolight, float bias)
1376 vec3_t center, radius, lightcenter, lightradius, pmin, pmax;
1377 float dp1, dn1, ap1, an1, dp2, dn2, ap2, an2;
1380 VectorSubtract(maxs, mins, radius);
1381 VectorScale(radius, 0.5f, radius);
1382 VectorAdd(mins, radius, center);
1383 Matrix4x4_Transform(worldtolight, center, lightcenter);
1384 Matrix4x4_Transform3x3(radiustolight, radius, lightradius);
1385 VectorSubtract(lightcenter, lightradius, pmin);
1386 VectorAdd(lightcenter, lightradius, pmax);
1388 dp1 = pmax[0] + pmax[1], dn1 = pmax[0] - pmin[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1389 dp2 = pmin[0] + pmin[1], dn2 = pmin[0] - pmax[1], ap2 = fabs(dp2), an2 = fabs(dn2);
1390 if(ap1 > bias*an1 && ap2 > bias*an2)
1392 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1393 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1394 if(an1 > bias*ap1 && an2 > bias*ap2)
1396 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1397 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1399 dp1 = pmax[1] + pmax[2], dn1 = pmax[1] - pmin[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1400 dp2 = pmin[1] + pmin[2], dn2 = pmin[1] - pmax[2], ap2 = fabs(dp2), an2 = fabs(dn2);
1401 if(ap1 > bias*an1 && ap2 > bias*an2)
1403 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1404 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1405 if(an1 > bias*ap1 && an2 > bias*ap2)
1407 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1408 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1410 dp1 = pmax[2] + pmax[0], dn1 = pmax[2] - pmin[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1411 dp2 = pmin[2] + pmin[0], dn2 = pmin[2] - pmax[0], ap2 = fabs(dp2), an2 = fabs(dn2);
1412 if(ap1 > bias*an1 && ap2 > bias*an2)
1414 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1415 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1416 if(an1 > bias*ap1 && an2 > bias*ap2)
1418 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1419 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1424 #define R_Shadow_CalcEntitySideMask(ent, worldtolight, radiustolight, bias) R_Shadow_CalcBBoxSideMask((ent)->mins, (ent)->maxs, worldtolight, radiustolight, bias)
1426 int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
1428 // p is in the cubemap's local coordinate system
1429 // bias = border/(size - border)
1430 float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn);
1431 float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn);
1432 float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn);
1434 if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
1435 if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
1436 if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
1437 if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
1438 if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
1439 if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
1443 int R_Shadow_CullFrustumSides(rtlight_t *rtlight, float size, float border)
1447 int sides = 0x3F, masks[6] = { 3<<4, 3<<4, 3<<0, 3<<0, 3<<2, 3<<2 };
1448 float scale = (size - 2*border)/size, len;
1449 float bias = border / (float)(size - border), dp, dn, ap, an;
1450 // check if cone enclosing side would cross frustum plane
1451 scale = 2 / (scale*scale + 2);
1452 for (i = 0;i < 5;i++)
1454 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) > -0.03125)
1456 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[i].normal, n);
1457 len = scale*VectorLength2(n);
1458 if(n[0]*n[0] > len) sides &= n[0] < 0 ? ~(1<<0) : ~(2 << 0);
1459 if(n[1]*n[1] > len) sides &= n[1] < 0 ? ~(1<<2) : ~(2 << 2);
1460 if(n[2]*n[2] > len) sides &= n[2] < 0 ? ~(1<<4) : ~(2 << 4);
1462 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[4]) >= r_refdef.farclip - r_refdef.nearclip + 0.03125)
1464 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[4].normal, n);
1465 len = scale*VectorLength(n);
1466 if(n[0]*n[0] > len) sides &= n[0] >= 0 ? ~(1<<0) : ~(2 << 0);
1467 if(n[1]*n[1] > len) sides &= n[1] >= 0 ? ~(1<<2) : ~(2 << 2);
1468 if(n[2]*n[2] > len) sides &= n[2] >= 0 ? ~(1<<4) : ~(2 << 4);
1470 // this next test usually clips off more sides than the former, but occasionally clips fewer/different ones, so do both and combine results
1471 // check if frustum corners/origin cross plane sides
1472 for (i = 0;i < 5;i++)
1474 Matrix4x4_Transform(&rtlight->matrix_worldtolight, !i ? r_refdef.view.origin : r_refdef.view.frustumcorner[i-1], p);
1475 dp = p[0] + p[1], dn = p[0] - p[1], ap = fabs(dp), an = fabs(dn),
1476 masks[0] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1477 masks[1] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1478 dp = p[1] + p[2], dn = p[1] - p[2], ap = fabs(dp), an = fabs(dn),
1479 masks[2] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1480 masks[3] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1481 dp = p[2] + p[0], dn = p[2] - p[0], ap = fabs(dp), an = fabs(dn),
1482 masks[4] |= ap <= bias*an ? 0x3F : (dp >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1483 masks[5] |= an <= bias*ap ? 0x3F : (dn >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1485 return sides & masks[0] & masks[1] & masks[2] & masks[3] & masks[4] & masks[5];
1488 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)
1496 int mask, surfacemask = 0;
1497 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1499 bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
1500 tend = firsttriangle + numtris;
1501 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1503 // surface box entirely inside light box, no box cull
1504 if (projectdirection)
1506 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1508 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1509 TriangleNormal(v[0], v[1], v[2], normal);
1510 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1512 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1513 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1514 surfacemask |= mask;
1517 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;
1518 shadowsides[numshadowsides] = mask;
1519 shadowsideslist[numshadowsides++] = t;
1526 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1528 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1529 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]))
1531 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1532 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1533 surfacemask |= mask;
1536 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;
1537 shadowsides[numshadowsides] = mask;
1538 shadowsideslist[numshadowsides++] = t;
1546 // surface box not entirely inside light box, cull each triangle
1547 if (projectdirection)
1549 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1551 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1552 TriangleNormal(v[0], v[1], v[2], normal);
1553 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1554 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1556 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1557 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1558 surfacemask |= mask;
1561 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;
1562 shadowsides[numshadowsides] = mask;
1563 shadowsideslist[numshadowsides++] = t;
1570 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1572 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1573 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1574 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1576 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1577 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1578 surfacemask |= mask;
1581 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;
1582 shadowsides[numshadowsides] = mask;
1583 shadowsideslist[numshadowsides++] = t;
1592 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)
1594 int i, j, outtriangles = 0;
1595 int *outelement3i[6];
1596 if (!numverts || !numsidetris || !r_shadow_compilingrtlight)
1598 outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5];
1599 // make sure shadowelements is big enough for this mesh
1600 if (maxshadowtriangles < outtriangles)
1601 R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1);
1603 // compute the offset and size of the separate index lists for each cubemap side
1605 for (i = 0;i < 6;i++)
1607 outelement3i[i] = shadowelements + outtriangles * 3;
1608 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles;
1609 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i];
1610 outtriangles += sidetotals[i];
1613 // gather up the (sparse) triangles into separate index lists for each cubemap side
1614 for (i = 0;i < numsidetris;i++)
1616 const int *element = elements + sidetris[i] * 3;
1617 for (j = 0;j < 6;j++)
1619 if (sides[i] & (1 << j))
1621 outelement3i[j][0] = element[0];
1622 outelement3i[j][1] = element[1];
1623 outelement3i[j][2] = element[2];
1624 outelement3i[j] += 3;
1629 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, outtriangles, shadowelements);
1632 static void R_Shadow_MakeTextures_MakeCorona(void)
1636 unsigned char pixels[32][32][4];
1637 for (y = 0;y < 32;y++)
1639 dy = (y - 15.5f) * (1.0f / 16.0f);
1640 for (x = 0;x < 32;x++)
1642 dx = (x - 15.5f) * (1.0f / 16.0f);
1643 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1644 a = bound(0, a, 255);
1645 pixels[y][x][0] = a;
1646 pixels[y][x][1] = a;
1647 pixels[y][x][2] = a;
1648 pixels[y][x][3] = 255;
1651 r_shadow_lightcorona = R_LoadTexture2D(r_shadow_texturepool, "lightcorona", 32, 32, &pixels[0][0][0], TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_FORCELINEAR, NULL);
1654 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1656 float dist = sqrt(x*x+y*y+z*z);
1657 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1658 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1659 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1662 static void R_Shadow_MakeTextures(void)
1665 float intensity, dist;
1667 R_FreeTexturePool(&r_shadow_texturepool);
1668 r_shadow_texturepool = R_AllocTexturePool();
1669 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1670 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1671 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1672 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1673 for (x = 0;x <= ATTENTABLESIZE;x++)
1675 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1676 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1677 r_shadow_attentable[x] = bound(0, intensity, 1);
1679 // 1D gradient texture
1680 for (x = 0;x < ATTEN1DSIZE;x++)
1681 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1682 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);
1683 // 2D circle texture
1684 for (y = 0;y < ATTEN2DSIZE;y++)
1685 for (x = 0;x < ATTEN2DSIZE;x++)
1686 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);
1687 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);
1688 // 3D sphere texture
1689 if (r_shadow_texture3d.integer && gl_texture3d)
1691 for (z = 0;z < ATTEN3DSIZE;z++)
1692 for (y = 0;y < ATTEN3DSIZE;y++)
1693 for (x = 0;x < ATTEN3DSIZE;x++)
1694 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));
1695 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);
1698 r_shadow_attenuation3dtexture = NULL;
1701 R_Shadow_MakeTextures_MakeCorona();
1703 // Editor light sprites
1704 r_editlights_sprcursor = Draw_CachePic ("gfx/editlights/cursor");
1705 r_editlights_sprlight = Draw_CachePic ("gfx/editlights/light");
1706 r_editlights_sprnoshadowlight = Draw_CachePic ("gfx/editlights/noshadow");
1707 r_editlights_sprcubemaplight = Draw_CachePic ("gfx/editlights/cubemaplight");
1708 r_editlights_sprcubemapnoshadowlight = Draw_CachePic ("gfx/editlights/cubemapnoshadowlight");
1709 r_editlights_sprselection = Draw_CachePic ("gfx/editlights/selection");
1712 void R_Shadow_ValidateCvars(void)
1714 if (r_shadow_texture3d.integer && !gl_texture3d)
1715 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1716 if (gl_ext_separatestencil.integer && !gl_support_separatestencil)
1717 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
1718 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
1719 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1722 void R_Shadow_RenderMode_Begin(void)
1726 R_Shadow_ValidateCvars();
1728 if (!r_shadow_attenuation2dtexture
1729 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1730 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1731 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1732 R_Shadow_MakeTextures();
1735 R_Mesh_ColorPointer(NULL, 0, 0);
1736 R_Mesh_ResetTextureState();
1737 GL_BlendFunc(GL_ONE, GL_ZERO);
1738 GL_DepthRange(0, 1);
1739 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1741 GL_DepthMask(false);
1742 GL_Color(0, 0, 0, 1);
1743 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1745 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1747 if (gl_ext_separatestencil.integer)
1749 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
1750 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
1752 else if (gl_ext_stenciltwoside.integer)
1754 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
1755 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
1759 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
1760 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
1763 if (r_glsl.integer && gl_support_fragment_shader)
1764 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1765 else if (gl_dot3arb && gl_texturecubemap && r_textureunits.integer >= 2 && gl_combine.integer && gl_stencil)
1766 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_DOT3;
1768 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1771 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
1772 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
1773 r_shadow_drawbuffer = drawbuffer;
1774 r_shadow_readbuffer = readbuffer;
1775 r_shadow_cullface = r_refdef.view.cullface_back;
1778 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
1780 rsurface.rtlight = rtlight;
1783 void R_Shadow_RenderMode_Reset(void)
1786 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE)
1788 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1790 if (gl_support_ext_framebuffer_object)
1792 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);CHECKGLERROR
1794 qglDrawBuffer(r_shadow_drawbuffer);CHECKGLERROR
1795 qglReadBuffer(r_shadow_readbuffer);CHECKGLERROR
1796 R_SetViewport(&r_refdef.view.viewport);
1797 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
1798 R_Mesh_ColorPointer(NULL, 0, 0);
1799 R_Mesh_ResetTextureState();
1800 GL_DepthRange(0, 1);
1802 GL_DepthMask(false);
1803 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1804 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1805 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
1806 qglStencilMask(~0);CHECKGLERROR
1807 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
1808 qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
1809 r_refdef.view.cullface_back = r_shadow_cullface;
1810 GL_CullFace(r_refdef.view.cullface_back);
1811 GL_Color(1, 1, 1, 1);
1812 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
1813 GL_BlendFunc(GL_ONE, GL_ZERO);
1814 R_SetupGenericShader(false);
1815 r_shadow_usingshadowmaprect = false;
1816 r_shadow_usingshadowmapcube = false;
1817 r_shadow_usingshadowmap2d = false;
1821 void R_Shadow_ClearStencil(void)
1824 GL_Clear(GL_STENCIL_BUFFER_BIT);
1825 r_refdef.stats.lights_clears++;
1828 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
1830 r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
1831 if (r_shadow_rendermode == mode)
1834 R_Shadow_RenderMode_Reset();
1835 GL_ColorMask(0, 0, 0, 0);
1836 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1837 R_SetupDepthOrShadowShader();
1838 qglDepthFunc(GL_LESS);CHECKGLERROR
1839 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1840 r_shadow_rendermode = mode;
1845 case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
1846 GL_CullFace(GL_NONE);
1847 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1848 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1850 case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
1851 GL_CullFace(GL_NONE);
1852 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1853 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1855 case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
1856 GL_CullFace(GL_NONE);
1857 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1858 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
1859 qglStencilMask(~0);CHECKGLERROR
1860 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1861 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
1862 qglStencilMask(~0);CHECKGLERROR
1863 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1865 case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
1866 GL_CullFace(GL_NONE);
1867 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1868 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
1869 qglStencilMask(~0);CHECKGLERROR
1870 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1871 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
1872 qglStencilMask(~0);CHECKGLERROR
1873 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1878 static void R_Shadow_MakeVSDCT(void)
1880 // maps to a 2x3 texture rectangle with normalized coordinates
1885 // stores abs(dir.xy), offset.xy/2.5
1886 unsigned char data[4*6] =
1888 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
1889 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
1890 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
1891 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
1892 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
1893 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
1895 r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_ALWAYSPRECACHE | TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, NULL);
1898 void R_Shadow_RenderMode_ShadowMap(int side, qboolean clear, int size)
1903 float nearclip, farclip, bias;
1904 r_viewport_t viewport;
1906 maxsize = r_shadow_shadowmapmaxsize;
1907 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
1909 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
1910 r_shadow_shadowmap_parameters[2] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
1911 r_shadow_shadowmap_parameters[3] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
1912 r_shadow_shadowmapside = side;
1913 r_shadow_shadowmapsize = size;
1914 if (r_shadow_shadowmode == 1)
1916 // complex unrolled cube approach (more flexible)
1917 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
1918 R_Shadow_MakeVSDCT();
1919 if (!r_shadow_shadowmap2dtexture)
1922 int w = maxsize*2, h = gl_support_arb_texture_non_power_of_two ? maxsize*3 : maxsize*4;
1923 r_shadow_shadowmap2dtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "shadowmap", w, h, r_shadow_shadowmapprecision, r_shadow_shadowmapsampler);
1924 qglGenFramebuffersEXT(1, &r_shadow_fbo2d);CHECKGLERROR
1925 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbo2d);CHECKGLERROR
1926 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_shadowmap2dtexture), 0);CHECKGLERROR
1930 R_Shadow_RenderMode_Reset();
1931 if (r_shadow_shadowmap2dtexture)
1933 // render depth into the fbo, do not render color at all
1934 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbo2d);CHECKGLERROR
1935 qglDrawBuffer(GL_NONE);CHECKGLERROR
1936 qglReadBuffer(GL_NONE);CHECKGLERROR
1937 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
1938 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
1940 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
1941 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
1943 R_SetupDepthOrShadowShader();
1947 R_SetupShowDepthShader();
1948 qglClearColor(1,1,1,1);CHECKGLERROR
1950 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
1951 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
1952 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
1953 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
1954 r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
1955 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
1957 else if (r_shadow_shadowmode == 2)
1959 // complex unrolled cube approach (more flexible)
1960 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
1961 R_Shadow_MakeVSDCT();
1962 if (!r_shadow_shadowmaprectangletexture)
1965 r_shadow_shadowmaprectangletexture = R_LoadTextureShadowMapRectangle(r_shadow_texturepool, "shadowmap", maxsize*2, maxsize*3, r_shadow_shadowmapprecision, r_shadow_shadowmapsampler);
1966 qglGenFramebuffersEXT(1, &r_shadow_fborectangle);CHECKGLERROR
1967 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fborectangle);CHECKGLERROR
1968 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, R_GetTexture(r_shadow_shadowmaprectangletexture), 0);CHECKGLERROR
1972 R_Shadow_RenderMode_Reset();
1973 if (r_shadow_shadowmaprectangletexture)
1975 // render depth into the fbo, do not render color at all
1976 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fborectangle);CHECKGLERROR
1977 qglDrawBuffer(GL_NONE);CHECKGLERROR
1978 qglReadBuffer(GL_NONE);CHECKGLERROR
1979 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
1980 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
1982 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
1983 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
1985 R_SetupDepthOrShadowShader();
1989 R_SetupShowDepthShader();
1990 qglClearColor(1,1,1,1);CHECKGLERROR
1992 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
1993 r_shadow_shadowmap_texturescale[0] = 1.0f;
1994 r_shadow_shadowmap_texturescale[1] = 1.0f;
1995 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
1996 r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
1997 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE;
1999 else if (r_shadow_shadowmode == 3)
2001 // simple cube approach
2002 if (!r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod])
2005 r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod] = R_LoadTextureShadowMapCube(r_shadow_texturepool, "shadowmapcube", size, r_shadow_shadowmapprecision, r_shadow_shadowmapsampler);
2006 qglGenFramebuffersEXT(6, r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR
2007 for (i = 0;i < 6;i++)
2009 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbocubeside[r_shadow_shadowmaplod][i]);CHECKGLERROR
2010 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + i, R_GetTexture(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]), 0);CHECKGLERROR
2015 R_Shadow_RenderMode_Reset();
2016 if (r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod])
2018 // render depth into the fbo, do not render color at all
2019 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbocubeside[r_shadow_shadowmaplod][side]);CHECKGLERROR
2020 qglDrawBuffer(GL_NONE);CHECKGLERROR
2021 qglReadBuffer(GL_NONE);CHECKGLERROR
2022 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2023 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
2025 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2026 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2028 R_SetupDepthOrShadowShader();
2032 R_SetupShowDepthShader();
2033 qglClearColor(1,1,1,1);CHECKGLERROR
2035 R_Viewport_InitCubeSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, nearclip, farclip, NULL);
2036 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]);
2037 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureWidth(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]);
2038 r_shadow_shadowmap_parameters[0] = 1.0f;
2039 r_shadow_shadowmap_parameters[1] = 1.0f;
2040 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE;
2043 R_SetViewport(&viewport);
2044 GL_PolygonOffset(0, 0);
2045 if(r_shadow_shadowmode >= 1 && r_shadow_shadowmode <= 2)
2047 static qboolean cullfront[6] = { false, true, false, true, true, false };
2048 if(cullfront[side]) r_refdef.view.cullface_back = r_refdef.view.cullface_front;
2050 GL_CullFace(r_refdef.view.cullface_back);
2051 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2054 qglClearDepth(1);CHECKGLERROR
2057 qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
2061 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
2064 R_Shadow_RenderMode_Reset();
2065 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2068 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2072 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2073 // only draw light where this geometry was already rendered AND the
2074 // stencil is 128 (values other than this mean shadow)
2075 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
2077 r_shadow_rendermode = r_shadow_lightingrendermode;
2078 // do global setup needed for the chosen lighting mode
2079 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2081 R_Mesh_TexBindCubeMap(GL20TU_CUBE, R_GetTexture(rsurface.rtlight->currentcubemap)); // light filter
2082 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2086 if (r_shadow_shadowmode == 1)
2088 r_shadow_usingshadowmap2d = true;
2089 R_Mesh_TexBind(GL20TU_SHADOWMAP2D, R_GetTexture(r_shadow_shadowmap2dtexture));
2092 else if (r_shadow_shadowmode == 2)
2094 r_shadow_usingshadowmaprect = true;
2095 R_Mesh_TexBindRectangle(GL20TU_SHADOWMAPRECT, R_GetTexture(r_shadow_shadowmaprectangletexture));
2098 else if (r_shadow_shadowmode == 3)
2100 r_shadow_usingshadowmapcube = true;
2101 R_Mesh_TexBindCubeMap(GL20TU_SHADOWMAPCUBE, R_GetTexture(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]));
2105 if (r_shadow_shadowmapvsdct && (r_shadow_usingshadowmap2d || r_shadow_usingshadowmaprect))
2107 R_Mesh_TexBindCubeMap(GL20TU_CUBEPROJECTION, R_GetTexture(r_shadow_shadowmapvsdcttexture));
2112 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_VERTEX)
2113 R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
2114 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2118 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
2121 R_Shadow_RenderMode_Reset();
2122 GL_BlendFunc(GL_ONE, GL_ONE);
2123 GL_DepthRange(0, 1);
2124 GL_DepthTest(r_showshadowvolumes.integer < 2);
2125 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
2126 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2127 GL_CullFace(GL_NONE);
2128 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
2131 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
2134 R_Shadow_RenderMode_Reset();
2135 GL_BlendFunc(GL_ONE, GL_ONE);
2136 GL_DepthRange(0, 1);
2137 GL_DepthTest(r_showlighting.integer < 2);
2138 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2141 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2145 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2146 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
2148 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2151 void R_Shadow_RenderMode_End(void)
2154 R_Shadow_RenderMode_Reset();
2155 R_Shadow_RenderMode_ActiveLight(NULL);
2157 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2158 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2161 int bboxedges[12][2] =
2180 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2182 int i, ix1, iy1, ix2, iy2;
2183 float x1, y1, x2, y2;
2185 float vertex[20][3];
2194 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2195 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2196 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2197 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2199 if (!r_shadow_scissor.integer)
2202 // if view is inside the light box, just say yes it's visible
2203 if (BoxesOverlap(r_refdef.view.origin, r_refdef.view.origin, mins, maxs))
2206 x1 = y1 = x2 = y2 = 0;
2208 // transform all corners that are infront of the nearclip plane
2209 VectorNegate(r_refdef.view.frustum[4].normal, plane4f);
2210 plane4f[3] = r_refdef.view.frustum[4].dist;
2212 for (i = 0;i < 8;i++)
2214 Vector4Set(corner[i], (i & 1) ? maxs[0] : mins[0], (i & 2) ? maxs[1] : mins[1], (i & 4) ? maxs[2] : mins[2], 1);
2215 dist[i] = DotProduct4(corner[i], plane4f);
2216 sign[i] = dist[i] > 0;
2219 VectorCopy(corner[i], vertex[numvertices]);
2223 // if some points are behind the nearclip, add clipped edge points to make
2224 // sure that the scissor boundary is complete
2225 if (numvertices > 0 && numvertices < 8)
2227 // add clipped edge points
2228 for (i = 0;i < 12;i++)
2230 j = bboxedges[i][0];
2231 k = bboxedges[i][1];
2232 if (sign[j] != sign[k])
2234 f = dist[j] / (dist[j] - dist[k]);
2235 VectorLerp(corner[j], f, corner[k], vertex[numvertices]);
2241 // if we have no points to check, the light is behind the view plane
2245 // if we have some points to transform, check what screen area is covered
2246 x1 = y1 = x2 = y2 = 0;
2248 //Con_Printf("%i vertices to transform...\n", numvertices);
2249 for (i = 0;i < numvertices;i++)
2251 VectorCopy(vertex[i], v);
2252 R_Viewport_TransformToScreen(&r_refdef.view.viewport, v, v2);
2253 //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]);
2256 if (x1 > v2[0]) x1 = v2[0];
2257 if (x2 < v2[0]) x2 = v2[0];
2258 if (y1 > v2[1]) y1 = v2[1];
2259 if (y2 < v2[1]) y2 = v2[1];
2268 // now convert the scissor rectangle to integer screen coordinates
2269 ix1 = (int)(x1 - 1.0f);
2270 iy1 = vid.height - (int)(y2 - 1.0f);
2271 ix2 = (int)(x2 + 1.0f);
2272 iy2 = vid.height - (int)(y1 + 1.0f);
2273 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
2275 // clamp it to the screen
2276 if (ix1 < r_refdef.view.viewport.x) ix1 = r_refdef.view.viewport.x;
2277 if (iy1 < r_refdef.view.viewport.y) iy1 = r_refdef.view.viewport.y;
2278 if (ix2 > r_refdef.view.viewport.x + r_refdef.view.viewport.width) ix2 = r_refdef.view.viewport.x + r_refdef.view.viewport.width;
2279 if (iy2 > r_refdef.view.viewport.y + r_refdef.view.viewport.height) iy2 = r_refdef.view.viewport.y + r_refdef.view.viewport.height;
2281 // if it is inside out, it's not visible
2282 if (ix2 <= ix1 || iy2 <= iy1)
2285 // the light area is visible, set up the scissor rectangle
2286 r_shadow_lightscissor[0] = ix1;
2287 r_shadow_lightscissor[1] = iy1;
2288 r_shadow_lightscissor[2] = ix2 - ix1;
2289 r_shadow_lightscissor[3] = iy2 - iy1;
2291 r_refdef.stats.lights_scissored++;
2295 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, int numtriangles, const int *element3i, const float *diffusecolor, const float *ambientcolor)
2297 float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
2298 float *normal3f = rsurface.normal3f + 3 * firstvertex;
2299 float *color4f = rsurface.array_color4f + 4 * firstvertex;
2300 float dist, dot, distintensity, shadeintensity, v[3], n[3];
2301 if (r_textureunits.integer >= 3)
2303 if (VectorLength2(diffusecolor) > 0)
2305 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2307 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2308 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2309 if ((dot = DotProduct(n, v)) < 0)
2311 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2312 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
2315 VectorCopy(ambientcolor, color4f);
2316 if (r_refdef.fogenabled)
2319 f = FogPoint_Model(vertex3f);
2320 VectorScale(color4f, f, color4f);
2327 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2329 VectorCopy(ambientcolor, color4f);
2330 if (r_refdef.fogenabled)
2333 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2334 f = FogPoint_Model(vertex3f);
2335 VectorScale(color4f, f, color4f);
2341 else if (r_textureunits.integer >= 2)
2343 if (VectorLength2(diffusecolor) > 0)
2345 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2347 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2348 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2350 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2351 if ((dot = DotProduct(n, v)) < 0)
2353 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2354 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2355 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2356 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2360 color4f[0] = ambientcolor[0] * distintensity;
2361 color4f[1] = ambientcolor[1] * distintensity;
2362 color4f[2] = ambientcolor[2] * distintensity;
2364 if (r_refdef.fogenabled)
2367 f = FogPoint_Model(vertex3f);
2368 VectorScale(color4f, f, color4f);
2372 VectorClear(color4f);
2378 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2380 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2381 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2383 color4f[0] = ambientcolor[0] * distintensity;
2384 color4f[1] = ambientcolor[1] * distintensity;
2385 color4f[2] = ambientcolor[2] * distintensity;
2386 if (r_refdef.fogenabled)
2389 f = FogPoint_Model(vertex3f);
2390 VectorScale(color4f, f, color4f);
2394 VectorClear(color4f);
2401 if (VectorLength2(diffusecolor) > 0)
2403 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2405 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2406 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2408 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2409 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2410 if ((dot = DotProduct(n, v)) < 0)
2412 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2413 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2414 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2415 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2419 color4f[0] = ambientcolor[0] * distintensity;
2420 color4f[1] = ambientcolor[1] * distintensity;
2421 color4f[2] = ambientcolor[2] * distintensity;
2423 if (r_refdef.fogenabled)
2426 f = FogPoint_Model(vertex3f);
2427 VectorScale(color4f, f, color4f);
2431 VectorClear(color4f);
2437 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2439 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2440 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2442 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2443 color4f[0] = ambientcolor[0] * distintensity;
2444 color4f[1] = ambientcolor[1] * distintensity;
2445 color4f[2] = ambientcolor[2] * distintensity;
2446 if (r_refdef.fogenabled)
2449 f = FogPoint_Model(vertex3f);
2450 VectorScale(color4f, f, color4f);
2454 VectorClear(color4f);
2461 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
2463 static void R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
2466 float *out3f = rsurface.array_texcoord3f + 3 * firstvertex;
2467 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
2468 const float *svector3f = rsurface.svector3f + 3 * firstvertex;
2469 const float *tvector3f = rsurface.tvector3f + 3 * firstvertex;
2470 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
2472 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
2474 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
2475 // the cubemap normalizes this for us
2476 out3f[0] = DotProduct(svector3f, lightdir);
2477 out3f[1] = DotProduct(tvector3f, lightdir);
2478 out3f[2] = DotProduct(normal3f, lightdir);
2482 static void R_Shadow_GenTexCoords_Specular_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
2485 float *out3f = rsurface.array_texcoord3f + 3 * firstvertex;
2486 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
2487 const float *svector3f = rsurface.svector3f + 3 * firstvertex;
2488 const float *tvector3f = rsurface.tvector3f + 3 * firstvertex;
2489 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
2490 float lightdir[3], eyedir[3], halfdir[3];
2491 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
2493 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
2494 VectorNormalize(lightdir);
2495 VectorSubtract(rsurface.modelorg, vertex3f, eyedir);
2496 VectorNormalize(eyedir);
2497 VectorAdd(lightdir, eyedir, halfdir);
2498 // the cubemap normalizes this for us
2499 out3f[0] = DotProduct(svector3f, halfdir);
2500 out3f[1] = DotProduct(tvector3f, halfdir);
2501 out3f[2] = DotProduct(normal3f, halfdir);
2505 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)
2507 // used to display how many times a surface is lit for level design purposes
2508 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2511 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)
2513 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2514 R_SetupSurfaceShader(lightcolorbase, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT);
2515 if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND))
2516 R_Mesh_ColorPointer(rsurface.modellightmapcolor4f, rsurface.modellightmapcolor4f_bufferobject, rsurface.modellightmapcolor4f_bufferoffset);
2518 R_Mesh_ColorPointer(NULL, 0, 0);
2519 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
2520 R_Mesh_TexMatrix(1, &rsurface.texture->currentbackgroundtexmatrix);
2521 R_Mesh_TexBind(GL20TU_NORMAL, R_GetTexture(rsurface.texture->currentskinframe->nmap));
2522 R_Mesh_TexBind(GL20TU_COLOR, R_GetTexture(rsurface.texture->basetexture));
2523 R_Mesh_TexBind(GL20TU_GLOSS, R_GetTexture(rsurface.texture->glosstexture));
2524 if (rsurface.texture->backgroundcurrentskinframe)
2526 R_Mesh_TexBind(GL20TU_SECONDARY_NORMAL, R_GetTexture(rsurface.texture->backgroundcurrentskinframe->nmap));
2527 R_Mesh_TexBind(GL20TU_SECONDARY_COLOR, R_GetTexture(rsurface.texture->backgroundbasetexture));
2528 R_Mesh_TexBind(GL20TU_SECONDARY_GLOSS, R_GetTexture(rsurface.texture->backgroundglosstexture));
2529 R_Mesh_TexBind(GL20TU_SECONDARY_GLOW, R_GetTexture(rsurface.texture->backgroundcurrentskinframe->glow));
2531 //R_Mesh_TexBindCubeMap(GL20TU_CUBE, R_GetTexture(rsurface.rtlight->currentcubemap));
2532 R_Mesh_TexBind(GL20TU_FOGMASK, R_GetTexture(r_texture_fogattenuation));
2533 if(rsurface.texture->colormapping)
2535 R_Mesh_TexBind(GL20TU_PANTS, R_GetTexture(rsurface.texture->currentskinframe->pants));
2536 R_Mesh_TexBind(GL20TU_SHIRT, R_GetTexture(rsurface.texture->currentskinframe->shirt));
2538 R_Mesh_TexBind(GL20TU_ATTENUATION, R_GetTexture(r_shadow_attenuationgradienttexture));
2539 R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
2540 R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset);
2541 R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset);
2542 R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset);
2543 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2545 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2547 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2548 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2550 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
2554 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)
2556 // shared final code for all the dot3 layers
2558 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2559 for (renders = 0;renders < 64 && (r > 0 || g > 0 || b > 0);renders++, r--, g--, b--)
2561 GL_Color(bound(0, r, 1), bound(0, g, 1), bound(0, b, 1), 1);
2562 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2566 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)
2569 // colorscale accounts for how much we multiply the brightness
2572 // mult is how many times the final pass of the lighting will be
2573 // performed to get more brightness than otherwise possible.
2575 // Limit mult to 64 for sanity sake.
2577 if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
2579 // 3 3D combine path (Geforce3, Radeon 8500)
2580 memset(&m, 0, sizeof(m));
2581 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2582 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2583 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2584 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2585 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2586 m.tex[1] = R_GetTexture(basetexture);
2587 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
2588 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
2589 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
2590 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
2591 m.texcubemap[2] = R_GetTexture(rsurface.rtlight->currentcubemap);
2592 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2593 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2594 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2595 m.texmatrix[2] = rsurface.entitytolight;
2596 GL_BlendFunc(GL_ONE, GL_ONE);
2598 else if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
2600 // 2 3D combine path (Geforce3, original Radeon)
2601 memset(&m, 0, sizeof(m));
2602 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2603 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2604 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2605 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2606 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2607 m.tex[1] = R_GetTexture(basetexture);
2608 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
2609 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
2610 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
2611 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
2612 GL_BlendFunc(GL_ONE, GL_ONE);
2614 else if (r_textureunits.integer >= 4 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2616 // 4 2D combine path (Geforce3, Radeon 8500)
2617 memset(&m, 0, sizeof(m));
2618 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2619 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2620 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2621 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2622 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2623 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2624 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2625 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2626 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2627 m.texmatrix[1] = rsurface.entitytoattenuationz;
2628 m.tex[2] = R_GetTexture(basetexture);
2629 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
2630 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
2631 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
2632 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
2633 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2635 m.texcubemap[3] = R_GetTexture(rsurface.rtlight->currentcubemap);
2636 m.pointer_texcoord3f[3] = rsurface.vertex3f;
2637 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
2638 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
2639 m.texmatrix[3] = rsurface.entitytolight;
2641 GL_BlendFunc(GL_ONE, GL_ONE);
2643 else if (r_textureunits.integer >= 3 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
2645 // 3 2D combine path (Geforce3, original Radeon)
2646 memset(&m, 0, sizeof(m));
2647 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2648 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2649 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2650 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2651 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2652 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2653 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2654 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2655 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2656 m.texmatrix[1] = rsurface.entitytoattenuationz;
2657 m.tex[2] = R_GetTexture(basetexture);
2658 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
2659 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
2660 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
2661 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
2662 GL_BlendFunc(GL_ONE, GL_ONE);
2666 // 2/2/2 2D combine path (any dot3 card)
2667 memset(&m, 0, sizeof(m));
2668 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2669 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2670 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2671 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2672 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2673 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2674 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2675 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2676 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2677 m.texmatrix[1] = rsurface.entitytoattenuationz;
2678 R_Mesh_TextureState(&m);
2679 GL_ColorMask(0,0,0,1);
2680 GL_BlendFunc(GL_ONE, GL_ZERO);
2681 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2684 memset(&m, 0, sizeof(m));
2685 m.tex[0] = R_GetTexture(basetexture);
2686 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2687 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2688 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2689 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2690 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2692 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2693 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2694 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2695 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2696 m.texmatrix[1] = rsurface.entitytolight;
2698 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2700 // this final code is shared
2701 R_Mesh_TextureState(&m);
2702 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);
2705 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)
2708 // colorscale accounts for how much we multiply the brightness
2711 // mult is how many times the final pass of the lighting will be
2712 // performed to get more brightness than otherwise possible.
2714 // Limit mult to 64 for sanity sake.
2716 // generate normalization cubemap texcoords
2717 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
2718 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
2720 // 3/2 3D combine path (Geforce3, Radeon 8500)
2721 memset(&m, 0, sizeof(m));
2722 m.tex[0] = R_GetTexture(normalmaptexture);
2723 m.texcombinergb[0] = GL_REPLACE;
2724 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2725 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2726 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2727 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2728 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2729 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2730 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2731 m.pointer_texcoord_bufferobject[1] = 0;
2732 m.pointer_texcoord_bufferoffset[1] = 0;
2733 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
2734 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2735 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2736 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2737 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
2738 R_Mesh_TextureState(&m);
2739 GL_ColorMask(0,0,0,1);
2740 GL_BlendFunc(GL_ONE, GL_ZERO);
2741 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2744 memset(&m, 0, sizeof(m));
2745 m.tex[0] = R_GetTexture(basetexture);
2746 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2747 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2748 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2749 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2750 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2752 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2753 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2754 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2755 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2756 m.texmatrix[1] = rsurface.entitytolight;
2758 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2760 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2762 // 1/2/2 3D combine path (original Radeon)
2763 memset(&m, 0, sizeof(m));
2764 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2765 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2766 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2767 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2768 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2769 R_Mesh_TextureState(&m);
2770 GL_ColorMask(0,0,0,1);
2771 GL_BlendFunc(GL_ONE, GL_ZERO);
2772 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2775 memset(&m, 0, sizeof(m));
2776 m.tex[0] = R_GetTexture(normalmaptexture);
2777 m.texcombinergb[0] = GL_REPLACE;
2778 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2779 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2780 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2781 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2782 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2783 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2784 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2785 m.pointer_texcoord_bufferobject[1] = 0;
2786 m.pointer_texcoord_bufferoffset[1] = 0;
2787 R_Mesh_TextureState(&m);
2788 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2789 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2792 memset(&m, 0, sizeof(m));
2793 m.tex[0] = R_GetTexture(basetexture);
2794 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2795 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2796 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2797 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2798 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2800 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2801 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2802 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2803 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2804 m.texmatrix[1] = rsurface.entitytolight;
2806 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2808 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
2810 // 2/2 3D combine path (original Radeon)
2811 memset(&m, 0, sizeof(m));
2812 m.tex[0] = R_GetTexture(normalmaptexture);
2813 m.texcombinergb[0] = GL_REPLACE;
2814 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2815 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2816 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2817 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2818 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2819 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2820 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2821 m.pointer_texcoord_bufferobject[1] = 0;
2822 m.pointer_texcoord_bufferoffset[1] = 0;
2823 R_Mesh_TextureState(&m);
2824 GL_ColorMask(0,0,0,1);
2825 GL_BlendFunc(GL_ONE, GL_ZERO);
2826 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2829 memset(&m, 0, sizeof(m));
2830 m.tex[0] = R_GetTexture(basetexture);
2831 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2832 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2833 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2834 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2835 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2836 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2837 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2838 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2839 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2840 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2842 else if (r_textureunits.integer >= 4)
2844 // 4/2 2D combine path (Geforce3, Radeon 8500)
2845 memset(&m, 0, sizeof(m));
2846 m.tex[0] = R_GetTexture(normalmaptexture);
2847 m.texcombinergb[0] = GL_REPLACE;
2848 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2849 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2850 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2851 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2852 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2853 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2854 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2855 m.pointer_texcoord_bufferobject[1] = 0;
2856 m.pointer_texcoord_bufferoffset[1] = 0;
2857 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2858 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2859 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2860 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2861 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
2862 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
2863 m.pointer_texcoord3f[3] = rsurface.vertex3f;
2864 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
2865 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
2866 m.texmatrix[3] = rsurface.entitytoattenuationz;
2867 R_Mesh_TextureState(&m);
2868 GL_ColorMask(0,0,0,1);
2869 GL_BlendFunc(GL_ONE, GL_ZERO);
2870 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2873 memset(&m, 0, sizeof(m));
2874 m.tex[0] = R_GetTexture(basetexture);
2875 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2876 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2877 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2878 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2879 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2881 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2882 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2883 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2884 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2885 m.texmatrix[1] = rsurface.entitytolight;
2887 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2891 // 2/2/2 2D combine path (any dot3 card)
2892 memset(&m, 0, sizeof(m));
2893 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2894 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2895 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2896 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2897 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2898 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2899 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2900 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2901 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2902 m.texmatrix[1] = rsurface.entitytoattenuationz;
2903 R_Mesh_TextureState(&m);
2904 GL_ColorMask(0,0,0,1);
2905 GL_BlendFunc(GL_ONE, GL_ZERO);
2906 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2909 memset(&m, 0, sizeof(m));
2910 m.tex[0] = R_GetTexture(normalmaptexture);
2911 m.texcombinergb[0] = GL_REPLACE;
2912 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2913 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2914 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2915 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2916 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2917 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2918 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2919 m.pointer_texcoord_bufferobject[1] = 0;
2920 m.pointer_texcoord_bufferoffset[1] = 0;
2921 R_Mesh_TextureState(&m);
2922 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2923 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2926 memset(&m, 0, sizeof(m));
2927 m.tex[0] = R_GetTexture(basetexture);
2928 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2929 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2930 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2931 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2932 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2934 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2935 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2936 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2937 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2938 m.texmatrix[1] = rsurface.entitytolight;
2940 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2942 // this final code is shared
2943 R_Mesh_TextureState(&m);
2944 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);
2947 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)
2949 float glossexponent;
2951 // FIXME: detect blendsquare!
2952 //if (!gl_support_blendsquare)
2955 // generate normalization cubemap texcoords
2956 R_Shadow_GenTexCoords_Specular_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
2957 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2959 // 2/0/0/1/2 3D combine blendsquare path
2960 memset(&m, 0, sizeof(m));
2961 m.tex[0] = R_GetTexture(normalmaptexture);
2962 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2963 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2964 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2965 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2966 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2967 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2968 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2969 m.pointer_texcoord_bufferobject[1] = 0;
2970 m.pointer_texcoord_bufferoffset[1] = 0;
2971 R_Mesh_TextureState(&m);
2972 GL_ColorMask(0,0,0,1);
2973 // this squares the result
2974 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2975 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2977 // second and third pass
2978 R_Mesh_ResetTextureState();
2979 // square alpha in framebuffer a few times to make it shiny
2980 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2981 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2982 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2985 memset(&m, 0, sizeof(m));
2986 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2987 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2988 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2989 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2990 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2991 R_Mesh_TextureState(&m);
2992 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2993 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2996 memset(&m, 0, sizeof(m));
2997 m.tex[0] = R_GetTexture(glosstexture);
2998 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2999 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3000 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3001 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3002 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
3004 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
3005 m.pointer_texcoord3f[1] = rsurface.vertex3f;
3006 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
3007 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
3008 m.texmatrix[1] = rsurface.entitytolight;
3010 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
3012 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
3014 // 2/0/0/2 3D combine blendsquare path
3015 memset(&m, 0, sizeof(m));
3016 m.tex[0] = R_GetTexture(normalmaptexture);
3017 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3018 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3019 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3020 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3021 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
3022 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
3023 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
3024 m.pointer_texcoord_bufferobject[1] = 0;
3025 m.pointer_texcoord_bufferoffset[1] = 0;
3026 R_Mesh_TextureState(&m);
3027 GL_ColorMask(0,0,0,1);
3028 // this squares the result
3029 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
3030 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3032 // second and third pass
3033 R_Mesh_ResetTextureState();
3034 // square alpha in framebuffer a few times to make it shiny
3035 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
3036 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
3037 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3040 memset(&m, 0, sizeof(m));
3041 m.tex[0] = R_GetTexture(glosstexture);
3042 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3043 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3044 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3045 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3046 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
3047 m.pointer_texcoord3f[1] = rsurface.vertex3f;
3048 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
3049 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
3050 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
3051 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
3055 // 2/0/0/2/2 2D combine blendsquare path
3056 memset(&m, 0, sizeof(m));
3057 m.tex[0] = R_GetTexture(normalmaptexture);
3058 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3059 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3060 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3061 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3062 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
3063 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
3064 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
3065 m.pointer_texcoord_bufferobject[1] = 0;
3066 m.pointer_texcoord_bufferoffset[1] = 0;
3067 R_Mesh_TextureState(&m);
3068 GL_ColorMask(0,0,0,1);
3069 // this squares the result
3070 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
3071 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3073 // second and third pass
3074 R_Mesh_ResetTextureState();
3075 // square alpha in framebuffer a few times to make it shiny
3076 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
3077 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
3078 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3081 memset(&m, 0, sizeof(m));
3082 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
3083 m.pointer_texcoord3f[0] = rsurface.vertex3f;
3084 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
3085 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
3086 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
3087 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
3088 m.pointer_texcoord3f[1] = rsurface.vertex3f;
3089 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
3090 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
3091 m.texmatrix[1] = rsurface.entitytoattenuationz;
3092 R_Mesh_TextureState(&m);
3093 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
3094 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3097 memset(&m, 0, sizeof(m));
3098 m.tex[0] = R_GetTexture(glosstexture);
3099 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3100 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3101 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3102 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3103 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
3105 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
3106 m.pointer_texcoord3f[1] = rsurface.vertex3f;
3107 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
3108 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
3109 m.texmatrix[1] = rsurface.entitytolight;
3111 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
3113 // this final code is shared
3114 R_Mesh_TextureState(&m);
3115 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);
3118 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)
3120 // ARB path (any Geforce, any Radeon)
3121 qboolean doambient = ambientscale > 0;
3122 qboolean dodiffuse = diffusescale > 0;
3123 qboolean dospecular = specularscale > 0;
3124 if (!doambient && !dodiffuse && !dospecular)
3126 R_Mesh_ColorPointer(NULL, 0, 0);
3128 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, basetexture, ambientscale * r_refdef.view.colorscale);
3130 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, basetexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
3134 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorpants, pantstexture, ambientscale * r_refdef.view.colorscale);
3136 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorpants, pantstexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
3141 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorshirt, shirttexture, ambientscale * r_refdef.view.colorscale);
3143 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorshirt, shirttexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
3146 R_Shadow_RenderLighting_Light_Dot3_SpecularPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, glosstexture, normalmaptexture, specularscale * r_refdef.view.colorscale);
3149 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
3156 int newnumtriangles;
3160 int maxtriangles = 4096;
3161 int newelements[4096*3];
3162 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, numtriangles, element3i, diffusecolor2, ambientcolor2);
3163 for (renders = 0;renders < 64;renders++)
3168 newnumtriangles = 0;
3170 // due to low fillrate on the cards this vertex lighting path is
3171 // designed for, we manually cull all triangles that do not
3172 // contain a lit vertex
3173 // this builds batches of triangles from multiple surfaces and
3174 // renders them at once
3175 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
3177 if (VectorLength2(rsurface.array_color4f + e[0] * 4) + VectorLength2(rsurface.array_color4f + e[1] * 4) + VectorLength2(rsurface.array_color4f + e[2] * 4) >= 0.01)
3179 if (newnumtriangles)
3181 newfirstvertex = min(newfirstvertex, e[0]);
3182 newlastvertex = max(newlastvertex, e[0]);
3186 newfirstvertex = e[0];
3187 newlastvertex = e[0];
3189 newfirstvertex = min(newfirstvertex, e[1]);
3190 newlastvertex = max(newlastvertex, e[1]);
3191 newfirstvertex = min(newfirstvertex, e[2]);
3192 newlastvertex = max(newlastvertex, e[2]);
3198 if (newnumtriangles >= maxtriangles)
3200 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
3201 newnumtriangles = 0;
3207 if (newnumtriangles >= 1)
3209 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
3212 // if we couldn't find any lit triangles, exit early
3215 // now reduce the intensity for the next overbright pass
3216 // we have to clamp to 0 here incase the drivers have improper
3217 // handling of negative colors
3218 // (some old drivers even have improper handling of >1 color)
3220 for (i = 0, c = rsurface.array_color4f + 4 * firstvertex;i < numvertices;i++, c += 4)
3222 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
3224 c[0] = max(0, c[0] - 1);
3225 c[1] = max(0, c[1] - 1);
3226 c[2] = max(0, c[2] - 1);
3238 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)
3240 // OpenGL 1.1 path (anything)
3241 float ambientcolorbase[3], diffusecolorbase[3];
3242 float ambientcolorpants[3], diffusecolorpants[3];
3243 float ambientcolorshirt[3], diffusecolorshirt[3];
3245 VectorScale(lightcolorbase, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorbase);
3246 VectorScale(lightcolorbase, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorbase);
3247 VectorScale(lightcolorpants, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorpants);
3248 VectorScale(lightcolorpants, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorpants);
3249 VectorScale(lightcolorshirt, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorshirt);
3250 VectorScale(lightcolorshirt, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorshirt);
3251 memset(&m, 0, sizeof(m));
3252 m.tex[0] = R_GetTexture(basetexture);
3253 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3254 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3255 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3256 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3257 if (r_textureunits.integer >= 2)
3260 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
3261 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
3262 m.pointer_texcoord3f[1] = rsurface.vertex3f;
3263 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
3264 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
3265 if (r_textureunits.integer >= 3)
3267 // Voodoo4 or Kyro (or Geforce3/Radeon with gl_combine off)
3268 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
3269 m.texmatrix[2] = rsurface.entitytoattenuationz;
3270 m.pointer_texcoord3f[2] = rsurface.vertex3f;
3271 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
3272 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
3275 R_Mesh_TextureState(&m);
3276 //R_Mesh_TexBind(0, R_GetTexture(basetexture));
3277 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorbase, ambientcolorbase);
3280 R_Mesh_TexBind(0, R_GetTexture(pantstexture));
3281 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorpants, ambientcolorpants);
3285 R_Mesh_TexBind(0, R_GetTexture(shirttexture));
3286 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorshirt, ambientcolorshirt);
3290 extern cvar_t gl_lightmaps;
3291 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)
3293 float ambientscale, diffusescale, specularscale;
3294 vec3_t lightcolorbase, lightcolorpants, lightcolorshirt;
3296 // calculate colors to render this texture with
3297 lightcolorbase[0] = rsurface.rtlight->currentcolor[0] * rsurface.texture->dlightcolor[0];
3298 lightcolorbase[1] = rsurface.rtlight->currentcolor[1] * rsurface.texture->dlightcolor[1];
3299 lightcolorbase[2] = rsurface.rtlight->currentcolor[2] * rsurface.texture->dlightcolor[2];
3300 ambientscale = rsurface.rtlight->ambientscale;
3301 diffusescale = rsurface.rtlight->diffusescale;
3302 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
3303 if (!r_shadow_usenormalmap.integer)
3305 ambientscale += 1.0f * diffusescale;
3309 if ((ambientscale + diffusescale) * VectorLength2(lightcolorbase) + specularscale * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
3311 RSurf_SetupDepthAndCulling();
3312 nmap = rsurface.texture->currentskinframe->nmap;
3313 if (gl_lightmaps.integer)
3314 nmap = r_texture_blanknormalmap;
3315 if (rsurface.texture->colormapping && !gl_lightmaps.integer)
3317 qboolean dopants = rsurface.texture->currentskinframe->pants != NULL && VectorLength2(rsurface.colormap_pantscolor) >= (1.0f / 1048576.0f);
3318 qboolean doshirt = rsurface.texture->currentskinframe->shirt != NULL && VectorLength2(rsurface.colormap_shirtcolor) >= (1.0f / 1048576.0f);
3321 lightcolorpants[0] = lightcolorbase[0] * rsurface.colormap_pantscolor[0];
3322 lightcolorpants[1] = lightcolorbase[1] * rsurface.colormap_pantscolor[1];
3323 lightcolorpants[2] = lightcolorbase[2] * rsurface.colormap_pantscolor[2];
3326 VectorClear(lightcolorpants);
3329 lightcolorshirt[0] = lightcolorbase[0] * rsurface.colormap_shirtcolor[0];
3330 lightcolorshirt[1] = lightcolorbase[1] * rsurface.colormap_shirtcolor[1];
3331 lightcolorshirt[2] = lightcolorbase[2] * rsurface.colormap_shirtcolor[2];
3334 VectorClear(lightcolorshirt);
3335 switch (r_shadow_rendermode)
3337 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
3338 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
3339 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);
3341 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
3342 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);
3344 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
3345 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);
3347 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3348 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);
3351 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
3357 switch (r_shadow_rendermode)
3359 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
3360 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
3361 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);
3363 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
3364 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);
3366 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
3367 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);
3369 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3370 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);
3373 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
3379 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)
3381 matrix4x4_t tempmatrix = *matrix;
3382 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
3384 // if this light has been compiled before, free the associated data
3385 R_RTLight_Uncompile(rtlight);
3387 // clear it completely to avoid any lingering data
3388 memset(rtlight, 0, sizeof(*rtlight));
3390 // copy the properties
3391 rtlight->matrix_lighttoworld = tempmatrix;
3392 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
3393 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
3394 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
3395 VectorCopy(color, rtlight->color);
3396 rtlight->cubemapname[0] = 0;
3397 if (cubemapname && cubemapname[0])
3398 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
3399 rtlight->shadow = shadow;
3400 rtlight->corona = corona;
3401 rtlight->style = style;
3402 rtlight->isstatic = isstatic;
3403 rtlight->coronasizescale = coronasizescale;
3404 rtlight->ambientscale = ambientscale;
3405 rtlight->diffusescale = diffusescale;
3406 rtlight->specularscale = specularscale;
3407 rtlight->flags = flags;
3409 // compute derived data
3410 //rtlight->cullradius = rtlight->radius;
3411 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
3412 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3413 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3414 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3415 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3416 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3417 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3420 // compiles rtlight geometry
3421 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
3422 void R_RTLight_Compile(rtlight_t *rtlight)
3425 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
3426 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
3427 entity_render_t *ent = r_refdef.scene.worldentity;
3428 dp_model_t *model = r_refdef.scene.worldmodel;
3429 unsigned char *data;
3432 // compile the light
3433 rtlight->compiled = true;
3434 rtlight->shadowmode = rtlight->shadow ? r_shadow_shadowmode : -1;
3435 rtlight->static_numleafs = 0;
3436 rtlight->static_numleafpvsbytes = 0;
3437 rtlight->static_leaflist = NULL;
3438 rtlight->static_leafpvs = NULL;
3439 rtlight->static_numsurfaces = 0;
3440 rtlight->static_surfacelist = NULL;
3441 rtlight->static_shadowmap_receivers = 0x3F;
3442 rtlight->static_shadowmap_casters = 0x3F;
3443 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3444 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3445 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3446 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3447 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3448 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3450 if (model && model->GetLightInfo)
3452 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
3453 r_shadow_compilingrtlight = rtlight;
3454 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);
3455 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);
3456 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
3457 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
3458 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3459 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
3460 rtlight->static_numsurfaces = numsurfaces;
3461 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
3462 rtlight->static_numleafs = numleafs;
3463 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
3464 rtlight->static_numleafpvsbytes = numleafpvsbytes;
3465 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
3466 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
3467 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
3468 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
3469 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3470 if (rtlight->static_numsurfaces)
3471 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3472 if (rtlight->static_numleafs)
3473 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3474 if (rtlight->static_numleafpvsbytes)
3475 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3476 if (rtlight->static_numshadowtrispvsbytes)
3477 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3478 if (rtlight->static_numlighttrispvsbytes)
3479 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3480 if (rtlight->shadowmode <= 0)
3482 if (model->CompileShadowVolume && rtlight->shadow)
3483 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3487 if (model->CompileShadowMap && rtlight->shadow)
3488 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3490 // now we're done compiling the rtlight
3491 r_shadow_compilingrtlight = NULL;
3495 // use smallest available cullradius - box radius or light radius
3496 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3497 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3499 shadowzpasstris = 0;
3500 if (rtlight->static_meshchain_shadow_zpass)
3501 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
3502 shadowzpasstris += mesh->numtriangles;
3504 shadowzfailtris = 0;
3505 if (rtlight->static_meshchain_shadow_zfail)
3506 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
3507 shadowzfailtris += mesh->numtriangles;
3510 if (rtlight->static_numlighttrispvsbytes)
3511 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3512 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3516 if (rtlight->static_numlighttrispvsbytes)
3517 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3518 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3521 if (developer.integer >= 10)
3522 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);
3525 void R_RTLight_Uncompile(rtlight_t *rtlight)
3527 if (rtlight->compiled)
3529 if (rtlight->static_meshchain_shadow_zpass)
3530 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
3531 rtlight->static_meshchain_shadow_zpass = NULL;
3532 if (rtlight->static_meshchain_shadow_zfail)
3533 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
3534 rtlight->static_meshchain_shadow_zfail = NULL;
3535 if (rtlight->static_meshchain_shadow_shadowmap)
3536 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
3537 rtlight->static_meshchain_shadow_shadowmap = NULL;
3538 // these allocations are grouped
3539 if (rtlight->static_surfacelist)
3540 Mem_Free(rtlight->static_surfacelist);
3541 rtlight->static_numleafs = 0;
3542 rtlight->static_numleafpvsbytes = 0;
3543 rtlight->static_leaflist = NULL;
3544 rtlight->static_leafpvs = NULL;
3545 rtlight->static_numsurfaces = 0;
3546 rtlight->static_surfacelist = NULL;
3547 rtlight->static_numshadowtrispvsbytes = 0;
3548 rtlight->static_shadowtrispvs = NULL;
3549 rtlight->static_numlighttrispvsbytes = 0;
3550 rtlight->static_lighttrispvs = NULL;
3551 rtlight->compiled = false;
3555 void R_Shadow_UncompileWorldLights(void)
3559 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3560 for (lightindex = 0;lightindex < range;lightindex++)
3562 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3565 R_RTLight_Uncompile(&light->rtlight);
3569 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3573 // reset the count of frustum planes
3574 // see rsurface.rtlight_frustumplanes definition for how much this array
3576 rsurface.rtlight_numfrustumplanes = 0;
3578 // haven't implemented a culling path for ortho rendering
3579 if (!r_refdef.view.useperspective)
3581 // check if the light is on screen and copy the 4 planes if it is
3582 for (i = 0;i < 4;i++)
3583 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3586 for (i = 0;i < 4;i++)
3587 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_refdef.view.frustum[i];
3592 // generate a deformed frustum that includes the light origin, this is
3593 // used to cull shadow casting surfaces that can not possibly cast a
3594 // shadow onto the visible light-receiving surfaces, which can be a
3597 // if the light origin is onscreen the result will be 4 planes exactly
3598 // if the light origin is offscreen on only one axis the result will
3599 // be exactly 5 planes (split-side case)
3600 // if the light origin is offscreen on two axes the result will be
3601 // exactly 4 planes (stretched corner case)
3602 for (i = 0;i < 4;i++)
3604 // quickly reject standard frustum planes that put the light
3605 // origin outside the frustum
3606 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3609 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_refdef.view.frustum[i];
3611 // if all the standard frustum planes were accepted, the light is onscreen
3612 // otherwise we need to generate some more planes below...
3613 if (rsurface.rtlight_numfrustumplanes < 4)
3615 // at least one of the stock frustum planes failed, so we need to
3616 // create one or two custom planes to enclose the light origin
3617 for (i = 0;i < 4;i++)
3619 // create a plane using the view origin and light origin, and a
3620 // single point from the frustum corner set
3621 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3622 VectorNormalize(plane.normal);
3623 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3624 // see if this plane is backwards and flip it if so
3625 for (j = 0;j < 4;j++)
3626 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3630 VectorNegate(plane.normal, plane.normal);
3632 // flipped plane, test again to see if it is now valid
3633 for (j = 0;j < 4;j++)
3634 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3636 // if the plane is still not valid, then it is dividing the
3637 // frustum and has to be rejected
3641 // we have created a valid plane, compute extra info
3642 PlaneClassify(&plane);
3644 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3646 // if we've found 5 frustum planes then we have constructed a
3647 // proper split-side case and do not need to keep searching for
3648 // planes to enclose the light origin
3649 if (rsurface.rtlight_numfrustumplanes == 5)
3657 for (i = 0;i < rsurface.rtlight_numfrustumplanes;i++)
3659 plane = rsurface.rtlight_frustumplanes[i];
3660 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));
3665 // now add the light-space box planes if the light box is rotated, as any
3666 // caster outside the oriented light box is irrelevant (even if it passed
3667 // the worldspace light box, which is axial)
3668 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3670 for (i = 0;i < 6;i++)
3674 v[i >> 1] = (i & 1) ? -1 : 1;
3675 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3676 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3677 plane.dist = VectorNormalizeLength(plane.normal);
3678 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3679 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3685 // add the world-space reduced box planes
3686 for (i = 0;i < 6;i++)
3688 VectorClear(plane.normal);
3689 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3690 plane.dist = (i & 1) ? -rsurface.rtlight_cullmaxs[i >> 1] : rsurface.rtlight_cullmins[i >> 1];
3691 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3700 // reduce all plane distances to tightly fit the rtlight cull box, which
3702 VectorSet(points[0], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
3703 VectorSet(points[1], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
3704 VectorSet(points[2], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
3705 VectorSet(points[3], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
3706 VectorSet(points[4], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
3707 VectorSet(points[5], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
3708 VectorSet(points[6], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
3709 VectorSet(points[7], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
3710 oldnum = rsurface.rtlight_numfrustumplanes;
3711 rsurface.rtlight_numfrustumplanes = 0;
3712 for (j = 0;j < oldnum;j++)
3714 // find the nearest point on the box to this plane
3715 bestdist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[0]);
3716 for (i = 1;i < 8;i++)
3718 dist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[i]);
3719 if (bestdist > dist)
3722 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);
3723 // if the nearest point is near or behind the plane, we want this
3724 // plane, otherwise the plane is useless as it won't cull anything
3725 if (rsurface.rtlight_frustumplanes[j].dist < bestdist + 0.03125)
3727 PlaneClassify(&rsurface.rtlight_frustumplanes[j]);
3728 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = rsurface.rtlight_frustumplanes[j];
3735 void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
3739 RSurf_ActiveWorldEntity();
3741 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3744 GL_CullFace(GL_NONE);
3745 mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3746 for (;mesh;mesh = mesh->next)
3748 if (!mesh->sidetotals[r_shadow_shadowmapside])
3750 r_refdef.stats.lights_shadowtriangles += mesh->sidetotals[r_shadow_shadowmapside];
3751 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
3752 R_Mesh_Draw(0, mesh->numverts, mesh->sideoffsets[r_shadow_shadowmapside], mesh->sidetotals[r_shadow_shadowmapside], mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3756 else if (r_refdef.scene.worldentity->model)
3757 r_refdef.scene.worldmodel->DrawShadowMap(r_shadow_shadowmapside, r_refdef.scene.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, surfacesides, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs);
3759 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3762 void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3767 int surfacelistindex;
3768 msurface_t *surface;
3770 RSurf_ActiveWorldEntity();
3772 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3775 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
3776 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
3777 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
3778 for (;mesh;mesh = mesh->next)
3780 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
3781 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
3782 GL_LockArrays(0, mesh->numverts);
3783 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
3785 // increment stencil if frontface is infront of depthbuffer
3786 GL_CullFace(r_refdef.view.cullface_back);
3787 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
3788 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3789 // decrement stencil if backface is infront of depthbuffer
3790 GL_CullFace(r_refdef.view.cullface_front);
3791 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
3793 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
3795 // decrement stencil if backface is behind depthbuffer
3796 GL_CullFace(r_refdef.view.cullface_front);
3797 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
3798 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3799 // increment stencil if frontface is behind depthbuffer
3800 GL_CullFace(r_refdef.view.cullface_back);
3801 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
3803 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3804 GL_LockArrays(0, 0);
3808 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh && r_shadow_culltriangles.integer)
3810 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
3811 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
3813 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
3814 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
3815 if (CHECKPVSBIT(trispvs, t))
3816 shadowmarklist[numshadowmark++] = t;
3818 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);
3820 else if (numsurfaces)
3821 r_refdef.scene.worldmodel->DrawShadowVolume(r_refdef.scene.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs);
3823 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3826 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3828 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3829 vec_t relativeshadowradius;
3830 RSurf_ActiveModelEntity(ent, false, false);
3831 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3832 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3833 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3834 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3835 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3836 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3837 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3838 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3839 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D)
3841 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
3844 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3845 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3848 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3850 // set up properties for rendering light onto this entity
3851 RSurf_ActiveModelEntity(ent, true, true);
3852 GL_AlphaTest(false);
3853 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3854 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3855 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3856 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3857 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
3858 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
3861 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3863 if (!r_refdef.scene.worldmodel->DrawLight)
3866 // set up properties for rendering light onto this entity
3867 RSurf_ActiveWorldEntity();
3868 GL_AlphaTest(false);
3869 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3870 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3871 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3872 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3873 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
3874 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
3876 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, trispvs);
3878 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3881 void R_Shadow_DrawEntityLight(entity_render_t *ent)
3883 dp_model_t *model = ent->model;
3884 if (!model->DrawLight)
3887 R_Shadow_SetupEntityLight(ent);
3889 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3891 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3894 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
3898 int numleafs, numsurfaces;
3899 int *leaflist, *surfacelist;
3900 unsigned char *leafpvs, *shadowtrispvs, *lighttrispvs, *surfacesides;
3901 int numlightentities;
3902 int numlightentities_noselfshadow;
3903 int numshadowentities;
3904 int numshadowentities_noselfshadow;
3905 static entity_render_t *lightentities[MAX_EDICTS];
3906 static entity_render_t *shadowentities[MAX_EDICTS];
3907 static unsigned char entitysides[MAX_EDICTS];
3908 int lightentities_noselfshadow;
3909 int shadowentities_noselfshadow;
3910 vec3_t nearestpoint;
3912 qboolean castshadows;
3915 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3916 // skip lights that are basically invisible (color 0 0 0)
3917 if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
3920 // loading is done before visibility checks because loading should happen
3921 // all at once at the start of a level, not when it stalls gameplay.
3922 // (especially important to benchmarks)
3924 if (rtlight->isstatic && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
3926 if (rtlight->compiled)
3927 R_RTLight_Uncompile(rtlight);
3928 R_RTLight_Compile(rtlight);
3932 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
3934 // look up the light style value at this time
3935 f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3936 VectorScale(rtlight->color, f, rtlight->currentcolor);
3938 if (rtlight->selected)
3940 f = 2 + sin(realtime * M_PI * 4.0);
3941 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3945 // if lightstyle is currently off, don't draw the light
3946 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3949 // if the light box is offscreen, skip it
3950 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3953 VectorCopy(rtlight->cullmins, rsurface.rtlight_cullmins);
3954 VectorCopy(rtlight->cullmaxs, rsurface.rtlight_cullmaxs);
3956 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3958 // compiled light, world available and can receive realtime lighting
3959 // retrieve leaf information
3960 numleafs = rtlight->static_numleafs;
3961 leaflist = rtlight->static_leaflist;
3962 leafpvs = rtlight->static_leafpvs;
3963 numsurfaces = rtlight->static_numsurfaces;
3964 surfacelist = rtlight->static_surfacelist;
3965 surfacesides = NULL;
3966 shadowtrispvs = rtlight->static_shadowtrispvs;
3967 lighttrispvs = rtlight->static_lighttrispvs;
3969 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3971 // dynamic light, world available and can receive realtime lighting
3972 // calculate lit surfaces and leafs
3973 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);
3974 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);
3975 leaflist = r_shadow_buffer_leaflist;
3976 leafpvs = r_shadow_buffer_leafpvs;
3977 surfacelist = r_shadow_buffer_surfacelist;
3978 surfacesides = r_shadow_buffer_surfacesides;
3979 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3980 lighttrispvs = r_shadow_buffer_lighttrispvs;
3981 // if the reduced leaf bounds are offscreen, skip it
3982 if (R_CullBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
3993 surfacesides = NULL;
3994 shadowtrispvs = NULL;
3995 lighttrispvs = NULL;
3997 // check if light is illuminating any visible leafs
4000 for (i = 0;i < numleafs;i++)
4001 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
4006 // set up a scissor rectangle for this light
4007 if (R_Shadow_ScissorForBBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
4010 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
4012 // make a list of lit entities and shadow casting entities
4013 numlightentities = 0;
4014 numlightentities_noselfshadow = 0;
4015 lightentities_noselfshadow = sizeof(lightentities)/sizeof(lightentities[0]) - 1;
4016 numshadowentities = 0;
4017 numshadowentities_noselfshadow = 0;
4018 shadowentities_noselfshadow = sizeof(shadowentities)/sizeof(shadowentities[0]) - 1;
4020 // add dynamic entities that are lit by the light
4021 if (r_drawentities.integer)
4023 for (i = 0;i < r_refdef.scene.numentities;i++)
4026 entity_render_t *ent = r_refdef.scene.entities[i];
4028 if (!BoxesOverlap(ent->mins, ent->maxs, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
4030 // skip the object entirely if it is not within the valid
4031 // shadow-casting region (which includes the lit region)
4032 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rsurface.rtlight_numfrustumplanes, rsurface.rtlight_frustumplanes))
4034 if (!(model = ent->model))
4036 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
4038 // this entity wants to receive light, is visible, and is
4039 // inside the light box
4040 // TODO: check if the surfaces in the model can receive light
4041 // so now check if it's in a leaf seen by the light
4042 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))
4044 if (ent->flags & RENDER_NOSELFSHADOW)
4045 lightentities[lightentities_noselfshadow - numlightentities_noselfshadow++] = ent;
4047 lightentities[numlightentities++] = ent;
4048 // since it is lit, it probably also casts a shadow...
4049 // about the VectorDistance2 - light emitting entities should not cast their own shadow
4050 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
4051 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
4053 // note: exterior models without the RENDER_NOSELFSHADOW
4054 // flag still create a RENDER_NOSELFSHADOW shadow but
4055 // are lit normally, this means that they are
4056 // self-shadowing but do not shadow other
4057 // RENDER_NOSELFSHADOW entities such as the gun
4058 // (very weird, but keeps the player shadow off the gun)
4059 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
4060 shadowentities[shadowentities_noselfshadow - numshadowentities_noselfshadow++] = ent;
4062 shadowentities[numshadowentities++] = ent;
4065 else if (ent->flags & RENDER_SHADOW)
4067 // this entity is not receiving light, but may still need to
4069 // TODO: check if the surfaces in the model can cast shadow
4070 // now check if it is in a leaf seen by the light
4071 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))
4073 // about the VectorDistance2 - light emitting entities should not cast their own shadow
4074 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
4075 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
4077 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
4078 shadowentities[shadowentities_noselfshadow - numshadowentities_noselfshadow++] = ent;
4080 shadowentities[numshadowentities++] = ent;
4086 // return if there's nothing at all to light
4087 if (!numlightentities && !numsurfaces)
4090 // don't let sound skip if going slow
4091 if (r_refdef.scene.extraupdate)
4094 // make this the active rtlight for rendering purposes
4095 R_Shadow_RenderMode_ActiveLight(rtlight);
4096 // count this light in the r_speeds
4097 r_refdef.stats.lights++;
4099 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
4101 // optionally draw visible shape of the shadow volumes
4102 // for performance analysis by level designers
4103 R_Shadow_RenderMode_VisibleShadowVolumes();
4105 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
4106 for (i = 0;i < numshadowentities;i++)
4107 R_Shadow_DrawEntityShadow(shadowentities[i]);
4108 for (i = 0;i < numshadowentities_noselfshadow;i++)
4109 R_Shadow_DrawEntityShadow(shadowentities[shadowentities_noselfshadow - i]);
4112 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
4114 // optionally draw the illuminated areas
4115 // for performance analysis by level designers
4116 R_Shadow_RenderMode_VisibleLighting(false, false);
4118 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4119 for (i = 0;i < numlightentities;i++)
4120 R_Shadow_DrawEntityLight(lightentities[i]);
4121 for (i = 0;i < numlightentities_noselfshadow;i++)
4122 R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
4125 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
4127 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
4128 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
4129 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
4130 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
4131 lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
4132 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapping_maxsize.integer);
4134 if (castshadows && r_shadow_shadowmode >= 1 && r_shadow_shadowmode <= 3 && r_glsl.integer && gl_support_fragment_shader)
4140 int receivermask = 0;
4141 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
4142 Matrix4x4_Abs(&radiustolight);
4144 r_shadow_shadowmaplod = 0;
4145 for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
4146 if ((r_shadow_shadowmapping_maxsize.integer >> i) > lodlinear)
4147 r_shadow_shadowmaplod = i;
4149 size = r_shadow_shadowmode == 3 ? r_shadow_shadowmapping_maxsize.integer >> r_shadow_shadowmaplod : lodlinear;
4150 size = bound(1, size, 2048);
4151 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
4155 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
4157 castermask = rtlight->static_shadowmap_casters;
4158 receivermask = rtlight->static_shadowmap_receivers;
4162 for(i = 0;i < numsurfaces;i++)
4164 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
4165 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4166 castermask |= surfacesides[i];
4167 receivermask |= surfacesides[i];
4171 if (receivermask < 0x3F)
4173 for (i = 0;i < numlightentities;i++)
4174 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4175 if (receivermask < 0x3F)
4176 for(i = 0; i < numlightentities_noselfshadow;i++)
4177 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[lightentities_noselfshadow - i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4180 receivermask &= R_Shadow_CullFrustumSides(rtlight, size, r_shadow_shadowmapborder);
4184 for (i = 0;i < numshadowentities;i++)
4185 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
4186 for (i = 0;i < numshadowentities_noselfshadow;i++)
4187 castermask |= (entitysides[shadowentities_noselfshadow - i] = R_Shadow_CalcEntitySideMask(shadowentities[shadowentities_noselfshadow - i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
4190 //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
4192 // render shadow casters into 6 sided depth texture
4193 for (side = 0;side < 6;side++) if (receivermask & (1 << side))
4195 R_Shadow_RenderMode_ShadowMap(side, true, size);
4196 if (! (castermask & (1 << side))) continue;
4198 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
4199 for (i = 0;i < numshadowentities;i++) if (entitysides[i] & (1 << side))
4200 R_Shadow_DrawEntityShadow(shadowentities[i]);
4203 if (numlightentities_noselfshadow)
4205 // render lighting using the depth texture as shadowmap
4206 // draw lighting in the unmasked areas
4207 R_Shadow_RenderMode_Lighting(false, false, true);
4208 for (i = 0;i < numlightentities_noselfshadow;i++)
4209 R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
4212 // render shadow casters into 6 sided depth texture
4213 if (numshadowentities_noselfshadow)
4215 for (side = 0;side < 6;side++) if ((receivermask & castermask) & (1 << side))
4217 R_Shadow_RenderMode_ShadowMap(side, false, size);
4218 for (i = 0;i < numshadowentities_noselfshadow;i++) if (entitysides[shadowentities_noselfshadow - i] && (1 << side))
4219 R_Shadow_DrawEntityShadow(shadowentities[shadowentities_noselfshadow - i]);
4223 // render lighting using the depth texture as shadowmap
4224 // draw lighting in the unmasked areas
4225 R_Shadow_RenderMode_Lighting(false, false, true);
4226 // draw lighting in the unmasked areas
4228 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4229 for (i = 0;i < numlightentities;i++)
4230 R_Shadow_DrawEntityLight(lightentities[i]);
4232 else if (castshadows && gl_stencil)
4234 // draw stencil shadow volumes to mask off pixels that are in shadow
4235 // so that they won't receive lighting
4236 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
4237 R_Shadow_ClearStencil();
4239 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
4240 for (i = 0;i < numshadowentities;i++)
4241 R_Shadow_DrawEntityShadow(shadowentities[i]);
4242 if (numlightentities_noselfshadow)
4244 // draw lighting in the unmasked areas
4245 R_Shadow_RenderMode_Lighting(true, false, false);
4246 for (i = 0;i < numlightentities_noselfshadow;i++)
4247 R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
4249 // optionally draw the illuminated areas
4250 // for performance analysis by level designers
4251 if (r_showlighting.integer && r_refdef.view.showdebug)
4253 R_Shadow_RenderMode_VisibleLighting(!r_showdisabledepthtest.integer, false);
4254 for (i = 0;i < numlightentities_noselfshadow;i++)
4255 R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
4258 for (i = 0;i < numshadowentities_noselfshadow;i++)
4259 R_Shadow_DrawEntityShadow(shadowentities[shadowentities_noselfshadow - i]);
4261 if (numsurfaces + numlightentities)
4263 // draw lighting in the unmasked areas
4264 R_Shadow_RenderMode_Lighting(true, false, false);
4266 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4267 for (i = 0;i < numlightentities;i++)
4268 R_Shadow_DrawEntityLight(lightentities[i]);
4273 if (numsurfaces + numlightentities)
4275 // draw lighting in the unmasked areas
4276 R_Shadow_RenderMode_Lighting(false, false, false);
4278 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4279 for (i = 0;i < numlightentities;i++)
4280 R_Shadow_DrawEntityLight(lightentities[i]);
4281 for (i = 0;i < numlightentities_noselfshadow;i++)
4282 R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
4287 void R_Shadow_DrawLightSprites(void);
4288 void R_ShadowVolumeLighting(qboolean visible)
4296 if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, 2048) ||
4297 (r_shadow_shadowmode != 0) != (r_shadow_shadowmapping.integer != 0) ||
4298 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0) ||
4299 r_shadow_shadowmaptexturetype != r_shadow_shadowmapping_texturetype.integer ||
4300 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
4301 r_shadow_shadowmapprecision != r_shadow_shadowmapping_precision.integer ||
4302 r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
4303 R_Shadow_FreeShadowMaps();
4305 if (r_editlights.integer)
4306 R_Shadow_DrawLightSprites();
4308 R_Shadow_RenderMode_Begin();
4310 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4311 if (r_shadow_debuglight.integer >= 0)
4313 lightindex = r_shadow_debuglight.integer;
4314 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4315 if (light && (light->flags & flag))
4316 R_DrawRTLight(&light->rtlight, visible);
4320 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4321 for (lightindex = 0;lightindex < range;lightindex++)
4323 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4324 if (light && (light->flags & flag))
4325 R_DrawRTLight(&light->rtlight, visible);
4328 if (r_refdef.scene.rtdlight)
4329 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4330 R_DrawRTLight(r_refdef.scene.lights[lnum], visible);
4332 R_Shadow_RenderMode_End();
4335 extern const float r_screenvertex3f[12];
4336 extern void R_SetupView(qboolean allowwaterclippingplane);
4337 extern void R_ResetViewRendering3D(void);
4338 extern void R_ResetViewRendering2D(void);
4339 extern cvar_t r_shadows;
4340 extern cvar_t r_shadows_darken;
4341 extern cvar_t r_shadows_drawafterrtlighting;
4342 extern cvar_t r_shadows_castfrombmodels;
4343 extern cvar_t r_shadows_throwdistance;
4344 extern cvar_t r_shadows_throwdirection;
4345 void R_DrawModelShadows(void)
4348 float relativethrowdistance;
4349 entity_render_t *ent;
4350 vec3_t relativelightorigin;
4351 vec3_t relativelightdirection;
4352 vec3_t relativeshadowmins, relativeshadowmaxs;
4353 vec3_t tmp, shadowdir;
4355 if (!r_drawentities.integer || !gl_stencil)
4359 R_ResetViewRendering3D();
4360 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4361 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4362 R_Shadow_RenderMode_Begin();
4363 R_Shadow_RenderMode_ActiveLight(NULL);
4364 r_shadow_lightscissor[0] = r_refdef.view.x;
4365 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
4366 r_shadow_lightscissor[2] = r_refdef.view.width;
4367 r_shadow_lightscissor[3] = r_refdef.view.height;
4368 R_Shadow_RenderMode_StencilShadowVolumes(false);
4371 if (r_shadows.integer == 2)
4373 Math_atov(r_shadows_throwdirection.string, shadowdir);
4374 VectorNormalize(shadowdir);
4377 R_Shadow_ClearStencil();
4379 for (i = 0;i < r_refdef.scene.numentities;i++)
4381 ent = r_refdef.scene.entities[i];
4383 // cast shadows from anything of the map (submodels are optional)
4384 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4386 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4387 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
4388 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
4389 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
4390 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4393 if(ent->entitynumber != 0)
4395 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
4396 int entnum, entnum2, recursion;
4397 entnum = entnum2 = ent->entitynumber;
4398 for(recursion = 32; recursion > 0; --recursion)
4400 entnum2 = cl.entities[entnum].state_current.tagentity;
4401 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
4406 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
4408 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
4409 // transform into modelspace of OUR entity
4410 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
4411 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
4414 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4417 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4420 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
4421 RSurf_ActiveModelEntity(ent, false, false);
4422 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4423 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4427 // not really the right mode, but this will disable any silly stencil features
4428 R_Shadow_RenderMode_End();
4430 // set up ortho view for rendering this pass
4431 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4432 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4433 //GL_ScissorTest(true);
4434 //R_Mesh_Matrix(&identitymatrix);
4435 //R_Mesh_ResetTextureState();
4436 R_ResetViewRendering2D();
4437 R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
4438 R_Mesh_ColorPointer(NULL, 0, 0);
4439 R_SetupGenericShader(false);
4441 // set up a darkening blend on shadowed areas
4442 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4443 //GL_DepthRange(0, 1);
4444 //GL_DepthTest(false);
4445 //GL_DepthMask(false);
4446 //GL_PolygonOffset(0, 0);CHECKGLERROR
4447 GL_Color(0, 0, 0, r_shadows_darken.value);
4448 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4449 //qglDepthFunc(GL_ALWAYS);CHECKGLERROR
4450 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
4451 qglStencilMask(~0);CHECKGLERROR
4452 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
4453 qglStencilFunc(GL_NOTEQUAL, 128, ~0);CHECKGLERROR
4455 // apply the blend to the shadowed areas
4456 R_Mesh_Draw(0, 4, 0, 2, NULL, polygonelements, 0, 0);
4458 // restore the viewport
4459 R_SetViewport(&r_refdef.view.viewport);
4461 // restore other state to normal
4462 //R_Shadow_RenderMode_End();
4465 void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4468 vec3_t centerorigin;
4469 // if it's too close, skip it
4470 if (VectorLength(rtlight->color) < (1.0f / 256.0f))
4472 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4475 if (usequery && r_numqueries + 2 <= r_maxqueries)
4477 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4478 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4479 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4482 // 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
4483 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
4484 qglDepthFunc(GL_ALWAYS);
4485 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);
4486 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4487 qglDepthFunc(GL_LEQUAL);
4488 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
4489 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);
4490 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4493 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4496 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4499 GLint allpixels = 0, visiblepixels = 0;
4500 // now we have to check the query result
4501 if (rtlight->corona_queryindex_visiblepixels)
4504 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
4505 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
4507 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
4508 if (visiblepixels < 1 || allpixels < 1)
4510 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
4511 cscale *= rtlight->corona_visibility;
4515 // FIXME: these traces should scan all render entities instead of cl.world
4516 if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
4519 VectorScale(rtlight->color, cscale, color);
4520 if (VectorLength(color) > (1.0f / 256.0f))
4521 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);
4524 void R_DrawCoronas(void)
4532 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4534 if (r_waterstate.renderingscene)
4536 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4537 R_Mesh_Matrix(&identitymatrix);
4539 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4541 // check occlusion of coronas
4542 // use GL_ARB_occlusion_query if available
4543 // otherwise use raytraces
4545 usequery = gl_support_arb_occlusion_query && r_coronas_occlusionquery.integer;
4548 GL_ColorMask(0,0,0,0);
4549 if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
4550 if (r_maxqueries < R_MAX_OCCLUSION_QUERIES)
4553 r_maxqueries = (range + r_refdef.scene.numlights) * 4;
4554 r_maxqueries = min(r_maxqueries, R_MAX_OCCLUSION_QUERIES);
4556 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
4560 for (lightindex = 0;lightindex < range;lightindex++)
4562 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4565 rtlight = &light->rtlight;
4566 rtlight->corona_visibility = 0;
4567 rtlight->corona_queryindex_visiblepixels = 0;
4568 rtlight->corona_queryindex_allpixels = 0;
4569 if (!(rtlight->flags & flag))
4571 if (rtlight->corona <= 0)
4573 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4575 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4577 for (i = 0;i < r_refdef.scene.numlights;i++)
4579 rtlight = r_refdef.scene.lights[i];
4580 rtlight->corona_visibility = 0;
4581 rtlight->corona_queryindex_visiblepixels = 0;
4582 rtlight->corona_queryindex_allpixels = 0;
4583 if (!(rtlight->flags & flag))
4585 if (rtlight->corona <= 0)
4587 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4590 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4592 // now draw the coronas using the query data for intensity info
4593 for (lightindex = 0;lightindex < range;lightindex++)
4595 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4598 rtlight = &light->rtlight;
4599 if (rtlight->corona_visibility <= 0)
4601 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4603 for (i = 0;i < r_refdef.scene.numlights;i++)
4605 rtlight = r_refdef.scene.lights[i];
4606 if (rtlight->corona_visibility <= 0)
4608 if (gl_flashblend.integer)
4609 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4611 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4617 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
4618 typedef struct suffixinfo_s
4621 qboolean flipx, flipy, flipdiagonal;
4624 static suffixinfo_t suffix[3][6] =
4627 {"px", false, false, false},
4628 {"nx", false, false, false},
4629 {"py", false, false, false},
4630 {"ny", false, false, false},
4631 {"pz", false, false, false},
4632 {"nz", false, false, false}
4635 {"posx", false, false, false},
4636 {"negx", false, false, false},
4637 {"posy", false, false, false},
4638 {"negy", false, false, false},
4639 {"posz", false, false, false},
4640 {"negz", false, false, false}
4643 {"rt", true, false, true},
4644 {"lf", false, true, true},
4645 {"ft", true, true, false},
4646 {"bk", false, false, false},
4647 {"up", true, false, true},
4648 {"dn", true, false, true}
4652 static int componentorder[4] = {0, 1, 2, 3};
4654 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
4656 int i, j, cubemapsize;
4657 unsigned char *cubemappixels, *image_buffer;
4658 rtexture_t *cubemaptexture;
4660 // must start 0 so the first loadimagepixels has no requested width/height
4662 cubemappixels = NULL;
4663 cubemaptexture = NULL;
4664 // keep trying different suffix groups (posx, px, rt) until one loads
4665 for (j = 0;j < 3 && !cubemappixels;j++)
4667 // load the 6 images in the suffix group
4668 for (i = 0;i < 6;i++)
4670 // generate an image name based on the base and and suffix
4671 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
4673 if ((image_buffer = loadimagepixelsbgra(name, false, false)))
4675 // an image loaded, make sure width and height are equal
4676 if (image_width == image_height && (!cubemappixels || image_width == cubemapsize))
4678 // if this is the first image to load successfully, allocate the cubemap memory
4679 if (!cubemappixels && image_width >= 1)
4681 cubemapsize = image_width;
4682 // note this clears to black, so unavailable sides are black
4683 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
4685 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
4687 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);
4690 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
4692 Mem_Free(image_buffer);
4696 // if a cubemap loaded, upload it
4699 if (developer_loading.integer)
4700 Con_Printf("loading cubemap \"%s\"\n", basename);
4702 if (!r_shadow_filters_texturepool)
4703 r_shadow_filters_texturepool = R_AllocTexturePool();
4704 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_BGRA, TEXF_PRECACHE | (gl_texturecompression_lightcubemaps.integer ? TEXF_COMPRESS : 0) | TEXF_FORCELINEAR, NULL);
4705 Mem_Free(cubemappixels);
4709 Con_DPrintf("failed to load cubemap \"%s\"\n", basename);
4710 if (developer_loading.integer)
4712 Con_Printf("(tried tried images ");
4713 for (j = 0;j < 3;j++)
4714 for (i = 0;i < 6;i++)
4715 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
4716 Con_Print(" and was unable to find any of them).\n");
4719 return cubemaptexture;
4722 rtexture_t *R_Shadow_Cubemap(const char *basename)
4725 for (i = 0;i < numcubemaps;i++)
4726 if (!strcasecmp(cubemaps[i].basename, basename))
4727 return cubemaps[i].texture ? cubemaps[i].texture : r_texture_whitecube;
4728 if (i >= MAX_CUBEMAPS)
4729 return r_texture_whitecube;
4731 strlcpy(cubemaps[i].basename, basename, sizeof(cubemaps[i].basename));
4732 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
4733 return cubemaps[i].texture;
4736 void R_Shadow_FreeCubemaps(void)
4739 for (i = 0;i < numcubemaps;i++)
4741 if (developer_loading.integer)
4742 Con_Printf("unloading cubemap \"%s\"\n", cubemaps[i].basename);
4743 if (cubemaps[i].texture)
4744 R_FreeTexture(cubemaps[i].texture);
4748 R_FreeTexturePool(&r_shadow_filters_texturepool);
4751 dlight_t *R_Shadow_NewWorldLight(void)
4753 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4756 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)
4759 // validate parameters
4760 if (style < 0 || style >= MAX_LIGHTSTYLES)
4762 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
4768 // copy to light properties
4769 VectorCopy(origin, light->origin);
4770 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4771 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4772 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4773 light->color[0] = max(color[0], 0);
4774 light->color[1] = max(color[1], 0);
4775 light->color[2] = max(color[2], 0);
4776 light->radius = max(radius, 0);
4777 light->style = style;
4778 light->shadow = shadowenable;
4779 light->corona = corona;
4780 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4781 light->coronasizescale = coronasizescale;
4782 light->ambientscale = ambientscale;
4783 light->diffusescale = diffusescale;
4784 light->specularscale = specularscale;
4785 light->flags = flags;
4787 // update renderable light data
4788 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4789 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);
4792 void R_Shadow_FreeWorldLight(dlight_t *light)
4794 if (r_shadow_selectedlight == light)
4795 r_shadow_selectedlight = NULL;
4796 R_RTLight_Uncompile(&light->rtlight);
4797 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4800 void R_Shadow_ClearWorldLights(void)
4804 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4805 for (lightindex = 0;lightindex < range;lightindex++)
4807 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4809 R_Shadow_FreeWorldLight(light);
4811 r_shadow_selectedlight = NULL;
4812 R_Shadow_FreeCubemaps();
4815 void R_Shadow_SelectLight(dlight_t *light)
4817 if (r_shadow_selectedlight)
4818 r_shadow_selectedlight->selected = false;
4819 r_shadow_selectedlight = light;
4820 if (r_shadow_selectedlight)
4821 r_shadow_selectedlight->selected = true;
4824 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4826 // this is never batched (there can be only one)
4827 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);
4830 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4837 // this is never batched (due to the ent parameter changing every time)
4838 // so numsurfaces == 1 and surfacelist[0] == lightnumber
4839 const dlight_t *light = (dlight_t *)ent;
4842 VectorScale(light->color, intensity, spritecolor);
4843 if (VectorLength(spritecolor) < 0.1732f)
4844 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
4845 if (VectorLength(spritecolor) > 1.0f)
4846 VectorNormalize(spritecolor);
4848 // draw light sprite
4849 if (light->cubemapname[0] && !light->shadow)
4850 pic = r_editlights_sprcubemapnoshadowlight;
4851 else if (light->cubemapname[0])
4852 pic = r_editlights_sprcubemaplight;
4853 else if (!light->shadow)
4854 pic = r_editlights_sprnoshadowlight;
4856 pic = r_editlights_sprlight;
4857 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);
4858 // draw selection sprite if light is selected
4859 if (light->selected)
4860 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);
4861 // VorteX todo: add normalmode/realtime mode light overlay sprites?
4864 void R_Shadow_DrawLightSprites(void)
4868 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4869 for (lightindex = 0;lightindex < range;lightindex++)
4871 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4873 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
4875 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
4878 void R_Shadow_SelectLightInView(void)
4880 float bestrating, rating, temp[3];
4884 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4887 for (lightindex = 0;lightindex < range;lightindex++)
4889 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4892 VectorSubtract(light->origin, r_refdef.view.origin, temp);
4893 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
4896 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
4897 if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1.0f)
4899 bestrating = rating;
4904 R_Shadow_SelectLight(best);
4907 void R_Shadow_LoadWorldLights(void)
4909 int n, a, style, shadow, flags;
4910 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
4911 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
4912 if (cl.worldmodel == NULL)
4914 Con_Print("No map loaded.\n");
4917 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4918 strlcat (name, ".rtlights", sizeof (name));
4919 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4929 for (;COM_Parse(t, true) && strcmp(
4930 if (COM_Parse(t, true))
4932 if (com_token[0] == '!')
4935 origin[0] = atof(com_token+1);
4938 origin[0] = atof(com_token);
4943 while (*s && *s != '\n' && *s != '\r')
4949 // check for modifier flags
4956 #if _MSC_VER >= 1400
4957 #define sscanf sscanf_s
4959 cubemapname[sizeof(cubemapname)-1] = 0;
4960 #if MAX_QPATH != 128
4961 #error update this code if MAX_QPATH changes
4963 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
4964 #if _MSC_VER >= 1400
4965 , sizeof(cubemapname)
4967 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
4970 flags = LIGHTFLAG_REALTIMEMODE;
4978 coronasizescale = 0.25f;
4980 VectorClear(angles);
4983 if (a < 9 || !strcmp(cubemapname, "\"\""))
4985 // remove quotes on cubemapname
4986 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
4989 namelen = strlen(cubemapname) - 2;
4990 memmove(cubemapname, cubemapname + 1, namelen);
4991 cubemapname[namelen] = '\0';
4995 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);
4998 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5006 Con_Printf("invalid rtlights file \"%s\"\n", name);
5007 Mem_Free(lightsstring);
5011 void R_Shadow_SaveWorldLights(void)
5015 size_t bufchars, bufmaxchars;
5017 char name[MAX_QPATH];
5018 char line[MAX_INPUTLINE];
5019 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
5020 // I hate lines which are 3 times my screen size :( --blub
5023 if (cl.worldmodel == NULL)
5025 Con_Print("No map loaded.\n");
5028 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
5029 strlcat (name, ".rtlights", sizeof (name));
5030 bufchars = bufmaxchars = 0;
5032 for (lightindex = 0;lightindex < range;lightindex++)
5034 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5037 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
5038 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);
5039 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
5040 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]);
5042 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);
5043 if (bufchars + strlen(line) > bufmaxchars)
5045 bufmaxchars = bufchars + strlen(line) + 2048;
5047 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
5051 memcpy(buf, oldbuf, bufchars);
5057 memcpy(buf + bufchars, line, strlen(line));
5058 bufchars += strlen(line);
5062 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
5067 void R_Shadow_LoadLightsFile(void)
5070 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
5071 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
5072 if (cl.worldmodel == NULL)
5074 Con_Print("No map loaded.\n");
5077 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
5078 strlcat (name, ".lights", sizeof (name));
5079 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5087 while (*s && *s != '\n' && *s != '\r')
5093 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);
5097 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);
5100 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
5101 radius = bound(15, radius, 4096);
5102 VectorScale(color, (2.0f / (8388608.0f)), color);
5103 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5111 Con_Printf("invalid lights file \"%s\"\n", name);
5112 Mem_Free(lightsstring);
5116 // tyrlite/hmap2 light types in the delay field
5117 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
5119 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
5121 int entnum, style, islight, skin, pflags, effects, type, n;
5124 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
5125 char key[256], value[MAX_INPUTLINE];
5127 if (cl.worldmodel == NULL)
5129 Con_Print("No map loaded.\n");
5132 // try to load a .ent file first
5133 FS_StripExtension (cl.worldmodel->name, key, sizeof (key));
5134 strlcat (key, ".ent", sizeof (key));
5135 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
5136 // and if that is not found, fall back to the bsp file entity string
5138 data = cl.worldmodel->brush.entities;
5141 for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
5143 type = LIGHTTYPE_MINUSX;
5144 origin[0] = origin[1] = origin[2] = 0;
5145 originhack[0] = originhack[1] = originhack[2] = 0;
5146 angles[0] = angles[1] = angles[2] = 0;
5147 color[0] = color[1] = color[2] = 1;
5148 light[0] = light[1] = light[2] = 1;light[3] = 300;
5149 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
5159 if (!COM_ParseToken_Simple(&data, false, false))
5161 if (com_token[0] == '}')
5162 break; // end of entity
5163 if (com_token[0] == '_')
5164 strlcpy(key, com_token + 1, sizeof(key));
5166 strlcpy(key, com_token, sizeof(key));
5167 while (key[strlen(key)-1] == ' ') // remove trailing spaces
5168 key[strlen(key)-1] = 0;
5169 if (!COM_ParseToken_Simple(&data, false, false))
5171 strlcpy(value, com_token, sizeof(value));
5173 // now that we have the key pair worked out...
5174 if (!strcmp("light", key))
5176 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5180 light[0] = vec[0] * (1.0f / 256.0f);
5181 light[1] = vec[0] * (1.0f / 256.0f);
5182 light[2] = vec[0] * (1.0f / 256.0f);
5188 light[0] = vec[0] * (1.0f / 255.0f);
5189 light[1] = vec[1] * (1.0f / 255.0f);
5190 light[2] = vec[2] * (1.0f / 255.0f);
5194 else if (!strcmp("delay", key))
5196 else if (!strcmp("origin", key))
5197 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5198 else if (!strcmp("angle", key))
5199 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5200 else if (!strcmp("angles", key))
5201 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5202 else if (!strcmp("color", key))
5203 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5204 else if (!strcmp("wait", key))
5205 fadescale = atof(value);
5206 else if (!strcmp("classname", key))
5208 if (!strncmp(value, "light", 5))
5211 if (!strcmp(value, "light_fluoro"))
5216 overridecolor[0] = 1;
5217 overridecolor[1] = 1;
5218 overridecolor[2] = 1;
5220 if (!strcmp(value, "light_fluorospark"))
5225 overridecolor[0] = 1;
5226 overridecolor[1] = 1;
5227 overridecolor[2] = 1;
5229 if (!strcmp(value, "light_globe"))
5234 overridecolor[0] = 1;
5235 overridecolor[1] = 0.8;
5236 overridecolor[2] = 0.4;
5238 if (!strcmp(value, "light_flame_large_yellow"))
5243 overridecolor[0] = 1;
5244 overridecolor[1] = 0.5;
5245 overridecolor[2] = 0.1;
5247 if (!strcmp(value, "light_flame_small_yellow"))
5252 overridecolor[0] = 1;
5253 overridecolor[1] = 0.5;
5254 overridecolor[2] = 0.1;
5256 if (!strcmp(value, "light_torch_small_white"))
5261 overridecolor[0] = 1;
5262 overridecolor[1] = 0.5;
5263 overridecolor[2] = 0.1;
5265 if (!strcmp(value, "light_torch_small_walltorch"))
5270 overridecolor[0] = 1;
5271 overridecolor[1] = 0.5;
5272 overridecolor[2] = 0.1;
5276 else if (!strcmp("style", key))
5277 style = atoi(value);
5278 else if (!strcmp("skin", key))
5279 skin = (int)atof(value);
5280 else if (!strcmp("pflags", key))
5281 pflags = (int)atof(value);
5282 else if (!strcmp("effects", key))
5283 effects = (int)atof(value);
5284 else if (cl.worldmodel->type == mod_brushq3)
5286 if (!strcmp("scale", key))
5287 lightscale = atof(value);
5288 if (!strcmp("fade", key))
5289 fadescale = atof(value);
5294 if (lightscale <= 0)
5298 if (color[0] == color[1] && color[0] == color[2])
5300 color[0] *= overridecolor[0];
5301 color[1] *= overridecolor[1];
5302 color[2] *= overridecolor[2];
5304 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5305 color[0] = color[0] * light[0];
5306 color[1] = color[1] * light[1];
5307 color[2] = color[2] * light[2];
5310 case LIGHTTYPE_MINUSX:
5312 case LIGHTTYPE_RECIPX:
5314 VectorScale(color, (1.0f / 16.0f), color);
5316 case LIGHTTYPE_RECIPXX:
5318 VectorScale(color, (1.0f / 16.0f), color);
5321 case LIGHTTYPE_NONE:
5325 case LIGHTTYPE_MINUSXX:
5328 VectorAdd(origin, originhack, origin);
5330 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);
5333 Mem_Free(entfiledata);
5337 void R_Shadow_SetCursorLocationForView(void)
5340 vec3_t dest, endpos;
5342 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5343 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
5344 if (trace.fraction < 1)
5346 dist = trace.fraction * r_editlights_cursordistance.value;
5347 push = r_editlights_cursorpushback.value;
5351 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5352 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5356 VectorClear( endpos );
5358 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5359 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5360 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5363 void R_Shadow_UpdateWorldLightSelection(void)
5365 if (r_editlights.integer)
5367 R_Shadow_SetCursorLocationForView();
5368 R_Shadow_SelectLightInView();
5371 R_Shadow_SelectLight(NULL);
5374 void R_Shadow_EditLights_Clear_f(void)
5376 R_Shadow_ClearWorldLights();
5379 void R_Shadow_EditLights_Reload_f(void)
5383 strlcpy(r_shadow_mapname, cl.worldmodel->name, sizeof(r_shadow_mapname));
5384 R_Shadow_ClearWorldLights();
5385 R_Shadow_LoadWorldLights();
5386 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5388 R_Shadow_LoadLightsFile();
5389 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5390 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5394 void R_Shadow_EditLights_Save_f(void)
5398 R_Shadow_SaveWorldLights();
5401 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
5403 R_Shadow_ClearWorldLights();
5404 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5407 void R_Shadow_EditLights_ImportLightsFile_f(void)
5409 R_Shadow_ClearWorldLights();
5410 R_Shadow_LoadLightsFile();
5413 void R_Shadow_EditLights_Spawn_f(void)
5416 if (!r_editlights.integer)
5418 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5421 if (Cmd_Argc() != 1)
5423 Con_Print("r_editlights_spawn does not take parameters\n");
5426 color[0] = color[1] = color[2] = 1;
5427 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5430 void R_Shadow_EditLights_Edit_f(void)
5432 vec3_t origin, angles, color;
5433 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5434 int style, shadows, flags, normalmode, realtimemode;
5435 char cubemapname[MAX_INPUTLINE];
5436 if (!r_editlights.integer)
5438 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5441 if (!r_shadow_selectedlight)
5443 Con_Print("No selected light.\n");
5446 VectorCopy(r_shadow_selectedlight->origin, origin);
5447 VectorCopy(r_shadow_selectedlight->angles, angles);
5448 VectorCopy(r_shadow_selectedlight->color, color);
5449 radius = r_shadow_selectedlight->radius;
5450 style = r_shadow_selectedlight->style;
5451 if (r_shadow_selectedlight->cubemapname)
5452 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5455 shadows = r_shadow_selectedlight->shadow;
5456 corona = r_shadow_selectedlight->corona;
5457 coronasizescale = r_shadow_selectedlight->coronasizescale;
5458 ambientscale = r_shadow_selectedlight->ambientscale;
5459 diffusescale = r_shadow_selectedlight->diffusescale;
5460 specularscale = r_shadow_selectedlight->specularscale;
5461 flags = r_shadow_selectedlight->flags;
5462 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5463 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5464 if (!strcmp(Cmd_Argv(1), "origin"))
5466 if (Cmd_Argc() != 5)
5468 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5471 origin[0] = atof(Cmd_Argv(2));
5472 origin[1] = atof(Cmd_Argv(3));
5473 origin[2] = atof(Cmd_Argv(4));
5475 else if (!strcmp(Cmd_Argv(1), "originx"))
5477 if (Cmd_Argc() != 3)
5479 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5482 origin[0] = atof(Cmd_Argv(2));
5484 else if (!strcmp(Cmd_Argv(1), "originy"))
5486 if (Cmd_Argc() != 3)
5488 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5491 origin[1] = atof(Cmd_Argv(2));
5493 else if (!strcmp(Cmd_Argv(1), "originz"))
5495 if (Cmd_Argc() != 3)
5497 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5500 origin[2] = atof(Cmd_Argv(2));
5502 else if (!strcmp(Cmd_Argv(1), "move"))
5504 if (Cmd_Argc() != 5)
5506 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5509 origin[0] += atof(Cmd_Argv(2));
5510 origin[1] += atof(Cmd_Argv(3));
5511 origin[2] += atof(Cmd_Argv(4));
5513 else if (!strcmp(Cmd_Argv(1), "movex"))
5515 if (Cmd_Argc() != 3)
5517 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5520 origin[0] += atof(Cmd_Argv(2));
5522 else if (!strcmp(Cmd_Argv(1), "movey"))
5524 if (Cmd_Argc() != 3)
5526 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5529 origin[1] += atof(Cmd_Argv(2));
5531 else if (!strcmp(Cmd_Argv(1), "movez"))
5533 if (Cmd_Argc() != 3)
5535 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5538 origin[2] += atof(Cmd_Argv(2));
5540 else if (!strcmp(Cmd_Argv(1), "angles"))
5542 if (Cmd_Argc() != 5)
5544 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5547 angles[0] = atof(Cmd_Argv(2));
5548 angles[1] = atof(Cmd_Argv(3));
5549 angles[2] = atof(Cmd_Argv(4));
5551 else if (!strcmp(Cmd_Argv(1), "anglesx"))
5553 if (Cmd_Argc() != 3)
5555 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5558 angles[0] = atof(Cmd_Argv(2));
5560 else if (!strcmp(Cmd_Argv(1), "anglesy"))
5562 if (Cmd_Argc() != 3)
5564 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5567 angles[1] = atof(Cmd_Argv(2));
5569 else if (!strcmp(Cmd_Argv(1), "anglesz"))
5571 if (Cmd_Argc() != 3)
5573 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5576 angles[2] = atof(Cmd_Argv(2));
5578 else if (!strcmp(Cmd_Argv(1), "color"))
5580 if (Cmd_Argc() != 5)
5582 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
5585 color[0] = atof(Cmd_Argv(2));
5586 color[1] = atof(Cmd_Argv(3));
5587 color[2] = atof(Cmd_Argv(4));
5589 else if (!strcmp(Cmd_Argv(1), "radius"))
5591 if (Cmd_Argc() != 3)
5593 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5596 radius = atof(Cmd_Argv(2));
5598 else if (!strcmp(Cmd_Argv(1), "colorscale"))
5600 if (Cmd_Argc() == 3)
5602 double scale = atof(Cmd_Argv(2));
5609 if (Cmd_Argc() != 5)
5611 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
5614 color[0] *= atof(Cmd_Argv(2));
5615 color[1] *= atof(Cmd_Argv(3));
5616 color[2] *= atof(Cmd_Argv(4));
5619 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
5621 if (Cmd_Argc() != 3)
5623 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5626 radius *= atof(Cmd_Argv(2));
5628 else if (!strcmp(Cmd_Argv(1), "style"))
5630 if (Cmd_Argc() != 3)
5632 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5635 style = atoi(Cmd_Argv(2));
5637 else if (!strcmp(Cmd_Argv(1), "cubemap"))
5641 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5644 if (Cmd_Argc() == 3)
5645 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
5649 else if (!strcmp(Cmd_Argv(1), "shadows"))
5651 if (Cmd_Argc() != 3)
5653 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5656 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5658 else if (!strcmp(Cmd_Argv(1), "corona"))
5660 if (Cmd_Argc() != 3)
5662 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5665 corona = atof(Cmd_Argv(2));
5667 else if (!strcmp(Cmd_Argv(1), "coronasize"))
5669 if (Cmd_Argc() != 3)
5671 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5674 coronasizescale = atof(Cmd_Argv(2));
5676 else if (!strcmp(Cmd_Argv(1), "ambient"))
5678 if (Cmd_Argc() != 3)
5680 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5683 ambientscale = atof(Cmd_Argv(2));
5685 else if (!strcmp(Cmd_Argv(1), "diffuse"))
5687 if (Cmd_Argc() != 3)
5689 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5692 diffusescale = atof(Cmd_Argv(2));
5694 else if (!strcmp(Cmd_Argv(1), "specular"))
5696 if (Cmd_Argc() != 3)
5698 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5701 specularscale = atof(Cmd_Argv(2));
5703 else if (!strcmp(Cmd_Argv(1), "normalmode"))
5705 if (Cmd_Argc() != 3)
5707 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5710 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5712 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
5714 if (Cmd_Argc() != 3)
5716 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5719 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5723 Con_Print("usage: r_editlights_edit [property] [value]\n");
5724 Con_Print("Selected light's properties:\n");
5725 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5726 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5727 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5728 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
5729 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
5730 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
5731 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5732 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
5733 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
5734 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
5735 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
5736 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
5737 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5738 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5741 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5742 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5745 void R_Shadow_EditLights_EditAll_f(void)
5751 if (!r_editlights.integer)
5753 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5757 // EditLights doesn't seem to have a "remove" command or something so:
5758 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5759 for (lightindex = 0;lightindex < range;lightindex++)
5761 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5764 R_Shadow_SelectLight(light);
5765 R_Shadow_EditLights_Edit_f();
5769 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
5771 int lightnumber, lightcount;
5772 size_t lightindex, range;
5776 if (!r_editlights.integer)
5778 x = vid_conwidth.value - 240;
5780 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
5783 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5784 for (lightindex = 0;lightindex < range;lightindex++)
5786 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5789 if (light == r_shadow_selectedlight)
5790 lightnumber = lightindex;
5793 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;
5794 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;
5796 if (r_shadow_selectedlight == NULL)
5798 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;
5799 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;
5800 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;
5801 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;
5802 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;
5803 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;
5804 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;
5805 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;
5806 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;
5807 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;
5808 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;
5809 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;
5810 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;
5811 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;
5812 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;
5815 void R_Shadow_EditLights_ToggleShadow_f(void)
5817 if (!r_editlights.integer)
5819 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5822 if (!r_shadow_selectedlight)
5824 Con_Print("No selected light.\n");
5827 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);
5830 void R_Shadow_EditLights_ToggleCorona_f(void)
5832 if (!r_editlights.integer)
5834 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5837 if (!r_shadow_selectedlight)
5839 Con_Print("No selected light.\n");
5842 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);
5845 void R_Shadow_EditLights_Remove_f(void)
5847 if (!r_editlights.integer)
5849 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
5852 if (!r_shadow_selectedlight)
5854 Con_Print("No selected light.\n");
5857 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
5858 r_shadow_selectedlight = NULL;
5861 void R_Shadow_EditLights_Help_f(void)
5864 "Documentation on r_editlights system:\n"
5866 "r_editlights : enable/disable editing mode\n"
5867 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
5868 "r_editlights_cursorpushback : push back cursor this far from surface\n"
5869 "r_editlights_cursorpushoff : push cursor off surface this far\n"
5870 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
5871 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
5873 "r_editlights_help : this help\n"
5874 "r_editlights_clear : remove all lights\n"
5875 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
5876 "r_editlights_save : save to .rtlights file\n"
5877 "r_editlights_spawn : create a light with default settings\n"
5878 "r_editlights_edit command : edit selected light - more documentation below\n"
5879 "r_editlights_remove : remove selected light\n"
5880 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
5881 "r_editlights_importlightentitiesfrommap : reload light entities\n"
5882 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
5884 "origin x y z : set light location\n"
5885 "originx x: set x component of light location\n"
5886 "originy y: set y component of light location\n"
5887 "originz z: set z component of light location\n"
5888 "move x y z : adjust light location\n"
5889 "movex x: adjust x component of light location\n"
5890 "movey y: adjust y component of light location\n"
5891 "movez z: adjust z component of light location\n"
5892 "angles x y z : set light angles\n"
5893 "anglesx x: set x component of light angles\n"
5894 "anglesy y: set y component of light angles\n"
5895 "anglesz z: set z component of light angles\n"
5896 "color r g b : set color of light (can be brighter than 1 1 1)\n"
5897 "radius radius : set radius (size) of light\n"
5898 "colorscale grey : multiply color of light (1 does nothing)\n"
5899 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
5900 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
5901 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
5902 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
5903 "cubemap basename : set filter cubemap of light (not yet supported)\n"
5904 "shadows 1/0 : turn on/off shadows\n"
5905 "corona n : set corona intensity\n"
5906 "coronasize n : set corona size (0-1)\n"
5907 "ambient n : set ambient intensity (0-1)\n"
5908 "diffuse n : set diffuse intensity (0-1)\n"
5909 "specular n : set specular intensity (0-1)\n"
5910 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
5911 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
5912 "<nothing> : print light properties to console\n"
5916 void R_Shadow_EditLights_CopyInfo_f(void)
5918 if (!r_editlights.integer)
5920 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
5923 if (!r_shadow_selectedlight)
5925 Con_Print("No selected light.\n");
5928 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
5929 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
5930 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
5931 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
5932 if (r_shadow_selectedlight->cubemapname)
5933 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
5935 r_shadow_bufferlight.cubemapname[0] = 0;
5936 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
5937 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
5938 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
5939 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
5940 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
5941 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
5942 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
5945 void R_Shadow_EditLights_PasteInfo_f(void)
5947 if (!r_editlights.integer)
5949 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
5952 if (!r_shadow_selectedlight)
5954 Con_Print("No selected light.\n");
5957 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);
5960 void R_Shadow_EditLights_Init(void)
5962 Cvar_RegisterVariable(&r_editlights);
5963 Cvar_RegisterVariable(&r_editlights_cursordistance);
5964 Cvar_RegisterVariable(&r_editlights_cursorpushback);
5965 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
5966 Cvar_RegisterVariable(&r_editlights_cursorgrid);
5967 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
5968 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
5969 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
5970 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)");
5971 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
5972 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
5973 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
5974 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)");
5975 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
5976 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
5977 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
5978 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
5979 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
5980 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
5981 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)");
5987 =============================================================================
5991 =============================================================================
5994 void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, int dynamic)
5996 VectorClear(diffusecolor);
5997 VectorClear(diffusenormal);
5999 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
6001 ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_refdef.scene.ambient * (2.0f / 128.0f);
6002 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
6005 VectorSet(ambientcolor, 1, 1, 1);
6012 for (i = 0;i < r_refdef.scene.numlights;i++)
6014 light = r_refdef.scene.lights[i];
6015 Matrix4x4_Transform(&light->matrix_worldtolight, p, v);
6016 f = 1 - VectorLength2(v);
6017 if (f > 0 && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
6018 VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);