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_FrustumCullSides(rtlight_t *rtlight, float size, float border)
1445 static const vec3_t lightnormals[6] = { { 1, 0, 0 }, { -1, 0, 0 }, { 0, 1, 0 }, { 0, -1, 0 }, { 0, 0, 1 }, { 0, 0, -1 } };
1450 float scale = 0.707106781186548*size/(size - 2*border);
1451 for (i = 0;i < 5;i++)
1453 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) > -0.03125)
1455 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[i].normal, frustumdir);
1456 VectorNormalize(frustumdir);
1457 for (j = 0;j < 6;j++)
1458 if(DotProduct(frustumdir, lightnormals[j]) < -scale)
1461 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[4]) > r_refdef.farclip - r_refdef.nearclip + 0.03125)
1463 Matrix4x4_Transform3x3(&rtlight->matrix_worldtolight, r_refdef.view.frustum[4].normal, frustumdir);
1464 VectorNormalize(frustumdir);
1465 for (j = 0;j < 6;j++)
1466 if (DotProduct(frustumdir, lightnormals[j]) > scale)
1472 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)
1480 int mask, surfacemask = 0;
1481 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1483 bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
1484 tend = firsttriangle + numtris;
1485 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1487 // surface box entirely inside light box, no box cull
1488 if (projectdirection)
1490 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1492 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1493 TriangleNormal(v[0], v[1], v[2], normal);
1494 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1496 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1497 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1498 surfacemask |= mask;
1501 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;
1502 shadowsides[numshadowsides] = mask;
1503 shadowsideslist[numshadowsides++] = t;
1510 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1512 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1513 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]))
1515 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1516 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1517 surfacemask |= mask;
1520 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;
1521 shadowsides[numshadowsides] = mask;
1522 shadowsideslist[numshadowsides++] = t;
1530 // surface box not entirely inside light box, cull each triangle
1531 if (projectdirection)
1533 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1535 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1536 TriangleNormal(v[0], v[1], v[2], normal);
1537 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1538 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1540 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1541 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1542 surfacemask |= mask;
1545 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;
1546 shadowsides[numshadowsides] = mask;
1547 shadowsideslist[numshadowsides++] = t;
1554 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1556 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1557 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1558 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1560 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1561 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1562 surfacemask |= mask;
1565 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;
1566 shadowsides[numshadowsides] = mask;
1567 shadowsideslist[numshadowsides++] = t;
1576 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)
1578 int i, j, outtriangles = 0;
1579 int *outelement3i[6];
1580 if (!numverts || !numsidetris || !r_shadow_compilingrtlight)
1582 outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5];
1583 // make sure shadowelements is big enough for this mesh
1584 if (maxshadowtriangles < outtriangles)
1585 R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1);
1587 // compute the offset and size of the separate index lists for each cubemap side
1589 for (i = 0;i < 6;i++)
1591 outelement3i[i] = shadowelements + outtriangles * 3;
1592 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles;
1593 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i];
1594 outtriangles += sidetotals[i];
1597 // gather up the (sparse) triangles into separate index lists for each cubemap side
1598 for (i = 0;i < numsidetris;i++)
1600 const int *element = elements + sidetris[i] * 3;
1601 for (j = 0;j < 6;j++)
1603 if (sides[i] & (1 << j))
1605 outelement3i[j][0] = element[0];
1606 outelement3i[j][1] = element[1];
1607 outelement3i[j][2] = element[2];
1608 outelement3i[j] += 3;
1613 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, outtriangles, shadowelements);
1616 static void R_Shadow_MakeTextures_MakeCorona(void)
1620 unsigned char pixels[32][32][4];
1621 for (y = 0;y < 32;y++)
1623 dy = (y - 15.5f) * (1.0f / 16.0f);
1624 for (x = 0;x < 32;x++)
1626 dx = (x - 15.5f) * (1.0f / 16.0f);
1627 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1628 a = bound(0, a, 255);
1629 pixels[y][x][0] = a;
1630 pixels[y][x][1] = a;
1631 pixels[y][x][2] = a;
1632 pixels[y][x][3] = 255;
1635 r_shadow_lightcorona = R_LoadTexture2D(r_shadow_texturepool, "lightcorona", 32, 32, &pixels[0][0][0], TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_FORCELINEAR, NULL);
1638 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1640 float dist = sqrt(x*x+y*y+z*z);
1641 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1642 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1643 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1646 static void R_Shadow_MakeTextures(void)
1649 float intensity, dist;
1651 R_FreeTexturePool(&r_shadow_texturepool);
1652 r_shadow_texturepool = R_AllocTexturePool();
1653 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1654 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1655 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1656 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1657 for (x = 0;x <= ATTENTABLESIZE;x++)
1659 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1660 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1661 r_shadow_attentable[x] = bound(0, intensity, 1);
1663 // 1D gradient texture
1664 for (x = 0;x < ATTEN1DSIZE;x++)
1665 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1666 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);
1667 // 2D circle texture
1668 for (y = 0;y < ATTEN2DSIZE;y++)
1669 for (x = 0;x < ATTEN2DSIZE;x++)
1670 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);
1671 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);
1672 // 3D sphere texture
1673 if (r_shadow_texture3d.integer && gl_texture3d)
1675 for (z = 0;z < ATTEN3DSIZE;z++)
1676 for (y = 0;y < ATTEN3DSIZE;y++)
1677 for (x = 0;x < ATTEN3DSIZE;x++)
1678 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));
1679 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);
1682 r_shadow_attenuation3dtexture = NULL;
1685 R_Shadow_MakeTextures_MakeCorona();
1687 // Editor light sprites
1688 r_editlights_sprcursor = Draw_CachePic ("gfx/editlights/cursor");
1689 r_editlights_sprlight = Draw_CachePic ("gfx/editlights/light");
1690 r_editlights_sprnoshadowlight = Draw_CachePic ("gfx/editlights/noshadow");
1691 r_editlights_sprcubemaplight = Draw_CachePic ("gfx/editlights/cubemaplight");
1692 r_editlights_sprcubemapnoshadowlight = Draw_CachePic ("gfx/editlights/cubemapnoshadowlight");
1693 r_editlights_sprselection = Draw_CachePic ("gfx/editlights/selection");
1696 void R_Shadow_ValidateCvars(void)
1698 if (r_shadow_texture3d.integer && !gl_texture3d)
1699 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1700 if (gl_ext_separatestencil.integer && !gl_support_separatestencil)
1701 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
1702 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
1703 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1706 void R_Shadow_RenderMode_Begin(void)
1710 R_Shadow_ValidateCvars();
1712 if (!r_shadow_attenuation2dtexture
1713 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1714 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1715 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1716 R_Shadow_MakeTextures();
1719 R_Mesh_ColorPointer(NULL, 0, 0);
1720 R_Mesh_ResetTextureState();
1721 GL_BlendFunc(GL_ONE, GL_ZERO);
1722 GL_DepthRange(0, 1);
1723 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1725 GL_DepthMask(false);
1726 GL_Color(0, 0, 0, 1);
1727 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1729 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1731 if (gl_ext_separatestencil.integer)
1733 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
1734 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
1736 else if (gl_ext_stenciltwoside.integer)
1738 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
1739 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
1743 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
1744 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
1747 if (r_glsl.integer && gl_support_fragment_shader)
1748 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1749 else if (gl_dot3arb && gl_texturecubemap && r_textureunits.integer >= 2 && gl_combine.integer && gl_stencil)
1750 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_DOT3;
1752 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1755 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
1756 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
1757 r_shadow_drawbuffer = drawbuffer;
1758 r_shadow_readbuffer = readbuffer;
1759 r_shadow_cullface = r_refdef.view.cullface_back;
1762 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
1764 rsurface.rtlight = rtlight;
1767 void R_Shadow_RenderMode_Reset(void)
1770 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE)
1772 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1774 if (gl_support_ext_framebuffer_object)
1776 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);CHECKGLERROR
1778 qglDrawBuffer(r_shadow_drawbuffer);CHECKGLERROR
1779 qglReadBuffer(r_shadow_readbuffer);CHECKGLERROR
1780 R_SetViewport(&r_refdef.view.viewport);
1781 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
1782 R_Mesh_ColorPointer(NULL, 0, 0);
1783 R_Mesh_ResetTextureState();
1784 GL_DepthRange(0, 1);
1786 GL_DepthMask(false);
1787 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1788 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1789 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
1790 qglStencilMask(~0);CHECKGLERROR
1791 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
1792 qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
1793 r_refdef.view.cullface_back = r_shadow_cullface;
1794 GL_CullFace(r_refdef.view.cullface_back);
1795 GL_Color(1, 1, 1, 1);
1796 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
1797 GL_BlendFunc(GL_ONE, GL_ZERO);
1798 R_SetupGenericShader(false);
1799 r_shadow_usingshadowmaprect = false;
1800 r_shadow_usingshadowmapcube = false;
1801 r_shadow_usingshadowmap2d = false;
1805 void R_Shadow_ClearStencil(void)
1808 GL_Clear(GL_STENCIL_BUFFER_BIT);
1809 r_refdef.stats.lights_clears++;
1812 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
1814 r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
1815 if (r_shadow_rendermode == mode)
1818 R_Shadow_RenderMode_Reset();
1819 GL_ColorMask(0, 0, 0, 0);
1820 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1821 R_SetupDepthOrShadowShader();
1822 qglDepthFunc(GL_LESS);CHECKGLERROR
1823 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1824 r_shadow_rendermode = mode;
1829 case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
1830 GL_CullFace(GL_NONE);
1831 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1832 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1834 case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
1835 GL_CullFace(GL_NONE);
1836 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1837 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1839 case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
1840 GL_CullFace(GL_NONE);
1841 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1842 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
1843 qglStencilMask(~0);CHECKGLERROR
1844 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1845 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
1846 qglStencilMask(~0);CHECKGLERROR
1847 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1849 case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
1850 GL_CullFace(GL_NONE);
1851 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1852 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
1853 qglStencilMask(~0);CHECKGLERROR
1854 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1855 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
1856 qglStencilMask(~0);CHECKGLERROR
1857 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1862 static void R_Shadow_MakeVSDCT(void)
1864 // maps to a 2x3 texture rectangle with normalized coordinates
1869 // stores abs(dir.xy), offset.xy/2.5
1870 unsigned char data[4*6] =
1872 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
1873 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
1874 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
1875 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
1876 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
1877 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
1879 r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_ALWAYSPRECACHE | TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, NULL);
1882 void R_Shadow_RenderMode_ShadowMap(int side, qboolean clear, int size)
1887 float nearclip, farclip, bias;
1888 r_viewport_t viewport;
1890 maxsize = r_shadow_shadowmapmaxsize;
1891 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
1893 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
1894 r_shadow_shadowmap_parameters[2] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
1895 r_shadow_shadowmap_parameters[3] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
1896 r_shadow_shadowmapside = side;
1897 r_shadow_shadowmapsize = size;
1898 if (r_shadow_shadowmode == 1)
1900 // complex unrolled cube approach (more flexible)
1901 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
1902 R_Shadow_MakeVSDCT();
1903 if (!r_shadow_shadowmap2dtexture)
1906 int w = maxsize*2, h = gl_support_arb_texture_non_power_of_two ? maxsize*3 : maxsize*4;
1907 r_shadow_shadowmap2dtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "shadowmap", w, h, r_shadow_shadowmapprecision, r_shadow_shadowmapsampler);
1908 qglGenFramebuffersEXT(1, &r_shadow_fbo2d);CHECKGLERROR
1909 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbo2d);CHECKGLERROR
1910 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_shadowmap2dtexture), 0);CHECKGLERROR
1914 R_Shadow_RenderMode_Reset();
1915 if (r_shadow_shadowmap2dtexture)
1917 // render depth into the fbo, do not render color at all
1918 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbo2d);CHECKGLERROR
1919 qglDrawBuffer(GL_NONE);CHECKGLERROR
1920 qglReadBuffer(GL_NONE);CHECKGLERROR
1921 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
1922 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
1924 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
1925 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
1927 R_SetupDepthOrShadowShader();
1931 R_SetupShowDepthShader();
1932 qglClearColor(1,1,1,1);CHECKGLERROR
1934 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
1935 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
1936 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
1937 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
1938 r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
1939 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
1941 else if (r_shadow_shadowmode == 2)
1943 // complex unrolled cube approach (more flexible)
1944 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
1945 R_Shadow_MakeVSDCT();
1946 if (!r_shadow_shadowmaprectangletexture)
1949 r_shadow_shadowmaprectangletexture = R_LoadTextureShadowMapRectangle(r_shadow_texturepool, "shadowmap", maxsize*2, maxsize*3, r_shadow_shadowmapprecision, r_shadow_shadowmapsampler);
1950 qglGenFramebuffersEXT(1, &r_shadow_fborectangle);CHECKGLERROR
1951 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fborectangle);CHECKGLERROR
1952 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, R_GetTexture(r_shadow_shadowmaprectangletexture), 0);CHECKGLERROR
1956 R_Shadow_RenderMode_Reset();
1957 if (r_shadow_shadowmaprectangletexture)
1959 // render depth into the fbo, do not render color at all
1960 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fborectangle);CHECKGLERROR
1961 qglDrawBuffer(GL_NONE);CHECKGLERROR
1962 qglReadBuffer(GL_NONE);CHECKGLERROR
1963 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
1964 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
1966 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
1967 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
1969 R_SetupDepthOrShadowShader();
1973 R_SetupShowDepthShader();
1974 qglClearColor(1,1,1,1);CHECKGLERROR
1976 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
1977 r_shadow_shadowmap_texturescale[0] = 1.0f;
1978 r_shadow_shadowmap_texturescale[1] = 1.0f;
1979 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
1980 r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
1981 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE;
1983 else if (r_shadow_shadowmode == 3)
1985 // simple cube approach
1986 if (!r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod])
1989 r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod] = R_LoadTextureShadowMapCube(r_shadow_texturepool, "shadowmapcube", size, r_shadow_shadowmapprecision, r_shadow_shadowmapsampler);
1990 qglGenFramebuffersEXT(6, r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR
1991 for (i = 0;i < 6;i++)
1993 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbocubeside[r_shadow_shadowmaplod][i]);CHECKGLERROR
1994 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
1999 R_Shadow_RenderMode_Reset();
2000 if (r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod])
2002 // render depth into the fbo, do not render color at all
2003 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbocubeside[r_shadow_shadowmaplod][side]);CHECKGLERROR
2004 qglDrawBuffer(GL_NONE);CHECKGLERROR
2005 qglReadBuffer(GL_NONE);CHECKGLERROR
2006 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
2007 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
2009 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
2010 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
2012 R_SetupDepthOrShadowShader();
2016 R_SetupShowDepthShader();
2017 qglClearColor(1,1,1,1);CHECKGLERROR
2019 R_Viewport_InitCubeSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, nearclip, farclip, NULL);
2020 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]);
2021 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureWidth(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]);
2022 r_shadow_shadowmap_parameters[0] = 1.0f;
2023 r_shadow_shadowmap_parameters[1] = 1.0f;
2024 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE;
2027 R_SetViewport(&viewport);
2028 GL_PolygonOffset(0, 0);
2029 if(r_shadow_shadowmode >= 1 && r_shadow_shadowmode <= 2)
2031 static qboolean cullfront[6] = { false, true, false, true, true, false };
2032 if(cullfront[side]) r_refdef.view.cullface_back = r_refdef.view.cullface_front;
2034 GL_CullFace(r_refdef.view.cullface_back);
2035 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
2038 qglClearDepth(1);CHECKGLERROR
2041 qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
2045 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
2048 R_Shadow_RenderMode_Reset();
2049 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2052 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2056 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2057 // only draw light where this geometry was already rendered AND the
2058 // stencil is 128 (values other than this mean shadow)
2059 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
2061 r_shadow_rendermode = r_shadow_lightingrendermode;
2062 // do global setup needed for the chosen lighting mode
2063 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
2065 R_Mesh_TexBindCubeMap(GL20TU_CUBE, R_GetTexture(rsurface.rtlight->currentcubemap)); // light filter
2066 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2070 if (r_shadow_shadowmode == 1)
2072 r_shadow_usingshadowmap2d = true;
2073 R_Mesh_TexBind(GL20TU_SHADOWMAP2D, R_GetTexture(r_shadow_shadowmap2dtexture));
2076 else if (r_shadow_shadowmode == 2)
2078 r_shadow_usingshadowmaprect = true;
2079 R_Mesh_TexBindRectangle(GL20TU_SHADOWMAPRECT, R_GetTexture(r_shadow_shadowmaprectangletexture));
2082 else if (r_shadow_shadowmode == 3)
2084 r_shadow_usingshadowmapcube = true;
2085 R_Mesh_TexBindCubeMap(GL20TU_SHADOWMAPCUBE, R_GetTexture(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]));
2089 if (r_shadow_shadowmapvsdct && (r_shadow_usingshadowmap2d || r_shadow_usingshadowmaprect))
2091 R_Mesh_TexBindCubeMap(GL20TU_CUBEPROJECTION, R_GetTexture(r_shadow_shadowmapvsdcttexture));
2096 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_VERTEX)
2097 R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
2098 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2102 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
2105 R_Shadow_RenderMode_Reset();
2106 GL_BlendFunc(GL_ONE, GL_ONE);
2107 GL_DepthRange(0, 1);
2108 GL_DepthTest(r_showshadowvolumes.integer < 2);
2109 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
2110 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2111 GL_CullFace(GL_NONE);
2112 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
2115 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
2118 R_Shadow_RenderMode_Reset();
2119 GL_BlendFunc(GL_ONE, GL_ONE);
2120 GL_DepthRange(0, 1);
2121 GL_DepthTest(r_showlighting.integer < 2);
2122 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2125 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2129 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2130 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
2132 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2135 void R_Shadow_RenderMode_End(void)
2138 R_Shadow_RenderMode_Reset();
2139 R_Shadow_RenderMode_ActiveLight(NULL);
2141 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2142 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2145 int bboxedges[12][2] =
2164 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2166 int i, ix1, iy1, ix2, iy2;
2167 float x1, y1, x2, y2;
2169 float vertex[20][3];
2178 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2179 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2180 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2181 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2183 if (!r_shadow_scissor.integer)
2186 // if view is inside the light box, just say yes it's visible
2187 if (BoxesOverlap(r_refdef.view.origin, r_refdef.view.origin, mins, maxs))
2190 x1 = y1 = x2 = y2 = 0;
2192 // transform all corners that are infront of the nearclip plane
2193 VectorNegate(r_refdef.view.frustum[4].normal, plane4f);
2194 plane4f[3] = r_refdef.view.frustum[4].dist;
2196 for (i = 0;i < 8;i++)
2198 Vector4Set(corner[i], (i & 1) ? maxs[0] : mins[0], (i & 2) ? maxs[1] : mins[1], (i & 4) ? maxs[2] : mins[2], 1);
2199 dist[i] = DotProduct4(corner[i], plane4f);
2200 sign[i] = dist[i] > 0;
2203 VectorCopy(corner[i], vertex[numvertices]);
2207 // if some points are behind the nearclip, add clipped edge points to make
2208 // sure that the scissor boundary is complete
2209 if (numvertices > 0 && numvertices < 8)
2211 // add clipped edge points
2212 for (i = 0;i < 12;i++)
2214 j = bboxedges[i][0];
2215 k = bboxedges[i][1];
2216 if (sign[j] != sign[k])
2218 f = dist[j] / (dist[j] - dist[k]);
2219 VectorLerp(corner[j], f, corner[k], vertex[numvertices]);
2225 // if we have no points to check, the light is behind the view plane
2229 // if we have some points to transform, check what screen area is covered
2230 x1 = y1 = x2 = y2 = 0;
2232 //Con_Printf("%i vertices to transform...\n", numvertices);
2233 for (i = 0;i < numvertices;i++)
2235 VectorCopy(vertex[i], v);
2236 R_Viewport_TransformToScreen(&r_refdef.view.viewport, v, v2);
2237 //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]);
2240 if (x1 > v2[0]) x1 = v2[0];
2241 if (x2 < v2[0]) x2 = v2[0];
2242 if (y1 > v2[1]) y1 = v2[1];
2243 if (y2 < v2[1]) y2 = v2[1];
2252 // now convert the scissor rectangle to integer screen coordinates
2253 ix1 = (int)(x1 - 1.0f);
2254 iy1 = vid.height - (int)(y2 - 1.0f);
2255 ix2 = (int)(x2 + 1.0f);
2256 iy2 = vid.height - (int)(y1 + 1.0f);
2257 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
2259 // clamp it to the screen
2260 if (ix1 < r_refdef.view.viewport.x) ix1 = r_refdef.view.viewport.x;
2261 if (iy1 < r_refdef.view.viewport.y) iy1 = r_refdef.view.viewport.y;
2262 if (ix2 > r_refdef.view.viewport.x + r_refdef.view.viewport.width) ix2 = r_refdef.view.viewport.x + r_refdef.view.viewport.width;
2263 if (iy2 > r_refdef.view.viewport.y + r_refdef.view.viewport.height) iy2 = r_refdef.view.viewport.y + r_refdef.view.viewport.height;
2265 // if it is inside out, it's not visible
2266 if (ix2 <= ix1 || iy2 <= iy1)
2269 // the light area is visible, set up the scissor rectangle
2270 r_shadow_lightscissor[0] = ix1;
2271 r_shadow_lightscissor[1] = iy1;
2272 r_shadow_lightscissor[2] = ix2 - ix1;
2273 r_shadow_lightscissor[3] = iy2 - iy1;
2275 r_refdef.stats.lights_scissored++;
2279 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, int numtriangles, const int *element3i, const float *diffusecolor, const float *ambientcolor)
2281 float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
2282 float *normal3f = rsurface.normal3f + 3 * firstvertex;
2283 float *color4f = rsurface.array_color4f + 4 * firstvertex;
2284 float dist, dot, distintensity, shadeintensity, v[3], n[3];
2285 if (r_textureunits.integer >= 3)
2287 if (VectorLength2(diffusecolor) > 0)
2289 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2291 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2292 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2293 if ((dot = DotProduct(n, v)) < 0)
2295 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2296 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
2299 VectorCopy(ambientcolor, color4f);
2300 if (r_refdef.fogenabled)
2303 f = FogPoint_Model(vertex3f);
2304 VectorScale(color4f, f, color4f);
2311 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2313 VectorCopy(ambientcolor, color4f);
2314 if (r_refdef.fogenabled)
2317 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2318 f = FogPoint_Model(vertex3f);
2319 VectorScale(color4f, f, color4f);
2325 else if (r_textureunits.integer >= 2)
2327 if (VectorLength2(diffusecolor) > 0)
2329 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2331 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2332 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2334 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2335 if ((dot = DotProduct(n, v)) < 0)
2337 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2338 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2339 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2340 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2344 color4f[0] = ambientcolor[0] * distintensity;
2345 color4f[1] = ambientcolor[1] * distintensity;
2346 color4f[2] = ambientcolor[2] * distintensity;
2348 if (r_refdef.fogenabled)
2351 f = FogPoint_Model(vertex3f);
2352 VectorScale(color4f, f, color4f);
2356 VectorClear(color4f);
2362 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2364 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2365 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2367 color4f[0] = ambientcolor[0] * distintensity;
2368 color4f[1] = ambientcolor[1] * distintensity;
2369 color4f[2] = ambientcolor[2] * distintensity;
2370 if (r_refdef.fogenabled)
2373 f = FogPoint_Model(vertex3f);
2374 VectorScale(color4f, f, color4f);
2378 VectorClear(color4f);
2385 if (VectorLength2(diffusecolor) > 0)
2387 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2389 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2390 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2392 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2393 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2394 if ((dot = DotProduct(n, v)) < 0)
2396 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2397 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2398 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2399 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2403 color4f[0] = ambientcolor[0] * distintensity;
2404 color4f[1] = ambientcolor[1] * distintensity;
2405 color4f[2] = ambientcolor[2] * distintensity;
2407 if (r_refdef.fogenabled)
2410 f = FogPoint_Model(vertex3f);
2411 VectorScale(color4f, f, color4f);
2415 VectorClear(color4f);
2421 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2423 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2424 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2426 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2427 color4f[0] = ambientcolor[0] * distintensity;
2428 color4f[1] = ambientcolor[1] * distintensity;
2429 color4f[2] = ambientcolor[2] * distintensity;
2430 if (r_refdef.fogenabled)
2433 f = FogPoint_Model(vertex3f);
2434 VectorScale(color4f, f, color4f);
2438 VectorClear(color4f);
2445 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
2447 static void R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
2450 float *out3f = rsurface.array_texcoord3f + 3 * firstvertex;
2451 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
2452 const float *svector3f = rsurface.svector3f + 3 * firstvertex;
2453 const float *tvector3f = rsurface.tvector3f + 3 * firstvertex;
2454 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
2456 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
2458 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
2459 // the cubemap normalizes this for us
2460 out3f[0] = DotProduct(svector3f, lightdir);
2461 out3f[1] = DotProduct(tvector3f, lightdir);
2462 out3f[2] = DotProduct(normal3f, lightdir);
2466 static void R_Shadow_GenTexCoords_Specular_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
2469 float *out3f = rsurface.array_texcoord3f + 3 * firstvertex;
2470 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
2471 const float *svector3f = rsurface.svector3f + 3 * firstvertex;
2472 const float *tvector3f = rsurface.tvector3f + 3 * firstvertex;
2473 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
2474 float lightdir[3], eyedir[3], halfdir[3];
2475 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
2477 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
2478 VectorNormalize(lightdir);
2479 VectorSubtract(rsurface.modelorg, vertex3f, eyedir);
2480 VectorNormalize(eyedir);
2481 VectorAdd(lightdir, eyedir, halfdir);
2482 // the cubemap normalizes this for us
2483 out3f[0] = DotProduct(svector3f, halfdir);
2484 out3f[1] = DotProduct(tvector3f, halfdir);
2485 out3f[2] = DotProduct(normal3f, halfdir);
2489 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)
2491 // used to display how many times a surface is lit for level design purposes
2492 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2495 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)
2497 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2498 R_SetupSurfaceShader(lightcolorbase, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT);
2499 if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND))
2500 R_Mesh_ColorPointer(rsurface.modellightmapcolor4f, rsurface.modellightmapcolor4f_bufferobject, rsurface.modellightmapcolor4f_bufferoffset);
2502 R_Mesh_ColorPointer(NULL, 0, 0);
2503 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
2504 R_Mesh_TexMatrix(1, &rsurface.texture->currentbackgroundtexmatrix);
2505 R_Mesh_TexBind(GL20TU_NORMAL, R_GetTexture(rsurface.texture->currentskinframe->nmap));
2506 R_Mesh_TexBind(GL20TU_COLOR, R_GetTexture(rsurface.texture->basetexture));
2507 R_Mesh_TexBind(GL20TU_GLOSS, R_GetTexture(rsurface.texture->glosstexture));
2508 if (rsurface.texture->backgroundcurrentskinframe)
2510 R_Mesh_TexBind(GL20TU_SECONDARY_NORMAL, R_GetTexture(rsurface.texture->backgroundcurrentskinframe->nmap));
2511 R_Mesh_TexBind(GL20TU_SECONDARY_COLOR, R_GetTexture(rsurface.texture->backgroundbasetexture));
2512 R_Mesh_TexBind(GL20TU_SECONDARY_GLOSS, R_GetTexture(rsurface.texture->backgroundglosstexture));
2513 R_Mesh_TexBind(GL20TU_SECONDARY_GLOW, R_GetTexture(rsurface.texture->backgroundcurrentskinframe->glow));
2515 //R_Mesh_TexBindCubeMap(GL20TU_CUBE, R_GetTexture(rsurface.rtlight->currentcubemap));
2516 R_Mesh_TexBind(GL20TU_FOGMASK, R_GetTexture(r_texture_fogattenuation));
2517 if(rsurface.texture->colormapping)
2519 R_Mesh_TexBind(GL20TU_PANTS, R_GetTexture(rsurface.texture->currentskinframe->pants));
2520 R_Mesh_TexBind(GL20TU_SHIRT, R_GetTexture(rsurface.texture->currentskinframe->shirt));
2522 R_Mesh_TexBind(GL20TU_ATTENUATION, R_GetTexture(r_shadow_attenuationgradienttexture));
2523 R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
2524 R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset);
2525 R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset);
2526 R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset);
2527 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2529 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2531 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2532 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2534 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
2538 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)
2540 // shared final code for all the dot3 layers
2542 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2543 for (renders = 0;renders < 64 && (r > 0 || g > 0 || b > 0);renders++, r--, g--, b--)
2545 GL_Color(bound(0, r, 1), bound(0, g, 1), bound(0, b, 1), 1);
2546 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2550 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)
2553 // colorscale accounts for how much we multiply the brightness
2556 // mult is how many times the final pass of the lighting will be
2557 // performed to get more brightness than otherwise possible.
2559 // Limit mult to 64 for sanity sake.
2561 if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
2563 // 3 3D combine path (Geforce3, Radeon 8500)
2564 memset(&m, 0, sizeof(m));
2565 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2566 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2567 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2568 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2569 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2570 m.tex[1] = R_GetTexture(basetexture);
2571 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
2572 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
2573 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
2574 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
2575 m.texcubemap[2] = R_GetTexture(rsurface.rtlight->currentcubemap);
2576 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2577 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2578 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2579 m.texmatrix[2] = rsurface.entitytolight;
2580 GL_BlendFunc(GL_ONE, GL_ONE);
2582 else if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
2584 // 2 3D combine path (Geforce3, original Radeon)
2585 memset(&m, 0, sizeof(m));
2586 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2587 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2588 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2589 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2590 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2591 m.tex[1] = R_GetTexture(basetexture);
2592 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
2593 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
2594 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
2595 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
2596 GL_BlendFunc(GL_ONE, GL_ONE);
2598 else if (r_textureunits.integer >= 4 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2600 // 4 2D combine path (Geforce3, Radeon 8500)
2601 memset(&m, 0, sizeof(m));
2602 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
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(r_shadow_attenuation2dtexture);
2608 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2609 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2610 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2611 m.texmatrix[1] = rsurface.entitytoattenuationz;
2612 m.tex[2] = R_GetTexture(basetexture);
2613 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
2614 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
2615 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
2616 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
2617 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2619 m.texcubemap[3] = R_GetTexture(rsurface.rtlight->currentcubemap);
2620 m.pointer_texcoord3f[3] = rsurface.vertex3f;
2621 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
2622 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
2623 m.texmatrix[3] = rsurface.entitytolight;
2625 GL_BlendFunc(GL_ONE, GL_ONE);
2627 else if (r_textureunits.integer >= 3 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
2629 // 3 2D combine path (Geforce3, original Radeon)
2630 memset(&m, 0, sizeof(m));
2631 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2632 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2633 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2634 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2635 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2636 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2637 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2638 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2639 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2640 m.texmatrix[1] = rsurface.entitytoattenuationz;
2641 m.tex[2] = R_GetTexture(basetexture);
2642 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
2643 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
2644 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
2645 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
2646 GL_BlendFunc(GL_ONE, GL_ONE);
2650 // 2/2/2 2D combine path (any dot3 card)
2651 memset(&m, 0, sizeof(m));
2652 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2653 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2654 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2655 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2656 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2657 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2658 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2659 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2660 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2661 m.texmatrix[1] = rsurface.entitytoattenuationz;
2662 R_Mesh_TextureState(&m);
2663 GL_ColorMask(0,0,0,1);
2664 GL_BlendFunc(GL_ONE, GL_ZERO);
2665 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2668 memset(&m, 0, sizeof(m));
2669 m.tex[0] = R_GetTexture(basetexture);
2670 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2671 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2672 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2673 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2674 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2676 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2677 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2678 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2679 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2680 m.texmatrix[1] = rsurface.entitytolight;
2682 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2684 // this final code is shared
2685 R_Mesh_TextureState(&m);
2686 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);
2689 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)
2692 // colorscale accounts for how much we multiply the brightness
2695 // mult is how many times the final pass of the lighting will be
2696 // performed to get more brightness than otherwise possible.
2698 // Limit mult to 64 for sanity sake.
2700 // generate normalization cubemap texcoords
2701 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
2702 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
2704 // 3/2 3D combine path (Geforce3, Radeon 8500)
2705 memset(&m, 0, sizeof(m));
2706 m.tex[0] = R_GetTexture(normalmaptexture);
2707 m.texcombinergb[0] = GL_REPLACE;
2708 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2709 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2710 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2711 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2712 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2713 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2714 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2715 m.pointer_texcoord_bufferobject[1] = 0;
2716 m.pointer_texcoord_bufferoffset[1] = 0;
2717 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
2718 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2719 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2720 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2721 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
2722 R_Mesh_TextureState(&m);
2723 GL_ColorMask(0,0,0,1);
2724 GL_BlendFunc(GL_ONE, GL_ZERO);
2725 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2728 memset(&m, 0, sizeof(m));
2729 m.tex[0] = R_GetTexture(basetexture);
2730 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2731 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2732 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2733 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2734 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2736 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2737 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2738 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2739 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2740 m.texmatrix[1] = rsurface.entitytolight;
2742 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2744 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2746 // 1/2/2 3D combine path (original Radeon)
2747 memset(&m, 0, sizeof(m));
2748 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2749 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2750 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2751 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2752 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2753 R_Mesh_TextureState(&m);
2754 GL_ColorMask(0,0,0,1);
2755 GL_BlendFunc(GL_ONE, GL_ZERO);
2756 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2759 memset(&m, 0, sizeof(m));
2760 m.tex[0] = R_GetTexture(normalmaptexture);
2761 m.texcombinergb[0] = GL_REPLACE;
2762 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2763 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2764 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2765 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2766 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2767 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2768 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2769 m.pointer_texcoord_bufferobject[1] = 0;
2770 m.pointer_texcoord_bufferoffset[1] = 0;
2771 R_Mesh_TextureState(&m);
2772 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2773 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2776 memset(&m, 0, sizeof(m));
2777 m.tex[0] = R_GetTexture(basetexture);
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 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2784 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2785 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2786 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2787 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2788 m.texmatrix[1] = rsurface.entitytolight;
2790 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2792 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
2794 // 2/2 3D combine path (original Radeon)
2795 memset(&m, 0, sizeof(m));
2796 m.tex[0] = R_GetTexture(normalmaptexture);
2797 m.texcombinergb[0] = GL_REPLACE;
2798 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2799 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2800 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2801 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2802 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2803 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2804 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2805 m.pointer_texcoord_bufferobject[1] = 0;
2806 m.pointer_texcoord_bufferoffset[1] = 0;
2807 R_Mesh_TextureState(&m);
2808 GL_ColorMask(0,0,0,1);
2809 GL_BlendFunc(GL_ONE, GL_ZERO);
2810 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2813 memset(&m, 0, sizeof(m));
2814 m.tex[0] = R_GetTexture(basetexture);
2815 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2816 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2817 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2818 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2819 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2820 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2821 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2822 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2823 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2824 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2826 else if (r_textureunits.integer >= 4)
2828 // 4/2 2D combine path (Geforce3, Radeon 8500)
2829 memset(&m, 0, sizeof(m));
2830 m.tex[0] = R_GetTexture(normalmaptexture);
2831 m.texcombinergb[0] = GL_REPLACE;
2832 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2833 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2834 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2835 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2836 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2837 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2838 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2839 m.pointer_texcoord_bufferobject[1] = 0;
2840 m.pointer_texcoord_bufferoffset[1] = 0;
2841 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2842 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2843 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2844 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2845 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
2846 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
2847 m.pointer_texcoord3f[3] = rsurface.vertex3f;
2848 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
2849 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
2850 m.texmatrix[3] = rsurface.entitytoattenuationz;
2851 R_Mesh_TextureState(&m);
2852 GL_ColorMask(0,0,0,1);
2853 GL_BlendFunc(GL_ONE, GL_ZERO);
2854 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2857 memset(&m, 0, sizeof(m));
2858 m.tex[0] = R_GetTexture(basetexture);
2859 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2860 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2861 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2862 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2863 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2865 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2866 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2867 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2868 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2869 m.texmatrix[1] = rsurface.entitytolight;
2871 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2875 // 2/2/2 2D combine path (any dot3 card)
2876 memset(&m, 0, sizeof(m));
2877 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2878 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2879 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2880 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2881 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2882 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2883 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2884 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2885 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2886 m.texmatrix[1] = rsurface.entitytoattenuationz;
2887 R_Mesh_TextureState(&m);
2888 GL_ColorMask(0,0,0,1);
2889 GL_BlendFunc(GL_ONE, GL_ZERO);
2890 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2893 memset(&m, 0, sizeof(m));
2894 m.tex[0] = R_GetTexture(normalmaptexture);
2895 m.texcombinergb[0] = GL_REPLACE;
2896 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2897 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2898 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2899 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2900 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2901 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2902 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2903 m.pointer_texcoord_bufferobject[1] = 0;
2904 m.pointer_texcoord_bufferoffset[1] = 0;
2905 R_Mesh_TextureState(&m);
2906 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2907 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2910 memset(&m, 0, sizeof(m));
2911 m.tex[0] = R_GetTexture(basetexture);
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 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2918 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2919 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2920 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2921 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2922 m.texmatrix[1] = rsurface.entitytolight;
2924 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2926 // this final code is shared
2927 R_Mesh_TextureState(&m);
2928 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);
2931 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)
2933 float glossexponent;
2935 // FIXME: detect blendsquare!
2936 //if (!gl_support_blendsquare)
2939 // generate normalization cubemap texcoords
2940 R_Shadow_GenTexCoords_Specular_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
2941 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2943 // 2/0/0/1/2 3D combine blendsquare path
2944 memset(&m, 0, sizeof(m));
2945 m.tex[0] = R_GetTexture(normalmaptexture);
2946 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2947 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2948 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2949 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2950 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2951 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2952 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2953 m.pointer_texcoord_bufferobject[1] = 0;
2954 m.pointer_texcoord_bufferoffset[1] = 0;
2955 R_Mesh_TextureState(&m);
2956 GL_ColorMask(0,0,0,1);
2957 // this squares the result
2958 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2959 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2961 // second and third pass
2962 R_Mesh_ResetTextureState();
2963 // square alpha in framebuffer a few times to make it shiny
2964 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2965 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2966 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2969 memset(&m, 0, sizeof(m));
2970 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2971 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2972 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2973 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2974 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2975 R_Mesh_TextureState(&m);
2976 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2977 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2980 memset(&m, 0, sizeof(m));
2981 m.tex[0] = R_GetTexture(glosstexture);
2982 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2983 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2984 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2985 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2986 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2988 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2989 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2990 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2991 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2992 m.texmatrix[1] = rsurface.entitytolight;
2994 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2996 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
2998 // 2/0/0/2 3D combine blendsquare path
2999 memset(&m, 0, sizeof(m));
3000 m.tex[0] = R_GetTexture(normalmaptexture);
3001 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3002 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3003 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3004 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3005 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
3006 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
3007 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
3008 m.pointer_texcoord_bufferobject[1] = 0;
3009 m.pointer_texcoord_bufferoffset[1] = 0;
3010 R_Mesh_TextureState(&m);
3011 GL_ColorMask(0,0,0,1);
3012 // this squares the result
3013 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
3014 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3016 // second and third pass
3017 R_Mesh_ResetTextureState();
3018 // square alpha in framebuffer a few times to make it shiny
3019 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
3020 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
3021 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3024 memset(&m, 0, sizeof(m));
3025 m.tex[0] = R_GetTexture(glosstexture);
3026 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3027 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3028 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3029 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3030 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
3031 m.pointer_texcoord3f[1] = rsurface.vertex3f;
3032 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
3033 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
3034 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
3035 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
3039 // 2/0/0/2/2 2D combine blendsquare path
3040 memset(&m, 0, sizeof(m));
3041 m.tex[0] = R_GetTexture(normalmaptexture);
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.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
3047 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
3048 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
3049 m.pointer_texcoord_bufferobject[1] = 0;
3050 m.pointer_texcoord_bufferoffset[1] = 0;
3051 R_Mesh_TextureState(&m);
3052 GL_ColorMask(0,0,0,1);
3053 // this squares the result
3054 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
3055 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3057 // second and third pass
3058 R_Mesh_ResetTextureState();
3059 // square alpha in framebuffer a few times to make it shiny
3060 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
3061 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
3062 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
3065 memset(&m, 0, sizeof(m));
3066 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
3067 m.pointer_texcoord3f[0] = rsurface.vertex3f;
3068 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
3069 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
3070 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
3071 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
3072 m.pointer_texcoord3f[1] = rsurface.vertex3f;
3073 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
3074 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
3075 m.texmatrix[1] = rsurface.entitytoattenuationz;
3076 R_Mesh_TextureState(&m);
3077 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
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(glosstexture);
3083 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3084 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3085 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3086 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3087 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
3089 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
3090 m.pointer_texcoord3f[1] = rsurface.vertex3f;
3091 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
3092 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
3093 m.texmatrix[1] = rsurface.entitytolight;
3095 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
3097 // this final code is shared
3098 R_Mesh_TextureState(&m);
3099 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);
3102 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)
3104 // ARB path (any Geforce, any Radeon)
3105 qboolean doambient = ambientscale > 0;
3106 qboolean dodiffuse = diffusescale > 0;
3107 qboolean dospecular = specularscale > 0;
3108 if (!doambient && !dodiffuse && !dospecular)
3110 R_Mesh_ColorPointer(NULL, 0, 0);
3112 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, basetexture, ambientscale * r_refdef.view.colorscale);
3114 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, basetexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
3118 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorpants, pantstexture, ambientscale * r_refdef.view.colorscale);
3120 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorpants, pantstexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
3125 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorshirt, shirttexture, ambientscale * r_refdef.view.colorscale);
3127 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorshirt, shirttexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
3130 R_Shadow_RenderLighting_Light_Dot3_SpecularPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, glosstexture, normalmaptexture, specularscale * r_refdef.view.colorscale);
3133 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
3140 int newnumtriangles;
3144 int maxtriangles = 4096;
3145 int newelements[4096*3];
3146 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, numtriangles, element3i, diffusecolor2, ambientcolor2);
3147 for (renders = 0;renders < 64;renders++)
3152 newnumtriangles = 0;
3154 // due to low fillrate on the cards this vertex lighting path is
3155 // designed for, we manually cull all triangles that do not
3156 // contain a lit vertex
3157 // this builds batches of triangles from multiple surfaces and
3158 // renders them at once
3159 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
3161 if (VectorLength2(rsurface.array_color4f + e[0] * 4) + VectorLength2(rsurface.array_color4f + e[1] * 4) + VectorLength2(rsurface.array_color4f + e[2] * 4) >= 0.01)
3163 if (newnumtriangles)
3165 newfirstvertex = min(newfirstvertex, e[0]);
3166 newlastvertex = max(newlastvertex, e[0]);
3170 newfirstvertex = e[0];
3171 newlastvertex = e[0];
3173 newfirstvertex = min(newfirstvertex, e[1]);
3174 newlastvertex = max(newlastvertex, e[1]);
3175 newfirstvertex = min(newfirstvertex, e[2]);
3176 newlastvertex = max(newlastvertex, e[2]);
3182 if (newnumtriangles >= maxtriangles)
3184 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
3185 newnumtriangles = 0;
3191 if (newnumtriangles >= 1)
3193 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
3196 // if we couldn't find any lit triangles, exit early
3199 // now reduce the intensity for the next overbright pass
3200 // we have to clamp to 0 here incase the drivers have improper
3201 // handling of negative colors
3202 // (some old drivers even have improper handling of >1 color)
3204 for (i = 0, c = rsurface.array_color4f + 4 * firstvertex;i < numvertices;i++, c += 4)
3206 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
3208 c[0] = max(0, c[0] - 1);
3209 c[1] = max(0, c[1] - 1);
3210 c[2] = max(0, c[2] - 1);
3222 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)
3224 // OpenGL 1.1 path (anything)
3225 float ambientcolorbase[3], diffusecolorbase[3];
3226 float ambientcolorpants[3], diffusecolorpants[3];
3227 float ambientcolorshirt[3], diffusecolorshirt[3];
3229 VectorScale(lightcolorbase, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorbase);
3230 VectorScale(lightcolorbase, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorbase);
3231 VectorScale(lightcolorpants, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorpants);
3232 VectorScale(lightcolorpants, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorpants);
3233 VectorScale(lightcolorshirt, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorshirt);
3234 VectorScale(lightcolorshirt, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorshirt);
3235 memset(&m, 0, sizeof(m));
3236 m.tex[0] = R_GetTexture(basetexture);
3237 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3238 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3239 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3240 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3241 if (r_textureunits.integer >= 2)
3244 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
3245 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
3246 m.pointer_texcoord3f[1] = rsurface.vertex3f;
3247 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
3248 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
3249 if (r_textureunits.integer >= 3)
3251 // Voodoo4 or Kyro (or Geforce3/Radeon with gl_combine off)
3252 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
3253 m.texmatrix[2] = rsurface.entitytoattenuationz;
3254 m.pointer_texcoord3f[2] = rsurface.vertex3f;
3255 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
3256 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
3259 R_Mesh_TextureState(&m);
3260 //R_Mesh_TexBind(0, R_GetTexture(basetexture));
3261 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorbase, ambientcolorbase);
3264 R_Mesh_TexBind(0, R_GetTexture(pantstexture));
3265 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorpants, ambientcolorpants);
3269 R_Mesh_TexBind(0, R_GetTexture(shirttexture));
3270 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorshirt, ambientcolorshirt);
3274 extern cvar_t gl_lightmaps;
3275 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)
3277 float ambientscale, diffusescale, specularscale;
3278 vec3_t lightcolorbase, lightcolorpants, lightcolorshirt;
3280 // calculate colors to render this texture with
3281 lightcolorbase[0] = rsurface.rtlight->currentcolor[0] * rsurface.texture->dlightcolor[0];
3282 lightcolorbase[1] = rsurface.rtlight->currentcolor[1] * rsurface.texture->dlightcolor[1];
3283 lightcolorbase[2] = rsurface.rtlight->currentcolor[2] * rsurface.texture->dlightcolor[2];
3284 ambientscale = rsurface.rtlight->ambientscale;
3285 diffusescale = rsurface.rtlight->diffusescale;
3286 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
3287 if (!r_shadow_usenormalmap.integer)
3289 ambientscale += 1.0f * diffusescale;
3293 if ((ambientscale + diffusescale) * VectorLength2(lightcolorbase) + specularscale * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
3295 RSurf_SetupDepthAndCulling();
3296 nmap = rsurface.texture->currentskinframe->nmap;
3297 if (gl_lightmaps.integer)
3298 nmap = r_texture_blanknormalmap;
3299 if (rsurface.texture->colormapping && !gl_lightmaps.integer)
3301 qboolean dopants = rsurface.texture->currentskinframe->pants != NULL && VectorLength2(rsurface.colormap_pantscolor) >= (1.0f / 1048576.0f);
3302 qboolean doshirt = rsurface.texture->currentskinframe->shirt != NULL && VectorLength2(rsurface.colormap_shirtcolor) >= (1.0f / 1048576.0f);
3305 lightcolorpants[0] = lightcolorbase[0] * rsurface.colormap_pantscolor[0];
3306 lightcolorpants[1] = lightcolorbase[1] * rsurface.colormap_pantscolor[1];
3307 lightcolorpants[2] = lightcolorbase[2] * rsurface.colormap_pantscolor[2];
3310 VectorClear(lightcolorpants);
3313 lightcolorshirt[0] = lightcolorbase[0] * rsurface.colormap_shirtcolor[0];
3314 lightcolorshirt[1] = lightcolorbase[1] * rsurface.colormap_shirtcolor[1];
3315 lightcolorshirt[2] = lightcolorbase[2] * rsurface.colormap_shirtcolor[2];
3318 VectorClear(lightcolorshirt);
3319 switch (r_shadow_rendermode)
3321 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
3322 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
3323 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);
3325 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
3326 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);
3328 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
3329 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);
3331 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3332 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);
3335 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
3341 switch (r_shadow_rendermode)
3343 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
3344 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
3345 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);
3347 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
3348 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);
3350 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
3351 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);
3353 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3354 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);
3357 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
3363 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)
3365 matrix4x4_t tempmatrix = *matrix;
3366 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
3368 // if this light has been compiled before, free the associated data
3369 R_RTLight_Uncompile(rtlight);
3371 // clear it completely to avoid any lingering data
3372 memset(rtlight, 0, sizeof(*rtlight));
3374 // copy the properties
3375 rtlight->matrix_lighttoworld = tempmatrix;
3376 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
3377 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
3378 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
3379 VectorCopy(color, rtlight->color);
3380 rtlight->cubemapname[0] = 0;
3381 if (cubemapname && cubemapname[0])
3382 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
3383 rtlight->shadow = shadow;
3384 rtlight->corona = corona;
3385 rtlight->style = style;
3386 rtlight->isstatic = isstatic;
3387 rtlight->coronasizescale = coronasizescale;
3388 rtlight->ambientscale = ambientscale;
3389 rtlight->diffusescale = diffusescale;
3390 rtlight->specularscale = specularscale;
3391 rtlight->flags = flags;
3393 // compute derived data
3394 //rtlight->cullradius = rtlight->radius;
3395 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
3396 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3397 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3398 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3399 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3400 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3401 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3404 // compiles rtlight geometry
3405 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
3406 void R_RTLight_Compile(rtlight_t *rtlight)
3409 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
3410 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
3411 entity_render_t *ent = r_refdef.scene.worldentity;
3412 dp_model_t *model = r_refdef.scene.worldmodel;
3413 unsigned char *data;
3416 // compile the light
3417 rtlight->compiled = true;
3418 rtlight->shadowmode = rtlight->shadow ? r_shadow_shadowmode : -1;
3419 rtlight->static_numleafs = 0;
3420 rtlight->static_numleafpvsbytes = 0;
3421 rtlight->static_leaflist = NULL;
3422 rtlight->static_leafpvs = NULL;
3423 rtlight->static_numsurfaces = 0;
3424 rtlight->static_surfacelist = NULL;
3425 rtlight->static_shadowmap_receivers = 0x3F;
3426 rtlight->static_shadowmap_casters = 0x3F;
3427 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3428 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3429 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3430 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3431 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3432 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3434 if (model && model->GetLightInfo)
3436 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
3437 r_shadow_compilingrtlight = rtlight;
3438 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);
3439 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);
3440 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
3441 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
3442 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3443 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
3444 rtlight->static_numsurfaces = numsurfaces;
3445 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
3446 rtlight->static_numleafs = numleafs;
3447 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
3448 rtlight->static_numleafpvsbytes = numleafpvsbytes;
3449 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
3450 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
3451 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
3452 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
3453 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3454 if (rtlight->static_numsurfaces)
3455 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3456 if (rtlight->static_numleafs)
3457 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3458 if (rtlight->static_numleafpvsbytes)
3459 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3460 if (rtlight->static_numshadowtrispvsbytes)
3461 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3462 if (rtlight->static_numlighttrispvsbytes)
3463 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3464 if (rtlight->shadowmode <= 0)
3466 if (model->CompileShadowVolume && rtlight->shadow)
3467 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3471 if (model->CompileShadowMap && rtlight->shadow)
3472 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3474 // now we're done compiling the rtlight
3475 r_shadow_compilingrtlight = NULL;
3479 // use smallest available cullradius - box radius or light radius
3480 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3481 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3483 shadowzpasstris = 0;
3484 if (rtlight->static_meshchain_shadow_zpass)
3485 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
3486 shadowzpasstris += mesh->numtriangles;
3488 shadowzfailtris = 0;
3489 if (rtlight->static_meshchain_shadow_zfail)
3490 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
3491 shadowzfailtris += mesh->numtriangles;
3494 if (rtlight->static_numlighttrispvsbytes)
3495 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3496 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3500 if (rtlight->static_numlighttrispvsbytes)
3501 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3502 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3505 if (developer.integer >= 10)
3506 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);
3509 void R_RTLight_Uncompile(rtlight_t *rtlight)
3511 if (rtlight->compiled)
3513 if (rtlight->static_meshchain_shadow_zpass)
3514 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
3515 rtlight->static_meshchain_shadow_zpass = NULL;
3516 if (rtlight->static_meshchain_shadow_zfail)
3517 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
3518 rtlight->static_meshchain_shadow_zfail = NULL;
3519 if (rtlight->static_meshchain_shadow_shadowmap)
3520 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
3521 rtlight->static_meshchain_shadow_shadowmap = NULL;
3522 // these allocations are grouped
3523 if (rtlight->static_surfacelist)
3524 Mem_Free(rtlight->static_surfacelist);
3525 rtlight->static_numleafs = 0;
3526 rtlight->static_numleafpvsbytes = 0;
3527 rtlight->static_leaflist = NULL;
3528 rtlight->static_leafpvs = NULL;
3529 rtlight->static_numsurfaces = 0;
3530 rtlight->static_surfacelist = NULL;
3531 rtlight->static_numshadowtrispvsbytes = 0;
3532 rtlight->static_shadowtrispvs = NULL;
3533 rtlight->static_numlighttrispvsbytes = 0;
3534 rtlight->static_lighttrispvs = NULL;
3535 rtlight->compiled = false;
3539 void R_Shadow_UncompileWorldLights(void)
3543 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3544 for (lightindex = 0;lightindex < range;lightindex++)
3546 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3549 R_RTLight_Uncompile(&light->rtlight);
3553 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3557 // reset the count of frustum planes
3558 // see rsurface.rtlight_frustumplanes definition for how much this array
3560 rsurface.rtlight_numfrustumplanes = 0;
3562 // haven't implemented a culling path for ortho rendering
3563 if (!r_refdef.view.useperspective)
3565 // check if the light is on screen and copy the 4 planes if it is
3566 for (i = 0;i < 4;i++)
3567 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3570 for (i = 0;i < 4;i++)
3571 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_refdef.view.frustum[i];
3576 // generate a deformed frustum that includes the light origin, this is
3577 // used to cull shadow casting surfaces that can not possibly cast a
3578 // shadow onto the visible light-receiving surfaces, which can be a
3581 // if the light origin is onscreen the result will be 4 planes exactly
3582 // if the light origin is offscreen on only one axis the result will
3583 // be exactly 5 planes (split-side case)
3584 // if the light origin is offscreen on two axes the result will be
3585 // exactly 4 planes (stretched corner case)
3586 for (i = 0;i < 4;i++)
3588 // quickly reject standard frustum planes that put the light
3589 // origin outside the frustum
3590 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3593 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_refdef.view.frustum[i];
3595 // if all the standard frustum planes were accepted, the light is onscreen
3596 // otherwise we need to generate some more planes below...
3597 if (rsurface.rtlight_numfrustumplanes < 4)
3599 // at least one of the stock frustum planes failed, so we need to
3600 // create one or two custom planes to enclose the light origin
3601 for (i = 0;i < 4;i++)
3603 // create a plane using the view origin and light origin, and a
3604 // single point from the frustum corner set
3605 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3606 VectorNormalize(plane.normal);
3607 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3608 // see if this plane is backwards and flip it if so
3609 for (j = 0;j < 4;j++)
3610 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3614 VectorNegate(plane.normal, plane.normal);
3616 // flipped plane, test again to see if it is now valid
3617 for (j = 0;j < 4;j++)
3618 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3620 // if the plane is still not valid, then it is dividing the
3621 // frustum and has to be rejected
3625 // we have created a valid plane, compute extra info
3626 PlaneClassify(&plane);
3628 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3630 // if we've found 5 frustum planes then we have constructed a
3631 // proper split-side case and do not need to keep searching for
3632 // planes to enclose the light origin
3633 if (rsurface.rtlight_numfrustumplanes == 5)
3641 for (i = 0;i < rsurface.rtlight_numfrustumplanes;i++)
3643 plane = rsurface.rtlight_frustumplanes[i];
3644 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));
3649 // now add the light-space box planes if the light box is rotated, as any
3650 // caster outside the oriented light box is irrelevant (even if it passed
3651 // the worldspace light box, which is axial)
3652 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3654 for (i = 0;i < 6;i++)
3658 v[i >> 1] = (i & 1) ? -1 : 1;
3659 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3660 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3661 plane.dist = VectorNormalizeLength(plane.normal);
3662 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3663 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3669 // add the world-space reduced box planes
3670 for (i = 0;i < 6;i++)
3672 VectorClear(plane.normal);
3673 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3674 plane.dist = (i & 1) ? -rsurface.rtlight_cullmaxs[i >> 1] : rsurface.rtlight_cullmins[i >> 1];
3675 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3684 // reduce all plane distances to tightly fit the rtlight cull box, which
3686 VectorSet(points[0], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
3687 VectorSet(points[1], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
3688 VectorSet(points[2], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
3689 VectorSet(points[3], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
3690 VectorSet(points[4], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
3691 VectorSet(points[5], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
3692 VectorSet(points[6], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
3693 VectorSet(points[7], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
3694 oldnum = rsurface.rtlight_numfrustumplanes;
3695 rsurface.rtlight_numfrustumplanes = 0;
3696 for (j = 0;j < oldnum;j++)
3698 // find the nearest point on the box to this plane
3699 bestdist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[0]);
3700 for (i = 1;i < 8;i++)
3702 dist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[i]);
3703 if (bestdist > dist)
3706 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);
3707 // if the nearest point is near or behind the plane, we want this
3708 // plane, otherwise the plane is useless as it won't cull anything
3709 if (rsurface.rtlight_frustumplanes[j].dist < bestdist + 0.03125)
3711 PlaneClassify(&rsurface.rtlight_frustumplanes[j]);
3712 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = rsurface.rtlight_frustumplanes[j];
3719 void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs, const unsigned char *surfacesides)
3723 RSurf_ActiveWorldEntity();
3725 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3728 GL_CullFace(GL_NONE);
3729 mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3730 for (;mesh;mesh = mesh->next)
3732 if (!mesh->sidetotals[r_shadow_shadowmapside])
3734 r_refdef.stats.lights_shadowtriangles += mesh->sidetotals[r_shadow_shadowmapside];
3735 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
3736 R_Mesh_Draw(0, mesh->numverts, mesh->sideoffsets[r_shadow_shadowmapside], mesh->sidetotals[r_shadow_shadowmapside], mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3740 else if (r_refdef.scene.worldentity->model)
3741 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);
3743 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3746 void R_Shadow_DrawWorldShadow_ShadowVolume(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3751 int surfacelistindex;
3752 msurface_t *surface;
3754 RSurf_ActiveWorldEntity();
3756 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3759 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
3760 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
3761 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
3762 for (;mesh;mesh = mesh->next)
3764 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
3765 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
3766 GL_LockArrays(0, mesh->numverts);
3767 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
3769 // increment stencil if frontface is infront of depthbuffer
3770 GL_CullFace(r_refdef.view.cullface_back);
3771 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
3772 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3773 // decrement stencil if backface is infront of depthbuffer
3774 GL_CullFace(r_refdef.view.cullface_front);
3775 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
3777 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
3779 // decrement stencil if backface is behind depthbuffer
3780 GL_CullFace(r_refdef.view.cullface_front);
3781 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
3782 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3783 // increment stencil if frontface is behind depthbuffer
3784 GL_CullFace(r_refdef.view.cullface_back);
3785 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
3787 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3788 GL_LockArrays(0, 0);
3792 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh && r_shadow_culltriangles.integer)
3794 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
3795 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
3797 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
3798 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
3799 if (CHECKPVSBIT(trispvs, t))
3800 shadowmarklist[numshadowmark++] = t;
3802 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);
3804 else if (numsurfaces)
3805 r_refdef.scene.worldmodel->DrawShadowVolume(r_refdef.scene.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs);
3807 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3810 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3812 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3813 vec_t relativeshadowradius;
3814 RSurf_ActiveModelEntity(ent, false, false);
3815 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3816 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3817 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3818 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3819 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3820 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3821 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3822 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3823 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D)
3825 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, NULL, relativeshadowmins, relativeshadowmaxs);
3828 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3829 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3832 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3834 // set up properties for rendering light onto this entity
3835 RSurf_ActiveModelEntity(ent, true, true);
3836 GL_AlphaTest(false);
3837 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3838 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3839 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3840 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3841 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
3842 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
3845 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3847 if (!r_refdef.scene.worldmodel->DrawLight)
3850 // set up properties for rendering light onto this entity
3851 RSurf_ActiveWorldEntity();
3852 GL_AlphaTest(false);
3853 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3854 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3855 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3856 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3857 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
3858 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
3860 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, trispvs);
3862 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3865 void R_Shadow_DrawEntityLight(entity_render_t *ent)
3867 dp_model_t *model = ent->model;
3868 if (!model->DrawLight)
3871 R_Shadow_SetupEntityLight(ent);
3873 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3875 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3878 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
3882 int numleafs, numsurfaces;
3883 int *leaflist, *surfacelist;
3884 unsigned char *leafpvs, *shadowtrispvs, *lighttrispvs, *surfacesides;
3885 int numlightentities;
3886 int numlightentities_noselfshadow;
3887 int numshadowentities;
3888 int numshadowentities_noselfshadow;
3889 static entity_render_t *lightentities[MAX_EDICTS];
3890 static entity_render_t *shadowentities[MAX_EDICTS];
3891 static unsigned char entitysides[MAX_EDICTS];
3892 int lightentities_noselfshadow;
3893 int shadowentities_noselfshadow;
3894 vec3_t nearestpoint;
3896 qboolean castshadows;
3899 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3900 // skip lights that are basically invisible (color 0 0 0)
3901 if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
3904 // loading is done before visibility checks because loading should happen
3905 // all at once at the start of a level, not when it stalls gameplay.
3906 // (especially important to benchmarks)
3908 if (rtlight->isstatic && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
3910 if (rtlight->compiled)
3911 R_RTLight_Uncompile(rtlight);
3912 R_RTLight_Compile(rtlight);
3916 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
3918 // look up the light style value at this time
3919 f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3920 VectorScale(rtlight->color, f, rtlight->currentcolor);
3922 if (rtlight->selected)
3924 f = 2 + sin(realtime * M_PI * 4.0);
3925 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3929 // if lightstyle is currently off, don't draw the light
3930 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3933 // if the light box is offscreen, skip it
3934 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3937 VectorCopy(rtlight->cullmins, rsurface.rtlight_cullmins);
3938 VectorCopy(rtlight->cullmaxs, rsurface.rtlight_cullmaxs);
3940 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3942 // compiled light, world available and can receive realtime lighting
3943 // retrieve leaf information
3944 numleafs = rtlight->static_numleafs;
3945 leaflist = rtlight->static_leaflist;
3946 leafpvs = rtlight->static_leafpvs;
3947 numsurfaces = rtlight->static_numsurfaces;
3948 surfacelist = rtlight->static_surfacelist;
3949 surfacesides = NULL;
3950 shadowtrispvs = rtlight->static_shadowtrispvs;
3951 lighttrispvs = rtlight->static_lighttrispvs;
3953 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3955 // dynamic light, world available and can receive realtime lighting
3956 // calculate lit surfaces and leafs
3957 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);
3958 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);
3959 leaflist = r_shadow_buffer_leaflist;
3960 leafpvs = r_shadow_buffer_leafpvs;
3961 surfacelist = r_shadow_buffer_surfacelist;
3962 surfacesides = r_shadow_buffer_surfacesides;
3963 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3964 lighttrispvs = r_shadow_buffer_lighttrispvs;
3965 // if the reduced leaf bounds are offscreen, skip it
3966 if (R_CullBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
3977 surfacesides = NULL;
3978 shadowtrispvs = NULL;
3979 lighttrispvs = NULL;
3981 // check if light is illuminating any visible leafs
3984 for (i = 0;i < numleafs;i++)
3985 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3990 // set up a scissor rectangle for this light
3991 if (R_Shadow_ScissorForBBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
3994 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3996 // make a list of lit entities and shadow casting entities
3997 numlightentities = 0;
3998 numlightentities_noselfshadow = 0;
3999 lightentities_noselfshadow = sizeof(lightentities)/sizeof(lightentities[0]) - 1;
4000 numshadowentities = 0;
4001 numshadowentities_noselfshadow = 0;
4002 shadowentities_noselfshadow = sizeof(shadowentities)/sizeof(shadowentities[0]) - 1;
4004 // add dynamic entities that are lit by the light
4005 if (r_drawentities.integer)
4007 for (i = 0;i < r_refdef.scene.numentities;i++)
4010 entity_render_t *ent = r_refdef.scene.entities[i];
4012 if (!BoxesOverlap(ent->mins, ent->maxs, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
4014 // skip the object entirely if it is not within the valid
4015 // shadow-casting region (which includes the lit region)
4016 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rsurface.rtlight_numfrustumplanes, rsurface.rtlight_frustumplanes))
4018 if (!(model = ent->model))
4020 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
4022 // this entity wants to receive light, is visible, and is
4023 // inside the light box
4024 // TODO: check if the surfaces in the model can receive light
4025 // so now check if it's in a leaf seen by the light
4026 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))
4028 if (ent->flags & RENDER_NOSELFSHADOW)
4029 lightentities[lightentities_noselfshadow - numlightentities_noselfshadow++] = ent;
4031 lightentities[numlightentities++] = ent;
4032 // since it is lit, it probably also casts a shadow...
4033 // about the VectorDistance2 - light emitting entities should not cast their own shadow
4034 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
4035 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
4037 // note: exterior models without the RENDER_NOSELFSHADOW
4038 // flag still create a RENDER_NOSELFSHADOW shadow but
4039 // are lit normally, this means that they are
4040 // self-shadowing but do not shadow other
4041 // RENDER_NOSELFSHADOW entities such as the gun
4042 // (very weird, but keeps the player shadow off the gun)
4043 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
4044 shadowentities[shadowentities_noselfshadow - numshadowentities_noselfshadow++] = ent;
4046 shadowentities[numshadowentities++] = ent;
4049 else if (ent->flags & RENDER_SHADOW)
4051 // this entity is not receiving light, but may still need to
4053 // TODO: check if the surfaces in the model can cast shadow
4054 // now check if it is in a leaf seen by the light
4055 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))
4057 // about the VectorDistance2 - light emitting entities should not cast their own shadow
4058 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
4059 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
4061 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
4062 shadowentities[shadowentities_noselfshadow - numshadowentities_noselfshadow++] = ent;
4064 shadowentities[numshadowentities++] = ent;
4070 // return if there's nothing at all to light
4071 if (!numlightentities && !numsurfaces)
4074 // don't let sound skip if going slow
4075 if (r_refdef.scene.extraupdate)
4078 // make this the active rtlight for rendering purposes
4079 R_Shadow_RenderMode_ActiveLight(rtlight);
4080 // count this light in the r_speeds
4081 r_refdef.stats.lights++;
4083 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
4085 // optionally draw visible shape of the shadow volumes
4086 // for performance analysis by level designers
4087 R_Shadow_RenderMode_VisibleShadowVolumes();
4089 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
4090 for (i = 0;i < numshadowentities;i++)
4091 R_Shadow_DrawEntityShadow(shadowentities[i]);
4092 for (i = 0;i < numshadowentities_noselfshadow;i++)
4093 R_Shadow_DrawEntityShadow(shadowentities[shadowentities_noselfshadow - i]);
4096 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
4098 // optionally draw the illuminated areas
4099 // for performance analysis by level designers
4100 R_Shadow_RenderMode_VisibleLighting(false, false);
4102 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4103 for (i = 0;i < numlightentities;i++)
4104 R_Shadow_DrawEntityLight(lightentities[i]);
4105 for (i = 0;i < numlightentities_noselfshadow;i++)
4106 R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
4109 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
4111 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
4112 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
4113 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
4114 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
4115 lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
4116 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapping_maxsize.integer);
4118 if (castshadows && r_shadow_shadowmode >= 1 && r_shadow_shadowmode <= 3 && r_glsl.integer && gl_support_fragment_shader)
4124 int receivermask = 0;
4125 matrix4x4_t radiustolight = rtlight->matrix_worldtolight;
4126 Matrix4x4_Abs(&radiustolight);
4128 r_shadow_shadowmaplod = 0;
4129 for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
4130 if ((r_shadow_shadowmapping_maxsize.integer >> i) > lodlinear)
4131 r_shadow_shadowmaplod = i;
4133 size = r_shadow_shadowmode == 3 ? r_shadow_shadowmapping_maxsize.integer >> r_shadow_shadowmaplod : lodlinear;
4134 size = bound(1, size, 2048);
4135 borderbias = r_shadow_shadowmapborder / (float)(size - r_shadow_shadowmapborder);
4139 if (rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
4141 castermask = rtlight->static_shadowmap_casters;
4142 receivermask = rtlight->static_shadowmap_receivers;
4146 for(i = 0;i < numsurfaces;i++)
4148 msurface_t *surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[i];
4149 surfacesides[i] = R_Shadow_CalcBBoxSideMask(surface->mins, surface->maxs, &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4150 castermask |= surfacesides[i];
4151 receivermask |= surfacesides[i];
4155 if (receivermask < 0x3F)
4157 for (i = 0;i < numlightentities;i++)
4158 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4159 if (receivermask < 0x3F)
4160 for(i = 0; i < numlightentities_noselfshadow;i++)
4161 receivermask |= R_Shadow_CalcEntitySideMask(lightentities[lightentities_noselfshadow - i], &rtlight->matrix_worldtolight, &radiustolight, borderbias);
4164 receivermask &= R_Shadow_FrustumCullSides(rtlight, size, r_shadow_shadowmapborder);
4168 for (i = 0;i < numshadowentities;i++)
4169 castermask |= (entitysides[i] = R_Shadow_CalcEntitySideMask(shadowentities[i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
4170 for (i = 0;i < numshadowentities_noselfshadow;i++)
4171 castermask |= (entitysides[shadowentities_noselfshadow - i] = R_Shadow_CalcEntitySideMask(shadowentities[shadowentities_noselfshadow - i], &rtlight->matrix_worldtolight, &radiustolight, borderbias));
4174 //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
4176 // render shadow casters into 6 sided depth texture
4177 for (side = 0;side < 6;side++) if (receivermask & (1 << side))
4179 R_Shadow_RenderMode_ShadowMap(side, true, size);
4180 if (! (castermask & (1 << side))) continue;
4182 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs, surfacesides);
4183 for (i = 0;i < numshadowentities;i++) if (entitysides[i] & (1 << side))
4184 R_Shadow_DrawEntityShadow(shadowentities[i]);
4187 if (numlightentities_noselfshadow)
4189 // render lighting using the depth texture as shadowmap
4190 // draw lighting in the unmasked areas
4191 R_Shadow_RenderMode_Lighting(false, false, true);
4192 for (i = 0;i < numlightentities_noselfshadow;i++)
4193 R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
4196 // render shadow casters into 6 sided depth texture
4197 if (numshadowentities_noselfshadow)
4199 for (side = 0;side < 6;side++) if ((receivermask & castermask) & (1 << side))
4201 R_Shadow_RenderMode_ShadowMap(side, false, size);
4202 for (i = 0;i < numshadowentities_noselfshadow;i++) if (entitysides[shadowentities_noselfshadow - i] && (1 << side))
4203 R_Shadow_DrawEntityShadow(shadowentities[shadowentities_noselfshadow - i]);
4207 // render lighting using the depth texture as shadowmap
4208 // draw lighting in the unmasked areas
4209 R_Shadow_RenderMode_Lighting(false, false, true);
4210 // draw lighting in the unmasked areas
4212 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4213 for (i = 0;i < numlightentities;i++)
4214 R_Shadow_DrawEntityLight(lightentities[i]);
4216 else if (castshadows && gl_stencil)
4218 // draw stencil shadow volumes to mask off pixels that are in shadow
4219 // so that they won't receive lighting
4220 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
4221 R_Shadow_ClearStencil();
4223 R_Shadow_DrawWorldShadow_ShadowVolume(numsurfaces, surfacelist, shadowtrispvs);
4224 for (i = 0;i < numshadowentities;i++)
4225 R_Shadow_DrawEntityShadow(shadowentities[i]);
4226 if (numlightentities_noselfshadow)
4228 // draw lighting in the unmasked areas
4229 R_Shadow_RenderMode_Lighting(true, false, false);
4230 for (i = 0;i < numlightentities_noselfshadow;i++)
4231 R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
4233 // optionally draw the illuminated areas
4234 // for performance analysis by level designers
4235 if (r_showlighting.integer && r_refdef.view.showdebug)
4237 R_Shadow_RenderMode_VisibleLighting(!r_showdisabledepthtest.integer, false);
4238 for (i = 0;i < numlightentities_noselfshadow;i++)
4239 R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
4242 for (i = 0;i < numshadowentities_noselfshadow;i++)
4243 R_Shadow_DrawEntityShadow(shadowentities[shadowentities_noselfshadow - i]);
4245 if (numsurfaces + numlightentities)
4247 // draw lighting in the unmasked areas
4248 R_Shadow_RenderMode_Lighting(true, false, false);
4250 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4251 for (i = 0;i < numlightentities;i++)
4252 R_Shadow_DrawEntityLight(lightentities[i]);
4257 if (numsurfaces + numlightentities)
4259 // draw lighting in the unmasked areas
4260 R_Shadow_RenderMode_Lighting(false, false, false);
4262 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4263 for (i = 0;i < numlightentities;i++)
4264 R_Shadow_DrawEntityLight(lightentities[i]);
4265 for (i = 0;i < numlightentities_noselfshadow;i++)
4266 R_Shadow_DrawEntityLight(lightentities[lightentities_noselfshadow - i]);
4271 void R_Shadow_DrawLightSprites(void);
4272 void R_ShadowVolumeLighting(qboolean visible)
4280 if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, 2048) ||
4281 (r_shadow_shadowmode != 0) != (r_shadow_shadowmapping.integer != 0) ||
4282 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0) ||
4283 r_shadow_shadowmaptexturetype != r_shadow_shadowmapping_texturetype.integer ||
4284 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
4285 r_shadow_shadowmapprecision != r_shadow_shadowmapping_precision.integer ||
4286 r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
4287 R_Shadow_FreeShadowMaps();
4289 if (r_editlights.integer)
4290 R_Shadow_DrawLightSprites();
4292 R_Shadow_RenderMode_Begin();
4294 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4295 if (r_shadow_debuglight.integer >= 0)
4297 lightindex = r_shadow_debuglight.integer;
4298 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4299 if (light && (light->flags & flag))
4300 R_DrawRTLight(&light->rtlight, visible);
4304 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4305 for (lightindex = 0;lightindex < range;lightindex++)
4307 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4308 if (light && (light->flags & flag))
4309 R_DrawRTLight(&light->rtlight, visible);
4312 if (r_refdef.scene.rtdlight)
4313 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4314 R_DrawRTLight(r_refdef.scene.lights[lnum], visible);
4316 R_Shadow_RenderMode_End();
4319 extern const float r_screenvertex3f[12];
4320 extern void R_SetupView(qboolean allowwaterclippingplane);
4321 extern void R_ResetViewRendering3D(void);
4322 extern void R_ResetViewRendering2D(void);
4323 extern cvar_t r_shadows;
4324 extern cvar_t r_shadows_darken;
4325 extern cvar_t r_shadows_drawafterrtlighting;
4326 extern cvar_t r_shadows_castfrombmodels;
4327 extern cvar_t r_shadows_throwdistance;
4328 extern cvar_t r_shadows_throwdirection;
4329 void R_DrawModelShadows(void)
4332 float relativethrowdistance;
4333 entity_render_t *ent;
4334 vec3_t relativelightorigin;
4335 vec3_t relativelightdirection;
4336 vec3_t relativeshadowmins, relativeshadowmaxs;
4337 vec3_t tmp, shadowdir;
4339 if (!r_drawentities.integer || !gl_stencil)
4343 R_ResetViewRendering3D();
4344 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4345 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4346 R_Shadow_RenderMode_Begin();
4347 R_Shadow_RenderMode_ActiveLight(NULL);
4348 r_shadow_lightscissor[0] = r_refdef.view.x;
4349 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
4350 r_shadow_lightscissor[2] = r_refdef.view.width;
4351 r_shadow_lightscissor[3] = r_refdef.view.height;
4352 R_Shadow_RenderMode_StencilShadowVolumes(false);
4355 if (r_shadows.integer == 2)
4357 Math_atov(r_shadows_throwdirection.string, shadowdir);
4358 VectorNormalize(shadowdir);
4361 R_Shadow_ClearStencil();
4363 for (i = 0;i < r_refdef.scene.numentities;i++)
4365 ent = r_refdef.scene.entities[i];
4367 // cast shadows from anything of the map (submodels are optional)
4368 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4370 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4371 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
4372 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
4373 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
4374 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4377 if(ent->entitynumber != 0)
4379 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
4380 int entnum, entnum2, recursion;
4381 entnum = entnum2 = ent->entitynumber;
4382 for(recursion = 32; recursion > 0; --recursion)
4384 entnum2 = cl.entities[entnum].state_current.tagentity;
4385 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
4390 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
4392 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
4393 // transform into modelspace of OUR entity
4394 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
4395 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
4398 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4401 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4404 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
4405 RSurf_ActiveModelEntity(ent, false, false);
4406 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4407 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4411 // not really the right mode, but this will disable any silly stencil features
4412 R_Shadow_RenderMode_End();
4414 // set up ortho view for rendering this pass
4415 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4416 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4417 //GL_ScissorTest(true);
4418 //R_Mesh_Matrix(&identitymatrix);
4419 //R_Mesh_ResetTextureState();
4420 R_ResetViewRendering2D();
4421 R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
4422 R_Mesh_ColorPointer(NULL, 0, 0);
4423 R_SetupGenericShader(false);
4425 // set up a darkening blend on shadowed areas
4426 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4427 //GL_DepthRange(0, 1);
4428 //GL_DepthTest(false);
4429 //GL_DepthMask(false);
4430 //GL_PolygonOffset(0, 0);CHECKGLERROR
4431 GL_Color(0, 0, 0, r_shadows_darken.value);
4432 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4433 //qglDepthFunc(GL_ALWAYS);CHECKGLERROR
4434 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
4435 qglStencilMask(~0);CHECKGLERROR
4436 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
4437 qglStencilFunc(GL_NOTEQUAL, 128, ~0);CHECKGLERROR
4439 // apply the blend to the shadowed areas
4440 R_Mesh_Draw(0, 4, 0, 2, NULL, polygonelements, 0, 0);
4442 // restore the viewport
4443 R_SetViewport(&r_refdef.view.viewport);
4445 // restore other state to normal
4446 //R_Shadow_RenderMode_End();
4449 void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4452 vec3_t centerorigin;
4453 // if it's too close, skip it
4454 if (VectorLength(rtlight->color) < (1.0f / 256.0f))
4456 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4459 if (usequery && r_numqueries + 2 <= r_maxqueries)
4461 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4462 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4463 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4466 // 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
4467 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
4468 qglDepthFunc(GL_ALWAYS);
4469 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);
4470 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4471 qglDepthFunc(GL_LEQUAL);
4472 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
4473 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);
4474 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4477 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4480 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4483 GLint allpixels = 0, visiblepixels = 0;
4484 // now we have to check the query result
4485 if (rtlight->corona_queryindex_visiblepixels)
4488 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
4489 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
4491 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
4492 if (visiblepixels < 1 || allpixels < 1)
4494 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
4495 cscale *= rtlight->corona_visibility;
4499 // FIXME: these traces should scan all render entities instead of cl.world
4500 if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
4503 VectorScale(rtlight->color, cscale, color);
4504 if (VectorLength(color) > (1.0f / 256.0f))
4505 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);
4508 void R_DrawCoronas(void)
4516 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4518 if (r_waterstate.renderingscene)
4520 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4521 R_Mesh_Matrix(&identitymatrix);
4523 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4525 // check occlusion of coronas
4526 // use GL_ARB_occlusion_query if available
4527 // otherwise use raytraces
4529 usequery = gl_support_arb_occlusion_query && r_coronas_occlusionquery.integer;
4532 GL_ColorMask(0,0,0,0);
4533 if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
4534 if (r_maxqueries < R_MAX_OCCLUSION_QUERIES)
4537 r_maxqueries = (range + r_refdef.scene.numlights) * 4;
4538 r_maxqueries = min(r_maxqueries, R_MAX_OCCLUSION_QUERIES);
4540 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
4544 for (lightindex = 0;lightindex < range;lightindex++)
4546 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4549 rtlight = &light->rtlight;
4550 rtlight->corona_visibility = 0;
4551 rtlight->corona_queryindex_visiblepixels = 0;
4552 rtlight->corona_queryindex_allpixels = 0;
4553 if (!(rtlight->flags & flag))
4555 if (rtlight->corona <= 0)
4557 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4559 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4561 for (i = 0;i < r_refdef.scene.numlights;i++)
4563 rtlight = r_refdef.scene.lights[i];
4564 rtlight->corona_visibility = 0;
4565 rtlight->corona_queryindex_visiblepixels = 0;
4566 rtlight->corona_queryindex_allpixels = 0;
4567 if (!(rtlight->flags & flag))
4569 if (rtlight->corona <= 0)
4571 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4574 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4576 // now draw the coronas using the query data for intensity info
4577 for (lightindex = 0;lightindex < range;lightindex++)
4579 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4582 rtlight = &light->rtlight;
4583 if (rtlight->corona_visibility <= 0)
4585 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4587 for (i = 0;i < r_refdef.scene.numlights;i++)
4589 rtlight = r_refdef.scene.lights[i];
4590 if (rtlight->corona_visibility <= 0)
4592 if (gl_flashblend.integer)
4593 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4595 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4601 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
4602 typedef struct suffixinfo_s
4605 qboolean flipx, flipy, flipdiagonal;
4608 static suffixinfo_t suffix[3][6] =
4611 {"px", false, false, false},
4612 {"nx", false, false, false},
4613 {"py", false, false, false},
4614 {"ny", false, false, false},
4615 {"pz", false, false, false},
4616 {"nz", false, false, false}
4619 {"posx", false, false, false},
4620 {"negx", false, false, false},
4621 {"posy", false, false, false},
4622 {"negy", false, false, false},
4623 {"posz", false, false, false},
4624 {"negz", false, false, false}
4627 {"rt", true, false, true},
4628 {"lf", false, true, true},
4629 {"ft", true, true, false},
4630 {"bk", false, false, false},
4631 {"up", true, false, true},
4632 {"dn", true, false, true}
4636 static int componentorder[4] = {0, 1, 2, 3};
4638 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
4640 int i, j, cubemapsize;
4641 unsigned char *cubemappixels, *image_buffer;
4642 rtexture_t *cubemaptexture;
4644 // must start 0 so the first loadimagepixels has no requested width/height
4646 cubemappixels = NULL;
4647 cubemaptexture = NULL;
4648 // keep trying different suffix groups (posx, px, rt) until one loads
4649 for (j = 0;j < 3 && !cubemappixels;j++)
4651 // load the 6 images in the suffix group
4652 for (i = 0;i < 6;i++)
4654 // generate an image name based on the base and and suffix
4655 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
4657 if ((image_buffer = loadimagepixelsbgra(name, false, false)))
4659 // an image loaded, make sure width and height are equal
4660 if (image_width == image_height && (!cubemappixels || image_width == cubemapsize))
4662 // if this is the first image to load successfully, allocate the cubemap memory
4663 if (!cubemappixels && image_width >= 1)
4665 cubemapsize = image_width;
4666 // note this clears to black, so unavailable sides are black
4667 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
4669 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
4671 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);
4674 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
4676 Mem_Free(image_buffer);
4680 // if a cubemap loaded, upload it
4683 if (developer_loading.integer)
4684 Con_Printf("loading cubemap \"%s\"\n", basename);
4686 if (!r_shadow_filters_texturepool)
4687 r_shadow_filters_texturepool = R_AllocTexturePool();
4688 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_BGRA, TEXF_PRECACHE | (gl_texturecompression_lightcubemaps.integer ? TEXF_COMPRESS : 0) | TEXF_FORCELINEAR, NULL);
4689 Mem_Free(cubemappixels);
4693 Con_DPrintf("failed to load cubemap \"%s\"\n", basename);
4694 if (developer_loading.integer)
4696 Con_Printf("(tried tried images ");
4697 for (j = 0;j < 3;j++)
4698 for (i = 0;i < 6;i++)
4699 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
4700 Con_Print(" and was unable to find any of them).\n");
4703 return cubemaptexture;
4706 rtexture_t *R_Shadow_Cubemap(const char *basename)
4709 for (i = 0;i < numcubemaps;i++)
4710 if (!strcasecmp(cubemaps[i].basename, basename))
4711 return cubemaps[i].texture ? cubemaps[i].texture : r_texture_whitecube;
4712 if (i >= MAX_CUBEMAPS)
4713 return r_texture_whitecube;
4715 strlcpy(cubemaps[i].basename, basename, sizeof(cubemaps[i].basename));
4716 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
4717 return cubemaps[i].texture;
4720 void R_Shadow_FreeCubemaps(void)
4723 for (i = 0;i < numcubemaps;i++)
4725 if (developer_loading.integer)
4726 Con_Printf("unloading cubemap \"%s\"\n", cubemaps[i].basename);
4727 if (cubemaps[i].texture)
4728 R_FreeTexture(cubemaps[i].texture);
4732 R_FreeTexturePool(&r_shadow_filters_texturepool);
4735 dlight_t *R_Shadow_NewWorldLight(void)
4737 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4740 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)
4743 // validate parameters
4744 if (style < 0 || style >= MAX_LIGHTSTYLES)
4746 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
4752 // copy to light properties
4753 VectorCopy(origin, light->origin);
4754 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4755 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4756 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4757 light->color[0] = max(color[0], 0);
4758 light->color[1] = max(color[1], 0);
4759 light->color[2] = max(color[2], 0);
4760 light->radius = max(radius, 0);
4761 light->style = style;
4762 light->shadow = shadowenable;
4763 light->corona = corona;
4764 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4765 light->coronasizescale = coronasizescale;
4766 light->ambientscale = ambientscale;
4767 light->diffusescale = diffusescale;
4768 light->specularscale = specularscale;
4769 light->flags = flags;
4771 // update renderable light data
4772 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4773 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);
4776 void R_Shadow_FreeWorldLight(dlight_t *light)
4778 if (r_shadow_selectedlight == light)
4779 r_shadow_selectedlight = NULL;
4780 R_RTLight_Uncompile(&light->rtlight);
4781 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4784 void R_Shadow_ClearWorldLights(void)
4788 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4789 for (lightindex = 0;lightindex < range;lightindex++)
4791 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4793 R_Shadow_FreeWorldLight(light);
4795 r_shadow_selectedlight = NULL;
4796 R_Shadow_FreeCubemaps();
4799 void R_Shadow_SelectLight(dlight_t *light)
4801 if (r_shadow_selectedlight)
4802 r_shadow_selectedlight->selected = false;
4803 r_shadow_selectedlight = light;
4804 if (r_shadow_selectedlight)
4805 r_shadow_selectedlight->selected = true;
4808 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4810 // this is never batched (there can be only one)
4811 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);
4814 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4821 // this is never batched (due to the ent parameter changing every time)
4822 // so numsurfaces == 1 and surfacelist[0] == lightnumber
4823 const dlight_t *light = (dlight_t *)ent;
4826 VectorScale(light->color, intensity, spritecolor);
4827 if (VectorLength(spritecolor) < 0.1732f)
4828 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
4829 if (VectorLength(spritecolor) > 1.0f)
4830 VectorNormalize(spritecolor);
4832 // draw light sprite
4833 if (light->cubemapname[0] && !light->shadow)
4834 pic = r_editlights_sprcubemapnoshadowlight;
4835 else if (light->cubemapname[0])
4836 pic = r_editlights_sprcubemaplight;
4837 else if (!light->shadow)
4838 pic = r_editlights_sprnoshadowlight;
4840 pic = r_editlights_sprlight;
4841 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);
4842 // draw selection sprite if light is selected
4843 if (light->selected)
4844 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);
4845 // VorteX todo: add normalmode/realtime mode light overlay sprites?
4848 void R_Shadow_DrawLightSprites(void)
4852 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4853 for (lightindex = 0;lightindex < range;lightindex++)
4855 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4857 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
4859 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
4862 void R_Shadow_SelectLightInView(void)
4864 float bestrating, rating, temp[3];
4868 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4871 for (lightindex = 0;lightindex < range;lightindex++)
4873 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4876 VectorSubtract(light->origin, r_refdef.view.origin, temp);
4877 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
4880 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
4881 if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1.0f)
4883 bestrating = rating;
4888 R_Shadow_SelectLight(best);
4891 void R_Shadow_LoadWorldLights(void)
4893 int n, a, style, shadow, flags;
4894 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
4895 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
4896 if (cl.worldmodel == NULL)
4898 Con_Print("No map loaded.\n");
4901 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4902 strlcat (name, ".rtlights", sizeof (name));
4903 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4913 for (;COM_Parse(t, true) && strcmp(
4914 if (COM_Parse(t, true))
4916 if (com_token[0] == '!')
4919 origin[0] = atof(com_token+1);
4922 origin[0] = atof(com_token);
4927 while (*s && *s != '\n' && *s != '\r')
4933 // check for modifier flags
4940 #if _MSC_VER >= 1400
4941 #define sscanf sscanf_s
4943 cubemapname[sizeof(cubemapname)-1] = 0;
4944 #if MAX_QPATH != 128
4945 #error update this code if MAX_QPATH changes
4947 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
4948 #if _MSC_VER >= 1400
4949 , sizeof(cubemapname)
4951 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
4954 flags = LIGHTFLAG_REALTIMEMODE;
4962 coronasizescale = 0.25f;
4964 VectorClear(angles);
4967 if (a < 9 || !strcmp(cubemapname, "\"\""))
4969 // remove quotes on cubemapname
4970 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
4973 namelen = strlen(cubemapname) - 2;
4974 memmove(cubemapname, cubemapname + 1, namelen);
4975 cubemapname[namelen] = '\0';
4979 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);
4982 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4990 Con_Printf("invalid rtlights file \"%s\"\n", name);
4991 Mem_Free(lightsstring);
4995 void R_Shadow_SaveWorldLights(void)
4999 size_t bufchars, bufmaxchars;
5001 char name[MAX_QPATH];
5002 char line[MAX_INPUTLINE];
5003 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
5004 // I hate lines which are 3 times my screen size :( --blub
5007 if (cl.worldmodel == NULL)
5009 Con_Print("No map loaded.\n");
5012 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
5013 strlcat (name, ".rtlights", sizeof (name));
5014 bufchars = bufmaxchars = 0;
5016 for (lightindex = 0;lightindex < range;lightindex++)
5018 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5021 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
5022 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);
5023 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
5024 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]);
5026 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);
5027 if (bufchars + strlen(line) > bufmaxchars)
5029 bufmaxchars = bufchars + strlen(line) + 2048;
5031 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
5035 memcpy(buf, oldbuf, bufchars);
5041 memcpy(buf + bufchars, line, strlen(line));
5042 bufchars += strlen(line);
5046 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
5051 void R_Shadow_LoadLightsFile(void)
5054 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
5055 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
5056 if (cl.worldmodel == NULL)
5058 Con_Print("No map loaded.\n");
5061 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
5062 strlcat (name, ".lights", sizeof (name));
5063 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
5071 while (*s && *s != '\n' && *s != '\r')
5077 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);
5081 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);
5084 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
5085 radius = bound(15, radius, 4096);
5086 VectorScale(color, (2.0f / (8388608.0f)), color);
5087 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5095 Con_Printf("invalid lights file \"%s\"\n", name);
5096 Mem_Free(lightsstring);
5100 // tyrlite/hmap2 light types in the delay field
5101 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
5103 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
5105 int entnum, style, islight, skin, pflags, effects, type, n;
5108 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
5109 char key[256], value[MAX_INPUTLINE];
5111 if (cl.worldmodel == NULL)
5113 Con_Print("No map loaded.\n");
5116 // try to load a .ent file first
5117 FS_StripExtension (cl.worldmodel->name, key, sizeof (key));
5118 strlcat (key, ".ent", sizeof (key));
5119 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
5120 // and if that is not found, fall back to the bsp file entity string
5122 data = cl.worldmodel->brush.entities;
5125 for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
5127 type = LIGHTTYPE_MINUSX;
5128 origin[0] = origin[1] = origin[2] = 0;
5129 originhack[0] = originhack[1] = originhack[2] = 0;
5130 angles[0] = angles[1] = angles[2] = 0;
5131 color[0] = color[1] = color[2] = 1;
5132 light[0] = light[1] = light[2] = 1;light[3] = 300;
5133 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
5143 if (!COM_ParseToken_Simple(&data, false, false))
5145 if (com_token[0] == '}')
5146 break; // end of entity
5147 if (com_token[0] == '_')
5148 strlcpy(key, com_token + 1, sizeof(key));
5150 strlcpy(key, com_token, sizeof(key));
5151 while (key[strlen(key)-1] == ' ') // remove trailing spaces
5152 key[strlen(key)-1] = 0;
5153 if (!COM_ParseToken_Simple(&data, false, false))
5155 strlcpy(value, com_token, sizeof(value));
5157 // now that we have the key pair worked out...
5158 if (!strcmp("light", key))
5160 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5164 light[0] = vec[0] * (1.0f / 256.0f);
5165 light[1] = vec[0] * (1.0f / 256.0f);
5166 light[2] = vec[0] * (1.0f / 256.0f);
5172 light[0] = vec[0] * (1.0f / 255.0f);
5173 light[1] = vec[1] * (1.0f / 255.0f);
5174 light[2] = vec[2] * (1.0f / 255.0f);
5178 else if (!strcmp("delay", key))
5180 else if (!strcmp("origin", key))
5181 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5182 else if (!strcmp("angle", key))
5183 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5184 else if (!strcmp("angles", key))
5185 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5186 else if (!strcmp("color", key))
5187 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5188 else if (!strcmp("wait", key))
5189 fadescale = atof(value);
5190 else if (!strcmp("classname", key))
5192 if (!strncmp(value, "light", 5))
5195 if (!strcmp(value, "light_fluoro"))
5200 overridecolor[0] = 1;
5201 overridecolor[1] = 1;
5202 overridecolor[2] = 1;
5204 if (!strcmp(value, "light_fluorospark"))
5209 overridecolor[0] = 1;
5210 overridecolor[1] = 1;
5211 overridecolor[2] = 1;
5213 if (!strcmp(value, "light_globe"))
5218 overridecolor[0] = 1;
5219 overridecolor[1] = 0.8;
5220 overridecolor[2] = 0.4;
5222 if (!strcmp(value, "light_flame_large_yellow"))
5227 overridecolor[0] = 1;
5228 overridecolor[1] = 0.5;
5229 overridecolor[2] = 0.1;
5231 if (!strcmp(value, "light_flame_small_yellow"))
5236 overridecolor[0] = 1;
5237 overridecolor[1] = 0.5;
5238 overridecolor[2] = 0.1;
5240 if (!strcmp(value, "light_torch_small_white"))
5245 overridecolor[0] = 1;
5246 overridecolor[1] = 0.5;
5247 overridecolor[2] = 0.1;
5249 if (!strcmp(value, "light_torch_small_walltorch"))
5254 overridecolor[0] = 1;
5255 overridecolor[1] = 0.5;
5256 overridecolor[2] = 0.1;
5260 else if (!strcmp("style", key))
5261 style = atoi(value);
5262 else if (!strcmp("skin", key))
5263 skin = (int)atof(value);
5264 else if (!strcmp("pflags", key))
5265 pflags = (int)atof(value);
5266 else if (!strcmp("effects", key))
5267 effects = (int)atof(value);
5268 else if (cl.worldmodel->type == mod_brushq3)
5270 if (!strcmp("scale", key))
5271 lightscale = atof(value);
5272 if (!strcmp("fade", key))
5273 fadescale = atof(value);
5278 if (lightscale <= 0)
5282 if (color[0] == color[1] && color[0] == color[2])
5284 color[0] *= overridecolor[0];
5285 color[1] *= overridecolor[1];
5286 color[2] *= overridecolor[2];
5288 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5289 color[0] = color[0] * light[0];
5290 color[1] = color[1] * light[1];
5291 color[2] = color[2] * light[2];
5294 case LIGHTTYPE_MINUSX:
5296 case LIGHTTYPE_RECIPX:
5298 VectorScale(color, (1.0f / 16.0f), color);
5300 case LIGHTTYPE_RECIPXX:
5302 VectorScale(color, (1.0f / 16.0f), color);
5305 case LIGHTTYPE_NONE:
5309 case LIGHTTYPE_MINUSXX:
5312 VectorAdd(origin, originhack, origin);
5314 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);
5317 Mem_Free(entfiledata);
5321 void R_Shadow_SetCursorLocationForView(void)
5324 vec3_t dest, endpos;
5326 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5327 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
5328 if (trace.fraction < 1)
5330 dist = trace.fraction * r_editlights_cursordistance.value;
5331 push = r_editlights_cursorpushback.value;
5335 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5336 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5340 VectorClear( endpos );
5342 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5343 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5344 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5347 void R_Shadow_UpdateWorldLightSelection(void)
5349 if (r_editlights.integer)
5351 R_Shadow_SetCursorLocationForView();
5352 R_Shadow_SelectLightInView();
5355 R_Shadow_SelectLight(NULL);
5358 void R_Shadow_EditLights_Clear_f(void)
5360 R_Shadow_ClearWorldLights();
5363 void R_Shadow_EditLights_Reload_f(void)
5367 strlcpy(r_shadow_mapname, cl.worldmodel->name, sizeof(r_shadow_mapname));
5368 R_Shadow_ClearWorldLights();
5369 R_Shadow_LoadWorldLights();
5370 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5372 R_Shadow_LoadLightsFile();
5373 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5374 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5378 void R_Shadow_EditLights_Save_f(void)
5382 R_Shadow_SaveWorldLights();
5385 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
5387 R_Shadow_ClearWorldLights();
5388 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5391 void R_Shadow_EditLights_ImportLightsFile_f(void)
5393 R_Shadow_ClearWorldLights();
5394 R_Shadow_LoadLightsFile();
5397 void R_Shadow_EditLights_Spawn_f(void)
5400 if (!r_editlights.integer)
5402 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5405 if (Cmd_Argc() != 1)
5407 Con_Print("r_editlights_spawn does not take parameters\n");
5410 color[0] = color[1] = color[2] = 1;
5411 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5414 void R_Shadow_EditLights_Edit_f(void)
5416 vec3_t origin, angles, color;
5417 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5418 int style, shadows, flags, normalmode, realtimemode;
5419 char cubemapname[MAX_INPUTLINE];
5420 if (!r_editlights.integer)
5422 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5425 if (!r_shadow_selectedlight)
5427 Con_Print("No selected light.\n");
5430 VectorCopy(r_shadow_selectedlight->origin, origin);
5431 VectorCopy(r_shadow_selectedlight->angles, angles);
5432 VectorCopy(r_shadow_selectedlight->color, color);
5433 radius = r_shadow_selectedlight->radius;
5434 style = r_shadow_selectedlight->style;
5435 if (r_shadow_selectedlight->cubemapname)
5436 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5439 shadows = r_shadow_selectedlight->shadow;
5440 corona = r_shadow_selectedlight->corona;
5441 coronasizescale = r_shadow_selectedlight->coronasizescale;
5442 ambientscale = r_shadow_selectedlight->ambientscale;
5443 diffusescale = r_shadow_selectedlight->diffusescale;
5444 specularscale = r_shadow_selectedlight->specularscale;
5445 flags = r_shadow_selectedlight->flags;
5446 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5447 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5448 if (!strcmp(Cmd_Argv(1), "origin"))
5450 if (Cmd_Argc() != 5)
5452 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5455 origin[0] = atof(Cmd_Argv(2));
5456 origin[1] = atof(Cmd_Argv(3));
5457 origin[2] = atof(Cmd_Argv(4));
5459 else if (!strcmp(Cmd_Argv(1), "originx"))
5461 if (Cmd_Argc() != 3)
5463 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5466 origin[0] = atof(Cmd_Argv(2));
5468 else if (!strcmp(Cmd_Argv(1), "originy"))
5470 if (Cmd_Argc() != 3)
5472 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5475 origin[1] = atof(Cmd_Argv(2));
5477 else if (!strcmp(Cmd_Argv(1), "originz"))
5479 if (Cmd_Argc() != 3)
5481 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5484 origin[2] = atof(Cmd_Argv(2));
5486 else if (!strcmp(Cmd_Argv(1), "move"))
5488 if (Cmd_Argc() != 5)
5490 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5493 origin[0] += atof(Cmd_Argv(2));
5494 origin[1] += atof(Cmd_Argv(3));
5495 origin[2] += atof(Cmd_Argv(4));
5497 else if (!strcmp(Cmd_Argv(1), "movex"))
5499 if (Cmd_Argc() != 3)
5501 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5504 origin[0] += atof(Cmd_Argv(2));
5506 else if (!strcmp(Cmd_Argv(1), "movey"))
5508 if (Cmd_Argc() != 3)
5510 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5513 origin[1] += atof(Cmd_Argv(2));
5515 else if (!strcmp(Cmd_Argv(1), "movez"))
5517 if (Cmd_Argc() != 3)
5519 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5522 origin[2] += atof(Cmd_Argv(2));
5524 else if (!strcmp(Cmd_Argv(1), "angles"))
5526 if (Cmd_Argc() != 5)
5528 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5531 angles[0] = atof(Cmd_Argv(2));
5532 angles[1] = atof(Cmd_Argv(3));
5533 angles[2] = atof(Cmd_Argv(4));
5535 else if (!strcmp(Cmd_Argv(1), "anglesx"))
5537 if (Cmd_Argc() != 3)
5539 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5542 angles[0] = atof(Cmd_Argv(2));
5544 else if (!strcmp(Cmd_Argv(1), "anglesy"))
5546 if (Cmd_Argc() != 3)
5548 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5551 angles[1] = atof(Cmd_Argv(2));
5553 else if (!strcmp(Cmd_Argv(1), "anglesz"))
5555 if (Cmd_Argc() != 3)
5557 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5560 angles[2] = atof(Cmd_Argv(2));
5562 else if (!strcmp(Cmd_Argv(1), "color"))
5564 if (Cmd_Argc() != 5)
5566 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
5569 color[0] = atof(Cmd_Argv(2));
5570 color[1] = atof(Cmd_Argv(3));
5571 color[2] = atof(Cmd_Argv(4));
5573 else if (!strcmp(Cmd_Argv(1), "radius"))
5575 if (Cmd_Argc() != 3)
5577 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5580 radius = atof(Cmd_Argv(2));
5582 else if (!strcmp(Cmd_Argv(1), "colorscale"))
5584 if (Cmd_Argc() == 3)
5586 double scale = atof(Cmd_Argv(2));
5593 if (Cmd_Argc() != 5)
5595 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
5598 color[0] *= atof(Cmd_Argv(2));
5599 color[1] *= atof(Cmd_Argv(3));
5600 color[2] *= atof(Cmd_Argv(4));
5603 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
5605 if (Cmd_Argc() != 3)
5607 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5610 radius *= atof(Cmd_Argv(2));
5612 else if (!strcmp(Cmd_Argv(1), "style"))
5614 if (Cmd_Argc() != 3)
5616 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5619 style = atoi(Cmd_Argv(2));
5621 else if (!strcmp(Cmd_Argv(1), "cubemap"))
5625 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5628 if (Cmd_Argc() == 3)
5629 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
5633 else if (!strcmp(Cmd_Argv(1), "shadows"))
5635 if (Cmd_Argc() != 3)
5637 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5640 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5642 else if (!strcmp(Cmd_Argv(1), "corona"))
5644 if (Cmd_Argc() != 3)
5646 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5649 corona = atof(Cmd_Argv(2));
5651 else if (!strcmp(Cmd_Argv(1), "coronasize"))
5653 if (Cmd_Argc() != 3)
5655 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5658 coronasizescale = atof(Cmd_Argv(2));
5660 else if (!strcmp(Cmd_Argv(1), "ambient"))
5662 if (Cmd_Argc() != 3)
5664 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5667 ambientscale = atof(Cmd_Argv(2));
5669 else if (!strcmp(Cmd_Argv(1), "diffuse"))
5671 if (Cmd_Argc() != 3)
5673 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5676 diffusescale = atof(Cmd_Argv(2));
5678 else if (!strcmp(Cmd_Argv(1), "specular"))
5680 if (Cmd_Argc() != 3)
5682 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5685 specularscale = atof(Cmd_Argv(2));
5687 else if (!strcmp(Cmd_Argv(1), "normalmode"))
5689 if (Cmd_Argc() != 3)
5691 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5694 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5696 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
5698 if (Cmd_Argc() != 3)
5700 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5703 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5707 Con_Print("usage: r_editlights_edit [property] [value]\n");
5708 Con_Print("Selected light's properties:\n");
5709 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5710 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5711 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5712 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
5713 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
5714 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
5715 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5716 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
5717 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
5718 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
5719 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
5720 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
5721 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5722 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5725 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5726 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5729 void R_Shadow_EditLights_EditAll_f(void)
5735 if (!r_editlights.integer)
5737 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5741 // EditLights doesn't seem to have a "remove" command or something so:
5742 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5743 for (lightindex = 0;lightindex < range;lightindex++)
5745 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5748 R_Shadow_SelectLight(light);
5749 R_Shadow_EditLights_Edit_f();
5753 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
5755 int lightnumber, lightcount;
5756 size_t lightindex, range;
5760 if (!r_editlights.integer)
5762 x = vid_conwidth.value - 240;
5764 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
5767 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5768 for (lightindex = 0;lightindex < range;lightindex++)
5770 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5773 if (light == r_shadow_selectedlight)
5774 lightnumber = lightindex;
5777 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;
5778 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;
5780 if (r_shadow_selectedlight == NULL)
5782 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;
5783 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;
5784 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;
5785 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;
5786 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;
5787 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;
5788 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;
5789 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;
5790 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;
5791 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;
5792 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;
5793 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;
5794 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;
5795 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;
5796 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;
5799 void R_Shadow_EditLights_ToggleShadow_f(void)
5801 if (!r_editlights.integer)
5803 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5806 if (!r_shadow_selectedlight)
5808 Con_Print("No selected light.\n");
5811 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);
5814 void R_Shadow_EditLights_ToggleCorona_f(void)
5816 if (!r_editlights.integer)
5818 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5821 if (!r_shadow_selectedlight)
5823 Con_Print("No selected light.\n");
5826 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);
5829 void R_Shadow_EditLights_Remove_f(void)
5831 if (!r_editlights.integer)
5833 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
5836 if (!r_shadow_selectedlight)
5838 Con_Print("No selected light.\n");
5841 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
5842 r_shadow_selectedlight = NULL;
5845 void R_Shadow_EditLights_Help_f(void)
5848 "Documentation on r_editlights system:\n"
5850 "r_editlights : enable/disable editing mode\n"
5851 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
5852 "r_editlights_cursorpushback : push back cursor this far from surface\n"
5853 "r_editlights_cursorpushoff : push cursor off surface this far\n"
5854 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
5855 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
5857 "r_editlights_help : this help\n"
5858 "r_editlights_clear : remove all lights\n"
5859 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
5860 "r_editlights_save : save to .rtlights file\n"
5861 "r_editlights_spawn : create a light with default settings\n"
5862 "r_editlights_edit command : edit selected light - more documentation below\n"
5863 "r_editlights_remove : remove selected light\n"
5864 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
5865 "r_editlights_importlightentitiesfrommap : reload light entities\n"
5866 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
5868 "origin x y z : set light location\n"
5869 "originx x: set x component of light location\n"
5870 "originy y: set y component of light location\n"
5871 "originz z: set z component of light location\n"
5872 "move x y z : adjust light location\n"
5873 "movex x: adjust x component of light location\n"
5874 "movey y: adjust y component of light location\n"
5875 "movez z: adjust z component of light location\n"
5876 "angles x y z : set light angles\n"
5877 "anglesx x: set x component of light angles\n"
5878 "anglesy y: set y component of light angles\n"
5879 "anglesz z: set z component of light angles\n"
5880 "color r g b : set color of light (can be brighter than 1 1 1)\n"
5881 "radius radius : set radius (size) of light\n"
5882 "colorscale grey : multiply color of light (1 does nothing)\n"
5883 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
5884 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
5885 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
5886 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
5887 "cubemap basename : set filter cubemap of light (not yet supported)\n"
5888 "shadows 1/0 : turn on/off shadows\n"
5889 "corona n : set corona intensity\n"
5890 "coronasize n : set corona size (0-1)\n"
5891 "ambient n : set ambient intensity (0-1)\n"
5892 "diffuse n : set diffuse intensity (0-1)\n"
5893 "specular n : set specular intensity (0-1)\n"
5894 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
5895 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
5896 "<nothing> : print light properties to console\n"
5900 void R_Shadow_EditLights_CopyInfo_f(void)
5902 if (!r_editlights.integer)
5904 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
5907 if (!r_shadow_selectedlight)
5909 Con_Print("No selected light.\n");
5912 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
5913 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
5914 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
5915 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
5916 if (r_shadow_selectedlight->cubemapname)
5917 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
5919 r_shadow_bufferlight.cubemapname[0] = 0;
5920 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
5921 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
5922 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
5923 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
5924 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
5925 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
5926 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
5929 void R_Shadow_EditLights_PasteInfo_f(void)
5931 if (!r_editlights.integer)
5933 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
5936 if (!r_shadow_selectedlight)
5938 Con_Print("No selected light.\n");
5941 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);
5944 void R_Shadow_EditLights_Init(void)
5946 Cvar_RegisterVariable(&r_editlights);
5947 Cvar_RegisterVariable(&r_editlights_cursordistance);
5948 Cvar_RegisterVariable(&r_editlights_cursorpushback);
5949 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
5950 Cvar_RegisterVariable(&r_editlights_cursorgrid);
5951 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
5952 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
5953 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
5954 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)");
5955 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
5956 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
5957 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
5958 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)");
5959 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
5960 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
5961 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
5962 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
5963 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
5964 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
5965 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)");
5971 =============================================================================
5975 =============================================================================
5978 void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, int dynamic)
5980 VectorClear(diffusecolor);
5981 VectorClear(diffusenormal);
5983 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
5985 ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_refdef.scene.ambient * (2.0f / 128.0f);
5986 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
5989 VectorSet(ambientcolor, 1, 1, 1);
5996 for (i = 0;i < r_refdef.scene.numlights;i++)
5998 light = r_refdef.scene.lights[i];
5999 Matrix4x4_Transform(&light->matrix_worldtolight, p, v);
6000 f = 1 - VectorLength2(v);
6001 if (f > 0 && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
6002 VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);