3 Terminology: Stencil Shadow Volume (sometimes called Stencil Shadows)
4 An extrusion of the lit faces, beginning at the original geometry and ending
5 further from the light source than the original geometry (presumably at least
6 as far as the light's radius, if the light has a radius at all), capped at
7 both front and back to avoid any problems (extrusion from dark faces also
8 works but has a different set of problems)
10 This is normally rendered using Carmack's Reverse technique, in which
11 backfaces behind zbuffer (zfail) increment the stencil, and frontfaces behind
12 zbuffer (zfail) decrement the stencil, the result is a stencil value of zero
13 where shadows did not intersect the visible geometry, suitable as a stencil
14 mask for rendering lighting everywhere but shadow.
16 In our case to hopefully avoid the Creative Labs patent, we draw the backfaces
17 as decrement and the frontfaces as increment, and we redefine the DepthFunc to
18 GL_LESS (the patent uses GL_GEQUAL) which causes zfail when behind surfaces
19 and zpass when infront (the patent draws where zpass with a GL_GEQUAL test),
20 additionally we clear stencil to 128 to avoid the need for the unclamped
21 incr/decr extension (not related to patent).
24 This algorithm may be covered by Creative's patent (US Patent #6384822),
25 however that patent is quite specific about increment on backfaces and
26 decrement on frontfaces where zpass with GL_GEQUAL depth test, which is
27 opposite this implementation and partially opposite Carmack's Reverse paper
28 (which uses GL_LESS, but increments on backfaces and decrements on frontfaces).
32 Terminology: Stencil Light Volume (sometimes called Light Volumes)
33 Similar to a Stencil Shadow Volume, but inverted; rather than containing the
34 areas in shadow it contains the areas in light, this can only be built
35 quickly for certain limited cases (such as portal visibility from a point),
36 but is quite useful for some effects (sunlight coming from sky polygons is
37 one possible example, translucent occluders is another example).
41 Terminology: Optimized Stencil Shadow Volume
42 A Stencil Shadow Volume that has been processed sufficiently to ensure it has
43 no duplicate coverage of areas (no need to shadow an area twice), often this
44 greatly improves performance but is an operation too costly to use on moving
45 lights (however completely optimal Stencil Light Volumes can be constructed
50 Terminology: Per Pixel Lighting (sometimes abbreviated PPL)
51 Per pixel evaluation of lighting equations, at a bare minimum this involves
52 DOT3 shading of diffuse lighting (per pixel dotproduct of negated incidence
53 vector and surface normal, using a texture of the surface bumps, called a
54 NormalMap) if supported by hardware; in our case there is support for cards
55 which are incapable of DOT3, the quality is quite poor however. Additionally
56 it is desirable to have specular evaluation per pixel, per vertex
57 normalization of specular halfangle vectors causes noticable distortion but
58 is unavoidable on hardware without GL_ARB_fragment_program or
59 GL_ARB_fragment_shader.
63 Terminology: Normalization CubeMap
64 A cubemap containing normalized dot3-encoded (vectors of length 1 or less
65 encoded as RGB colors) for any possible direction, this technique allows per
66 pixel calculation of incidence vector for per pixel lighting purposes, which
67 would not otherwise be possible per pixel without GL_ARB_fragment_program or
68 GL_ARB_fragment_shader.
72 Terminology: 2D+1D Attenuation Texturing
73 A very crude approximation of light attenuation with distance which results
74 in cylindrical light shapes which fade vertically as a streak (some games
75 such as Doom3 allow this to be rotated to be less noticable in specific
76 cases), the technique is simply modulating lighting by two 2D textures (which
77 can be the same) on different axes of projection (XY and Z, typically), this
78 is the second best technique available without 3D Attenuation Texturing,
79 GL_ARB_fragment_program or GL_ARB_fragment_shader technology.
83 Terminology: 2D+1D Inverse Attenuation Texturing
84 A clever method described in papers on the Abducted engine, this has a squared
85 distance texture (bright on the outside, black in the middle), which is used
86 twice using GL_ADD blending, the result of this is used in an inverse modulate
87 (GL_ONE_MINUS_DST_ALPHA, GL_ZERO) to implement the equation
88 lighting*=(1-((X*X+Y*Y)+(Z*Z))) which is spherical (unlike 2D+1D attenuation
93 Terminology: 3D Attenuation Texturing
94 A slightly crude approximation of light attenuation with distance, its flaws
95 are limited radius and resolution (performance tradeoffs).
99 Terminology: 3D Attenuation-Normalization Texturing
100 A 3D Attenuation Texture merged with a Normalization CubeMap, by making the
101 vectors shorter the lighting becomes darker, a very effective optimization of
102 diffuse lighting if 3D Attenuation Textures are already used.
106 Terminology: Light Cubemap Filtering
107 A technique for modeling non-uniform light distribution according to
108 direction, for example a lantern may use a cubemap to describe the light
109 emission pattern of the cage around the lantern (as well as soot buildup
110 discoloring the light in certain areas), often also used for softened grate
111 shadows and light shining through a stained glass window (done crudely by
112 texturing the lighting with a cubemap), another good example would be a disco
113 light. This technique is used heavily in many games (Doom3 does not support
118 Terminology: Light Projection Filtering
119 A technique for modeling shadowing of light passing through translucent
120 surfaces, allowing stained glass windows and other effects to be done more
121 elegantly than possible with Light Cubemap Filtering by applying an occluder
122 texture to the lighting combined with a stencil light volume to limit the lit
123 area, this technique is used by Doom3 for spotlights and flashlights, among
124 other things, this can also be used more generally to render light passing
125 through multiple translucent occluders in a scene (using a light volume to
126 describe the area beyond the occluder, and thus mask off rendering of all
131 Terminology: Doom3 Lighting
132 A combination of Stencil Shadow Volume, Per Pixel Lighting, Normalization
133 CubeMap, 2D+1D Attenuation Texturing, and Light Projection Filtering, as
134 demonstrated by the game Doom3.
137 #include "quakedef.h"
138 #include "r_shadow.h"
139 #include "cl_collision.h"
143 #define R_SHADOW_SHADOWMAP_NUMCUBEMAPS 8
145 extern void R_Shadow_EditLights_Init(void);
147 typedef enum r_shadow_rendermode_e
149 R_SHADOW_RENDERMODE_NONE,
150 R_SHADOW_RENDERMODE_ZPASS_STENCIL,
151 R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL,
152 R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE,
153 R_SHADOW_RENDERMODE_ZFAIL_STENCIL,
154 R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL,
155 R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE,
156 R_SHADOW_RENDERMODE_LIGHT_VERTEX,
157 R_SHADOW_RENDERMODE_LIGHT_DOT3,
158 R_SHADOW_RENDERMODE_LIGHT_GLSL,
159 R_SHADOW_RENDERMODE_VISIBLEVOLUMES,
160 R_SHADOW_RENDERMODE_VISIBLELIGHTING,
161 R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE,
162 R_SHADOW_RENDERMODE_SHADOWMAP2D,
163 R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE,
165 r_shadow_rendermode_t;
167 r_shadow_rendermode_t r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
168 r_shadow_rendermode_t r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_NONE;
169 r_shadow_rendermode_t r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_NONE;
170 r_shadow_rendermode_t r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_NONE;
171 qboolean r_shadow_usingshadowmaprect;
172 qboolean r_shadow_usingshadowmap2d;
173 qboolean r_shadow_usingshadowmapcube;
174 int r_shadow_shadowmapside;
175 float r_shadow_shadowmap_texturescale[2];
176 float r_shadow_shadowmap_parameters[4];
177 int r_shadow_drawbuffer;
178 int r_shadow_readbuffer;
179 int r_shadow_cullface;
180 GLuint r_shadow_fborectangle;
181 GLuint r_shadow_fbocubeside[R_SHADOW_SHADOWMAP_NUMCUBEMAPS][6];
182 GLuint r_shadow_fbo2d;
183 int r_shadow_shadowmode;
184 int r_shadow_shadowmapfilterquality;
185 int r_shadow_shadowmaptexturetype;
186 int r_shadow_shadowmapprecision;
187 int r_shadow_shadowmapmaxsize;
188 qboolean r_shadow_shadowmapvsdct;
189 qboolean r_shadow_shadowmapsampler;
190 int r_shadow_shadowmappcf;
191 int r_shadow_shadowmapborder;
192 int r_shadow_lightscissor[4];
194 int maxshadowtriangles;
197 int maxshadowvertices;
198 float *shadowvertex3f;
208 unsigned char *shadowsides;
209 int *shadowsideslist;
216 int r_shadow_buffer_numleafpvsbytes;
217 unsigned char *r_shadow_buffer_visitingleafpvs;
218 unsigned char *r_shadow_buffer_leafpvs;
219 int *r_shadow_buffer_leaflist;
221 int r_shadow_buffer_numsurfacepvsbytes;
222 unsigned char *r_shadow_buffer_surfacepvs;
223 int *r_shadow_buffer_surfacelist;
225 int r_shadow_buffer_numshadowtrispvsbytes;
226 unsigned char *r_shadow_buffer_shadowtrispvs;
227 int r_shadow_buffer_numlighttrispvsbytes;
228 unsigned char *r_shadow_buffer_lighttrispvs;
230 rtexturepool_t *r_shadow_texturepool;
231 rtexture_t *r_shadow_attenuationgradienttexture;
232 rtexture_t *r_shadow_attenuation2dtexture;
233 rtexture_t *r_shadow_attenuation3dtexture;
234 rtexture_t *r_shadow_lightcorona;
235 rtexture_t *r_shadow_shadowmaprectangletexture;
236 rtexture_t *r_shadow_shadowmap2dtexture;
237 rtexture_t *r_shadow_shadowmapcubetexture[R_SHADOW_SHADOWMAP_NUMCUBEMAPS];
238 rtexture_t *r_shadow_shadowmapvsdcttexture;
239 int r_shadow_shadowmapsize; // changes for each light based on distance
240 int r_shadow_shadowmaplod; // changes for each light based on distance
242 // lights are reloaded when this changes
243 char r_shadow_mapname[MAX_QPATH];
245 // used only for light filters (cubemaps)
246 rtexturepool_t *r_shadow_filters_texturepool;
248 cvar_t r_shadow_bumpscale_basetexture = {0, "r_shadow_bumpscale_basetexture", "0", "generate fake bumpmaps from diffuse textures at this bumpyness, try 4 to match tenebrae, higher values increase depth, requires r_restart to take effect"};
249 cvar_t r_shadow_bumpscale_bumpmap = {0, "r_shadow_bumpscale_bumpmap", "4", "what magnitude to interpret _bump.tga textures as, higher values increase depth, requires r_restart to take effect"};
250 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
251 cvar_t r_shadow_usenormalmap = {CVAR_SAVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"};
252 cvar_t r_shadow_gloss = {CVAR_SAVE, "r_shadow_gloss", "1", "0 disables gloss (specularity) rendering, 1 uses gloss if textures are found, 2 forces a flat metallic specular effect on everything without textures (similar to tenebrae)"};
253 cvar_t r_shadow_gloss2intensity = {0, "r_shadow_gloss2intensity", "0.125", "how bright the forced flat gloss should look if r_shadow_gloss is 2"};
254 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
255 cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
256 cvar_t r_shadow_gloss2exponent = {0, "r_shadow_gloss2exponent", "32", "same as r_shadow_glossexponent but for forced gloss (gloss 2) surfaces"};
257 cvar_t r_shadow_glossexact = {0, "r_shadow_glossexact", "0", "use exact reflection math for gloss (slightly slower, but should look a tad better)"};
258 cvar_t r_shadow_lightattenuationdividebias = {0, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"};
259 cvar_t r_shadow_lightattenuationlinearscale = {0, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"};
260 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
261 cvar_t r_shadow_lightradiusscale = {0, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
262 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1", "use portal culling to exactly determine lit triangles when compiling world lights"};
263 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000", "how far to cast shadows"};
264 cvar_t r_shadow_frontsidecasting = {0, "r_shadow_frontsidecasting", "1", "whether to cast shadows from illuminated triangles (front side of model) or unlit triangles (back side of model)"};
265 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
266 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
267 cvar_t r_shadow_realtime_dlight_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
268 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
269 cvar_t r_shadow_realtime_world = {CVAR_SAVE, "r_shadow_realtime_world", "0", "enables rendering of full world lighting (whether loaded from the map, or a .rtlights file, or a .ent file, or a .lights file produced by hlight)"};
270 cvar_t r_shadow_realtime_world_lightmaps = {CVAR_SAVE, "r_shadow_realtime_world_lightmaps", "0", "brightness to render lightmaps when using full world lighting, try 0.5 for a tenebrae-like appearance"};
271 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
272 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
273 cvar_t r_shadow_realtime_world_compileshadow = {0, "r_shadow_realtime_world_compileshadow", "1", "enables compilation of shadows from world lights for higher performance rendering"};
274 cvar_t r_shadow_realtime_world_compilesvbsp = {0, "r_shadow_realtime_world_compilesvbsp", "1", "enables svbsp optimization during compilation"};
275 cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "1", "enables portal-based culling optimization during compilation"};
276 cvar_t r_shadow_scissor = {0, "r_shadow_scissor", "1", "use scissor optimization of light rendering (restricts rendering to the portion of the screen affected by the light)"};
277 cvar_t r_shadow_shadowmapping = {CVAR_SAVE, "r_shadow_shadowmapping", "0", "enables use of shadowmapping (depth texture sampling) instead of stencil shadow volumes, requires gl_fbo 1"};
278 cvar_t r_shadow_shadowmapping_texturetype = {CVAR_SAVE, "r_shadow_shadowmapping_texturetype", "0", "shadowmap texture types: 0 = auto-select, 1 = 2D, 2 = rectangle, 3 = cubemap"};
279 cvar_t r_shadow_shadowmapping_filterquality = {CVAR_SAVE, "r_shadow_shadowmapping_filterquality", "-1", "shadowmap filter modes: -1 = auto-select, 0 = no filtering, 1 = bilinear, 2 = bilinear 2x2 blur (fast), 3 = 3x3 blur (moderate), 4 = 4x4 blur (slow)"};
280 cvar_t r_shadow_shadowmapping_precision = {CVAR_SAVE, "r_shadow_shadowmapping_precision", "24", "requested minimum shadowmap texture precision"};
281 cvar_t r_shadow_shadowmapping_vsdct = {CVAR_SAVE, "r_shadow_shadowmapping_vsdct", "1", "enables use of virtual shadow depth cube texture"};
282 cvar_t r_shadow_shadowmapping_minsize = {CVAR_SAVE, "r_shadow_shadowmapping_minsize", "32", "shadowmap size limit"};
283 cvar_t r_shadow_shadowmapping_maxsize = {CVAR_SAVE, "r_shadow_shadowmapping_maxsize", "512", "shadowmap size limit"};
284 cvar_t r_shadow_shadowmapping_lod_bias = {CVAR_SAVE, "r_shadow_shadowmapping_lod_bias", "16", "shadowmap size bias"};
285 cvar_t r_shadow_shadowmapping_lod_scale = {CVAR_SAVE, "r_shadow_shadowmapping_lod_scale", "128", "shadowmap size scaling parameter"};
286 cvar_t r_shadow_shadowmapping_bordersize = {CVAR_SAVE, "r_shadow_shadowmapping_bordersize", "4", "shadowmap size bias for filtering"};
287 cvar_t r_shadow_shadowmapping_nearclip = {CVAR_SAVE, "r_shadow_shadowmapping_nearclip", "1", "shadowmap nearclip in world units"};
288 cvar_t r_shadow_shadowmapping_bias = {CVAR_SAVE, "r_shadow_shadowmapping_bias", "0.03", "shadowmap bias parameter (this is multiplied by nearclip * 1024 / lodsize)"};
289 cvar_t r_shadow_culltriangles = {0, "r_shadow_culltriangles", "1", "performs more expensive tests to remove unnecessary triangles of lit surfaces"};
290 cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
291 cvar_t r_shadow_polygonoffset = {0, "r_shadow_polygonoffset", "1", "how much to push shadow volumes into the distance when rendering, to reduce chances of zfighting artifacts (should not be less than 0)"};
292 cvar_t r_shadow_texture3d = {0, "r_shadow_texture3d", "1", "use 3D voxel textures for spherical attenuation rather than cylindrical (does not affect r_glsl lighting)"};
293 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "1", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
294 cvar_t r_coronas_occlusionsizescale = {CVAR_SAVE, "r_coronas_occlusionsizescale", "0.1", "size of light source for corona occlusion checksm the proportion of hidden pixels controls corona intensity"};
295 cvar_t r_coronas_occlusionquery = {CVAR_SAVE, "r_coronas_occlusionquery", "1", "use GL_ARB_occlusion_query extension if supported (fades coronas according to visibility)"};
296 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
297 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
298 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
299 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
300 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
301 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
302 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
303 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
304 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
306 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
307 #define ATTENTABLESIZE 256
308 // 1D gradient, 2D circle and 3D sphere attenuation textures
309 #define ATTEN1DSIZE 32
310 #define ATTEN2DSIZE 64
311 #define ATTEN3DSIZE 32
313 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
314 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
315 static float r_shadow_attentable[ATTENTABLESIZE+1];
317 rtlight_t *r_shadow_compilingrtlight;
318 static memexpandablearray_t r_shadow_worldlightsarray;
319 dlight_t *r_shadow_selectedlight;
320 dlight_t r_shadow_bufferlight;
321 vec3_t r_editlights_cursorlocation;
323 extern int con_vislines;
325 typedef struct cubemapinfo_s
332 #define MAX_CUBEMAPS 256
333 static int numcubemaps;
334 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
336 void R_Shadow_UncompileWorldLights(void);
337 void R_Shadow_ClearWorldLights(void);
338 void R_Shadow_SaveWorldLights(void);
339 void R_Shadow_LoadWorldLights(void);
340 void R_Shadow_LoadLightsFile(void);
341 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
342 void R_Shadow_EditLights_Reload_f(void);
343 void R_Shadow_ValidateCvars(void);
344 static void R_Shadow_MakeTextures(void);
346 // VorteX: custom editor light sprites
347 #define EDLIGHTSPRSIZE 8
348 cachepic_t *r_editlights_sprcursor;
349 cachepic_t *r_editlights_sprlight;
350 cachepic_t *r_editlights_sprnoshadowlight;
351 cachepic_t *r_editlights_sprcubemaplight;
352 cachepic_t *r_editlights_sprcubemapnoshadowlight;
353 cachepic_t *r_editlights_sprselection;
355 void R_Shadow_SetShadowMode(void)
357 r_shadow_shadowmapmaxsize = bound(1, r_shadow_shadowmapping_maxsize.integer, 2048);
358 r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer != 0;
359 r_shadow_shadowmapfilterquality = r_shadow_shadowmapping_filterquality.integer;
360 r_shadow_shadowmaptexturetype = r_shadow_shadowmapping_texturetype.integer;
361 r_shadow_shadowmapprecision = r_shadow_shadowmapping_precision.integer;
362 r_shadow_shadowmapborder = bound(0, r_shadow_shadowmapping_bordersize.integer, 16);
363 r_shadow_shadowmaplod = -1;
364 r_shadow_shadowmapsize = 0;
365 r_shadow_shadowmapsampler = false;
366 r_shadow_shadowmappcf = 0;
367 r_shadow_shadowmode = 0;
368 if(r_shadow_shadowmapping.integer)
370 if(r_shadow_shadowmapfilterquality < 0)
372 if(strstr(gl_vendor, "NVIDIA"))
374 r_shadow_shadowmapsampler = gl_support_arb_shadow;
375 r_shadow_shadowmappcf = 1;
377 else if(gl_support_amd_texture_texture4 || gl_support_arb_texture_gather)
378 r_shadow_shadowmappcf = 1;
379 else if(strstr(gl_vendor, "ATI"))
380 r_shadow_shadowmappcf = 1;
382 r_shadow_shadowmapsampler = gl_support_arb_shadow;
386 switch (r_shadow_shadowmapfilterquality)
389 r_shadow_shadowmapsampler = gl_support_arb_shadow;
392 r_shadow_shadowmapsampler = gl_support_arb_shadow;
393 r_shadow_shadowmappcf = 1;
396 r_shadow_shadowmappcf = 1;
399 r_shadow_shadowmappcf = 2;
403 r_shadow_shadowmode = r_shadow_shadowmaptexturetype;
404 if(r_shadow_shadowmode <= 0)
406 if((gl_support_amd_texture_texture4 || gl_support_arb_texture_gather) && r_shadow_shadowmappcf && !r_shadow_shadowmapsampler)
407 r_shadow_shadowmode = 1;
408 else if(gl_texturerectangle)
409 r_shadow_shadowmode = 2;
411 r_shadow_shadowmode = 1;
416 void R_Shadow_FreeShadowMaps(void)
420 R_Shadow_SetShadowMode();
422 if (r_shadow_fborectangle)
423 qglDeleteFramebuffersEXT(1, &r_shadow_fborectangle);
424 r_shadow_fborectangle = 0;
428 qglDeleteFramebuffersEXT(1, &r_shadow_fbo2d);
431 for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
432 if (r_shadow_fbocubeside[i][0])
433 qglDeleteFramebuffersEXT(6, r_shadow_fbocubeside[i]);
434 memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
437 if (r_shadow_shadowmaprectangletexture)
438 R_FreeTexture(r_shadow_shadowmaprectangletexture);
439 r_shadow_shadowmaprectangletexture = NULL;
441 if (r_shadow_shadowmap2dtexture)
442 R_FreeTexture(r_shadow_shadowmap2dtexture);
443 r_shadow_shadowmap2dtexture = NULL;
445 for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
446 if (r_shadow_shadowmapcubetexture[i])
447 R_FreeTexture(r_shadow_shadowmapcubetexture[i]);
448 memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
450 if (r_shadow_shadowmapvsdcttexture)
451 R_FreeTexture(r_shadow_shadowmapvsdcttexture);
452 r_shadow_shadowmapvsdcttexture = NULL;
457 void r_shadow_start(void)
459 // allocate vertex processing arrays
461 r_shadow_attenuationgradienttexture = NULL;
462 r_shadow_attenuation2dtexture = NULL;
463 r_shadow_attenuation3dtexture = NULL;
464 r_shadow_shadowmode = 0;
465 r_shadow_shadowmaprectangletexture = NULL;
466 r_shadow_shadowmap2dtexture = NULL;
467 memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
468 r_shadow_shadowmapvsdcttexture = NULL;
469 r_shadow_shadowmapmaxsize = 0;
470 r_shadow_shadowmapsize = 0;
471 r_shadow_shadowmaplod = 0;
472 r_shadow_shadowmapfilterquality = 0;
473 r_shadow_shadowmaptexturetype = 0;
474 r_shadow_shadowmapprecision = 0;
475 r_shadow_shadowmapvsdct = false;
476 r_shadow_shadowmapsampler = false;
477 r_shadow_shadowmappcf = 0;
478 r_shadow_fborectangle = 0;
480 memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
482 R_Shadow_FreeShadowMaps();
484 r_shadow_texturepool = NULL;
485 r_shadow_filters_texturepool = NULL;
486 R_Shadow_ValidateCvars();
487 R_Shadow_MakeTextures();
488 maxshadowtriangles = 0;
489 shadowelements = NULL;
490 maxshadowvertices = 0;
491 shadowvertex3f = NULL;
499 shadowmarklist = NULL;
504 shadowsideslist = NULL;
505 r_shadow_buffer_numleafpvsbytes = 0;
506 r_shadow_buffer_visitingleafpvs = NULL;
507 r_shadow_buffer_leafpvs = NULL;
508 r_shadow_buffer_leaflist = NULL;
509 r_shadow_buffer_numsurfacepvsbytes = 0;
510 r_shadow_buffer_surfacepvs = NULL;
511 r_shadow_buffer_surfacelist = NULL;
512 r_shadow_buffer_numshadowtrispvsbytes = 0;
513 r_shadow_buffer_shadowtrispvs = NULL;
514 r_shadow_buffer_numlighttrispvsbytes = 0;
515 r_shadow_buffer_lighttrispvs = NULL;
518 void r_shadow_shutdown(void)
521 R_Shadow_UncompileWorldLights();
523 R_Shadow_FreeShadowMaps();
527 r_shadow_attenuationgradienttexture = NULL;
528 r_shadow_attenuation2dtexture = NULL;
529 r_shadow_attenuation3dtexture = NULL;
530 R_FreeTexturePool(&r_shadow_texturepool);
531 R_FreeTexturePool(&r_shadow_filters_texturepool);
532 maxshadowtriangles = 0;
534 Mem_Free(shadowelements);
535 shadowelements = NULL;
537 Mem_Free(shadowvertex3f);
538 shadowvertex3f = NULL;
541 Mem_Free(vertexupdate);
544 Mem_Free(vertexremap);
550 Mem_Free(shadowmark);
553 Mem_Free(shadowmarklist);
554 shadowmarklist = NULL;
559 Mem_Free(shadowsides);
562 Mem_Free(shadowsideslist);
563 shadowsideslist = NULL;
564 r_shadow_buffer_numleafpvsbytes = 0;
565 if (r_shadow_buffer_visitingleafpvs)
566 Mem_Free(r_shadow_buffer_visitingleafpvs);
567 r_shadow_buffer_visitingleafpvs = NULL;
568 if (r_shadow_buffer_leafpvs)
569 Mem_Free(r_shadow_buffer_leafpvs);
570 r_shadow_buffer_leafpvs = NULL;
571 if (r_shadow_buffer_leaflist)
572 Mem_Free(r_shadow_buffer_leaflist);
573 r_shadow_buffer_leaflist = NULL;
574 r_shadow_buffer_numsurfacepvsbytes = 0;
575 if (r_shadow_buffer_surfacepvs)
576 Mem_Free(r_shadow_buffer_surfacepvs);
577 r_shadow_buffer_surfacepvs = NULL;
578 if (r_shadow_buffer_surfacelist)
579 Mem_Free(r_shadow_buffer_surfacelist);
580 r_shadow_buffer_surfacelist = NULL;
581 r_shadow_buffer_numshadowtrispvsbytes = 0;
582 if (r_shadow_buffer_shadowtrispvs)
583 Mem_Free(r_shadow_buffer_shadowtrispvs);
584 r_shadow_buffer_numlighttrispvsbytes = 0;
585 if (r_shadow_buffer_lighttrispvs)
586 Mem_Free(r_shadow_buffer_lighttrispvs);
589 void r_shadow_newmap(void)
591 if (cl.worldmodel && strncmp(cl.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
592 R_Shadow_EditLights_Reload_f();
595 void R_Shadow_Help_f(void)
598 "Documentation on r_shadow system:\n"
600 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
601 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
602 "r_shadow_debuglight : render only this light number (-1 = all)\n"
603 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
604 "r_shadow_gloss2intensity : brightness of forced gloss\n"
605 "r_shadow_glossintensity : brightness of textured gloss\n"
606 "r_shadow_lightattenuationlinearscale : used to generate attenuation texture\n"
607 "r_shadow_lightattenuationdividebias : used to generate attenuation texture\n"
608 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
609 "r_shadow_lightradiusscale : scale rendering radius of all lights\n"
610 "r_shadow_portallight : use portal visibility for static light precomputation\n"
611 "r_shadow_projectdistance : shadow volume projection distance\n"
612 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
613 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
614 "r_shadow_realtime_world : use high quality world lighting mode\n"
615 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
616 "r_shadow_realtime_world_shadows : cast shadows from world lights\n"
617 "r_shadow_realtime_world_compile : compile surface/visibility information\n"
618 "r_shadow_realtime_world_compileshadow : compile shadow geometry\n"
619 "r_shadow_scissor : use scissor optimization\n"
620 "r_shadow_polygonfactor : nudge shadow volumes closer/further\n"
621 "r_shadow_polygonoffset : nudge shadow volumes closer/further\n"
622 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
623 "r_showlighting : useful for performance testing; bright = slow!\n"
624 "r_showshadowvolumes : useful for performance testing; bright = slow!\n"
626 "r_shadow_help : this help\n"
630 void R_Shadow_Init(void)
632 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
633 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
634 Cvar_RegisterVariable(&r_shadow_usenormalmap);
635 Cvar_RegisterVariable(&r_shadow_debuglight);
636 Cvar_RegisterVariable(&r_shadow_gloss);
637 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
638 Cvar_RegisterVariable(&r_shadow_glossintensity);
639 Cvar_RegisterVariable(&r_shadow_glossexponent);
640 Cvar_RegisterVariable(&r_shadow_gloss2exponent);
641 Cvar_RegisterVariable(&r_shadow_glossexact);
642 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
643 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
644 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
645 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
646 Cvar_RegisterVariable(&r_shadow_portallight);
647 Cvar_RegisterVariable(&r_shadow_projectdistance);
648 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
649 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
650 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
651 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
652 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
653 Cvar_RegisterVariable(&r_shadow_realtime_world);
654 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
655 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
656 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
657 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
658 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
659 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
660 Cvar_RegisterVariable(&r_shadow_scissor);
661 Cvar_RegisterVariable(&r_shadow_shadowmapping);
662 Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
663 Cvar_RegisterVariable(&r_shadow_shadowmapping_texturetype);
664 Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
665 Cvar_RegisterVariable(&r_shadow_shadowmapping_precision);
666 Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
667 Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
668 Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
669 Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
670 Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
671 Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
672 Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
673 Cvar_RegisterVariable(&r_shadow_culltriangles);
674 Cvar_RegisterVariable(&r_shadow_polygonfactor);
675 Cvar_RegisterVariable(&r_shadow_polygonoffset);
676 Cvar_RegisterVariable(&r_shadow_texture3d);
677 Cvar_RegisterVariable(&r_coronas);
678 Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
679 Cvar_RegisterVariable(&r_coronas_occlusionquery);
680 Cvar_RegisterVariable(&gl_flashblend);
681 Cvar_RegisterVariable(&gl_ext_separatestencil);
682 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
683 if (gamemode == GAME_TENEBRAE)
685 Cvar_SetValue("r_shadow_gloss", 2);
686 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
688 Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f, "prints documentation on console commands and variables used by realtime lighting and shadowing system");
689 R_Shadow_EditLights_Init();
690 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
691 maxshadowtriangles = 0;
692 shadowelements = NULL;
693 maxshadowvertices = 0;
694 shadowvertex3f = NULL;
702 shadowmarklist = NULL;
707 shadowsideslist = NULL;
708 r_shadow_buffer_numleafpvsbytes = 0;
709 r_shadow_buffer_visitingleafpvs = NULL;
710 r_shadow_buffer_leafpvs = NULL;
711 r_shadow_buffer_leaflist = NULL;
712 r_shadow_buffer_numsurfacepvsbytes = 0;
713 r_shadow_buffer_surfacepvs = NULL;
714 r_shadow_buffer_surfacelist = NULL;
715 r_shadow_buffer_shadowtrispvs = NULL;
716 r_shadow_buffer_lighttrispvs = NULL;
717 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
720 matrix4x4_t matrix_attenuationxyz =
723 {0.5, 0.0, 0.0, 0.5},
724 {0.0, 0.5, 0.0, 0.5},
725 {0.0, 0.0, 0.5, 0.5},
730 matrix4x4_t matrix_attenuationz =
733 {0.0, 0.0, 0.5, 0.5},
734 {0.0, 0.0, 0.0, 0.5},
735 {0.0, 0.0, 0.0, 0.5},
740 void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles, int vertscale, int triscale)
742 numvertices = ((numvertices + 255) & ~255) * vertscale;
743 numtriangles = ((numtriangles + 255) & ~255) * triscale;
744 // make sure shadowelements is big enough for this volume
745 if (maxshadowtriangles < numtriangles)
747 maxshadowtriangles = numtriangles;
749 Mem_Free(shadowelements);
750 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[3]));
752 // make sure shadowvertex3f is big enough for this volume
753 if (maxshadowvertices < numvertices)
755 maxshadowvertices = numvertices;
757 Mem_Free(shadowvertex3f);
758 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[3]));
762 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
764 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
765 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
766 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
767 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
768 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
770 if (r_shadow_buffer_visitingleafpvs)
771 Mem_Free(r_shadow_buffer_visitingleafpvs);
772 if (r_shadow_buffer_leafpvs)
773 Mem_Free(r_shadow_buffer_leafpvs);
774 if (r_shadow_buffer_leaflist)
775 Mem_Free(r_shadow_buffer_leaflist);
776 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
777 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
778 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
779 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
781 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
783 if (r_shadow_buffer_surfacepvs)
784 Mem_Free(r_shadow_buffer_surfacepvs);
785 if (r_shadow_buffer_surfacelist)
786 Mem_Free(r_shadow_buffer_surfacelist);
787 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
788 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
789 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
791 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
793 if (r_shadow_buffer_shadowtrispvs)
794 Mem_Free(r_shadow_buffer_shadowtrispvs);
795 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
796 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
798 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
800 if (r_shadow_buffer_lighttrispvs)
801 Mem_Free(r_shadow_buffer_lighttrispvs);
802 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
803 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
807 void R_Shadow_PrepareShadowMark(int numtris)
809 // make sure shadowmark is big enough for this volume
810 if (maxshadowmark < numtris)
812 maxshadowmark = numtris;
814 Mem_Free(shadowmark);
816 Mem_Free(shadowmarklist);
817 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
818 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
822 // if shadowmarkcount wrapped we clear the array and adjust accordingly
823 if (shadowmarkcount == 0)
826 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
831 void R_Shadow_PrepareShadowSides(int numtris)
833 if (maxshadowsides < numtris)
835 maxshadowsides = numtris;
837 Mem_Free(shadowsides);
839 Mem_Free(shadowsideslist);
840 shadowsides = (unsigned char *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsides));
841 shadowsideslist = (int *)Mem_Alloc(r_main_mempool, maxshadowsides * sizeof(*shadowsideslist));
846 static int R_Shadow_ConstructShadowVolume_ZFail(int innumvertices, int innumtris, const int *inelement3i, const int *inneighbor3i, const float *invertex3f, int *outnumvertices, int *outelement3i, float *outvertex3f, const float *projectorigin, const float *projectdirection, float projectdistance, int numshadowmarktris, const int *shadowmarktris)
849 int outtriangles = 0, outvertices = 0;
852 float ratio, direction[3], projectvector[3];
854 if (projectdirection)
855 VectorScale(projectdirection, projectdistance, projectvector);
857 VectorClear(projectvector);
859 // create the vertices
860 if (projectdirection)
862 for (i = 0;i < numshadowmarktris;i++)
864 element = inelement3i + shadowmarktris[i] * 3;
865 for (j = 0;j < 3;j++)
867 if (vertexupdate[element[j]] != vertexupdatenum)
869 vertexupdate[element[j]] = vertexupdatenum;
870 vertexremap[element[j]] = outvertices;
871 vertex = invertex3f + element[j] * 3;
872 // project one copy of the vertex according to projectvector
873 VectorCopy(vertex, outvertex3f);
874 VectorAdd(vertex, projectvector, (outvertex3f + 3));
883 for (i = 0;i < numshadowmarktris;i++)
885 element = inelement3i + shadowmarktris[i] * 3;
886 for (j = 0;j < 3;j++)
888 if (vertexupdate[element[j]] != vertexupdatenum)
890 vertexupdate[element[j]] = vertexupdatenum;
891 vertexremap[element[j]] = outvertices;
892 vertex = invertex3f + element[j] * 3;
893 // project one copy of the vertex to the sphere radius of the light
894 // (FIXME: would projecting it to the light box be better?)
895 VectorSubtract(vertex, projectorigin, direction);
896 ratio = projectdistance / VectorLength(direction);
897 VectorCopy(vertex, outvertex3f);
898 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
906 if (r_shadow_frontsidecasting.integer)
908 for (i = 0;i < numshadowmarktris;i++)
910 int remappedelement[3];
912 const int *neighbortriangle;
914 markindex = shadowmarktris[i] * 3;
915 element = inelement3i + markindex;
916 neighbortriangle = inneighbor3i + markindex;
917 // output the front and back triangles
918 outelement3i[0] = vertexremap[element[0]];
919 outelement3i[1] = vertexremap[element[1]];
920 outelement3i[2] = vertexremap[element[2]];
921 outelement3i[3] = vertexremap[element[2]] + 1;
922 outelement3i[4] = vertexremap[element[1]] + 1;
923 outelement3i[5] = vertexremap[element[0]] + 1;
927 // output the sides (facing outward from this triangle)
928 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
930 remappedelement[0] = vertexremap[element[0]];
931 remappedelement[1] = vertexremap[element[1]];
932 outelement3i[0] = remappedelement[1];
933 outelement3i[1] = remappedelement[0];
934 outelement3i[2] = remappedelement[0] + 1;
935 outelement3i[3] = remappedelement[1];
936 outelement3i[4] = remappedelement[0] + 1;
937 outelement3i[5] = remappedelement[1] + 1;
942 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
944 remappedelement[1] = vertexremap[element[1]];
945 remappedelement[2] = vertexremap[element[2]];
946 outelement3i[0] = remappedelement[2];
947 outelement3i[1] = remappedelement[1];
948 outelement3i[2] = remappedelement[1] + 1;
949 outelement3i[3] = remappedelement[2];
950 outelement3i[4] = remappedelement[1] + 1;
951 outelement3i[5] = remappedelement[2] + 1;
956 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
958 remappedelement[0] = vertexremap[element[0]];
959 remappedelement[2] = vertexremap[element[2]];
960 outelement3i[0] = remappedelement[0];
961 outelement3i[1] = remappedelement[2];
962 outelement3i[2] = remappedelement[2] + 1;
963 outelement3i[3] = remappedelement[0];
964 outelement3i[4] = remappedelement[2] + 1;
965 outelement3i[5] = remappedelement[0] + 1;
974 for (i = 0;i < numshadowmarktris;i++)
976 int remappedelement[3];
978 const int *neighbortriangle;
980 markindex = shadowmarktris[i] * 3;
981 element = inelement3i + markindex;
982 neighbortriangle = inneighbor3i + markindex;
983 // output the front and back triangles
984 outelement3i[0] = vertexremap[element[2]];
985 outelement3i[1] = vertexremap[element[1]];
986 outelement3i[2] = vertexremap[element[0]];
987 outelement3i[3] = vertexremap[element[0]] + 1;
988 outelement3i[4] = vertexremap[element[1]] + 1;
989 outelement3i[5] = vertexremap[element[2]] + 1;
993 // output the sides (facing outward from this triangle)
994 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
996 remappedelement[0] = vertexremap[element[0]];
997 remappedelement[1] = vertexremap[element[1]];
998 outelement3i[0] = remappedelement[0];
999 outelement3i[1] = remappedelement[1];
1000 outelement3i[2] = remappedelement[1] + 1;
1001 outelement3i[3] = remappedelement[0];
1002 outelement3i[4] = remappedelement[1] + 1;
1003 outelement3i[5] = remappedelement[0] + 1;
1008 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
1010 remappedelement[1] = vertexremap[element[1]];
1011 remappedelement[2] = vertexremap[element[2]];
1012 outelement3i[0] = remappedelement[1];
1013 outelement3i[1] = remappedelement[2];
1014 outelement3i[2] = remappedelement[2] + 1;
1015 outelement3i[3] = remappedelement[1];
1016 outelement3i[4] = remappedelement[2] + 1;
1017 outelement3i[5] = remappedelement[1] + 1;
1022 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
1024 remappedelement[0] = vertexremap[element[0]];
1025 remappedelement[2] = vertexremap[element[2]];
1026 outelement3i[0] = remappedelement[2];
1027 outelement3i[1] = remappedelement[0];
1028 outelement3i[2] = remappedelement[0] + 1;
1029 outelement3i[3] = remappedelement[2];
1030 outelement3i[4] = remappedelement[0] + 1;
1031 outelement3i[5] = remappedelement[2] + 1;
1039 *outnumvertices = outvertices;
1040 return outtriangles;
1043 static int R_Shadow_ConstructShadowVolume_ZPass(int innumvertices, int innumtris, const int *inelement3i, const int *inneighbor3i, const float *invertex3f, int *outnumvertices, int *outelement3i, float *outvertex3f, const float *projectorigin, const float *projectdirection, float projectdistance, int numshadowmarktris, const int *shadowmarktris)
1046 int outtriangles = 0, outvertices = 0;
1048 const float *vertex;
1049 float ratio, direction[3], projectvector[3];
1052 if (projectdirection)
1053 VectorScale(projectdirection, projectdistance, projectvector);
1055 VectorClear(projectvector);
1057 for (i = 0;i < numshadowmarktris;i++)
1059 int remappedelement[3];
1061 const int *neighbortriangle;
1063 markindex = shadowmarktris[i] * 3;
1064 neighbortriangle = inneighbor3i + markindex;
1065 side[0] = shadowmark[neighbortriangle[0]] == shadowmarkcount;
1066 side[1] = shadowmark[neighbortriangle[1]] == shadowmarkcount;
1067 side[2] = shadowmark[neighbortriangle[2]] == shadowmarkcount;
1068 if (side[0] + side[1] + side[2] == 0)
1072 element = inelement3i + markindex;
1074 // create the vertices
1075 for (j = 0;j < 3;j++)
1077 if (side[j] + side[j+1] == 0)
1080 if (vertexupdate[k] != vertexupdatenum)
1082 vertexupdate[k] = vertexupdatenum;
1083 vertexremap[k] = outvertices;
1084 vertex = invertex3f + k * 3;
1085 VectorCopy(vertex, outvertex3f);
1086 if (projectdirection)
1088 // project one copy of the vertex according to projectvector
1089 VectorAdd(vertex, projectvector, (outvertex3f + 3));
1093 // project one copy of the vertex to the sphere radius of the light
1094 // (FIXME: would projecting it to the light box be better?)
1095 VectorSubtract(vertex, projectorigin, direction);
1096 ratio = projectdistance / VectorLength(direction);
1097 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1104 // output the sides (facing outward from this triangle)
1107 remappedelement[0] = vertexremap[element[0]];
1108 remappedelement[1] = vertexremap[element[1]];
1109 outelement3i[0] = remappedelement[1];
1110 outelement3i[1] = remappedelement[0];
1111 outelement3i[2] = remappedelement[0] + 1;
1112 outelement3i[3] = remappedelement[1];
1113 outelement3i[4] = remappedelement[0] + 1;
1114 outelement3i[5] = remappedelement[1] + 1;
1121 remappedelement[1] = vertexremap[element[1]];
1122 remappedelement[2] = vertexremap[element[2]];
1123 outelement3i[0] = remappedelement[2];
1124 outelement3i[1] = remappedelement[1];
1125 outelement3i[2] = remappedelement[1] + 1;
1126 outelement3i[3] = remappedelement[2];
1127 outelement3i[4] = remappedelement[1] + 1;
1128 outelement3i[5] = remappedelement[2] + 1;
1135 remappedelement[0] = vertexremap[element[0]];
1136 remappedelement[2] = vertexremap[element[2]];
1137 outelement3i[0] = remappedelement[0];
1138 outelement3i[1] = remappedelement[2];
1139 outelement3i[2] = remappedelement[2] + 1;
1140 outelement3i[3] = remappedelement[0];
1141 outelement3i[4] = remappedelement[2] + 1;
1142 outelement3i[5] = remappedelement[0] + 1;
1149 *outnumvertices = outvertices;
1150 return outtriangles;
1153 void R_Shadow_MarkVolumeFromBox(int firsttriangle, int numtris, const float *invertex3f, const int *elements, const vec3_t projectorigin, const vec3_t projectdirection, const vec3_t lightmins, const vec3_t lightmaxs, const vec3_t surfacemins, const vec3_t surfacemaxs)
1159 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1161 tend = firsttriangle + numtris;
1162 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1164 // surface box entirely inside light box, no box cull
1165 if (projectdirection)
1167 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1169 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
1170 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1171 shadowmarklist[numshadowmark++] = t;
1176 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1177 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
1178 shadowmarklist[numshadowmark++] = t;
1183 // surface box not entirely inside light box, cull each triangle
1184 if (projectdirection)
1186 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1188 v[0] = invertex3f + e[0] * 3;
1189 v[1] = invertex3f + e[1] * 3;
1190 v[2] = invertex3f + e[2] * 3;
1191 TriangleNormal(v[0], v[1], v[2], normal);
1192 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1193 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1194 shadowmarklist[numshadowmark++] = t;
1199 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1201 v[0] = invertex3f + e[0] * 3;
1202 v[1] = invertex3f + e[1] * 3;
1203 v[2] = invertex3f + e[2] * 3;
1204 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1205 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1206 shadowmarklist[numshadowmark++] = t;
1212 qboolean R_Shadow_UseZPass(vec3_t mins, vec3_t maxs)
1217 if (r_shadow_compilingrtlight || !r_shadow_frontsidecasting.integer || !r_shadow_usezpassifpossible.integer)
1219 // check if the shadow volume intersects the near plane
1221 // a ray between the eye and light origin may intersect the caster,
1222 // indicating that the shadow may touch the eye location, however we must
1223 // test the near plane (a polygon), not merely the eye location, so it is
1224 // easiest to enlarge the caster bounding shape slightly for this.
1230 void R_Shadow_VolumeFromList(int numverts, int numtris, const float *invertex3f, const int *elements, const int *neighbors, const vec3_t projectorigin, const vec3_t projectdirection, float projectdistance, int nummarktris, const int *marktris, vec3_t trismins, vec3_t trismaxs)
1232 int i, tris, outverts;
1233 if (projectdistance < 0.1)
1235 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
1238 if (!numverts || !nummarktris)
1240 // make sure shadowelements is big enough for this volume
1241 if (maxshadowtriangles < nummarktris*8 || maxshadowvertices < numverts*2)
1242 R_Shadow_ResizeShadowArrays(numverts, nummarktris, 2, 8);
1244 if (maxvertexupdate < numverts)
1246 maxvertexupdate = numverts;
1248 Mem_Free(vertexupdate);
1250 Mem_Free(vertexremap);
1251 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1252 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1253 vertexupdatenum = 0;
1256 if (vertexupdatenum == 0)
1258 vertexupdatenum = 1;
1259 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
1260 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
1263 for (i = 0;i < nummarktris;i++)
1264 shadowmark[marktris[i]] = shadowmarkcount;
1266 if (r_shadow_compilingrtlight)
1268 // if we're compiling an rtlight, capture the mesh
1269 //tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1270 //Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zpass, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1271 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1272 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zfail, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1276 // decide which type of shadow to generate and set stencil mode
1277 R_Shadow_RenderMode_StencilShadowVolumes(R_Shadow_UseZPass(trismins, trismaxs));
1278 // generate the sides or a solid volume, depending on type
1279 if (r_shadow_rendermode >= R_SHADOW_RENDERMODE_ZPASS_STENCIL && r_shadow_rendermode <= R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE)
1280 tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1282 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1283 r_refdef.stats.lights_dynamicshadowtriangles += tris;
1284 r_refdef.stats.lights_shadowtriangles += tris;
1286 R_Mesh_VertexPointer(shadowvertex3f, 0, 0);
1287 GL_LockArrays(0, outverts);
1288 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
1290 // increment stencil if frontface is infront of depthbuffer
1291 GL_CullFace(r_refdef.view.cullface_front);
1292 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1293 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1294 // decrement stencil if backface is infront of depthbuffer
1295 GL_CullFace(r_refdef.view.cullface_back);
1296 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1298 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
1300 // decrement stencil if backface is behind depthbuffer
1301 GL_CullFace(r_refdef.view.cullface_front);
1302 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1303 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1304 // increment stencil if frontface is behind depthbuffer
1305 GL_CullFace(r_refdef.view.cullface_back);
1306 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1308 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1309 GL_LockArrays(0, 0);
1314 int R_Shadow_CalcTriangleSideMask(const vec3_t p1, const vec3_t p2, const vec3_t p3, float bias)
1316 // p1, p2, p3 are in the cubemap's local coordinate system
1317 // bias = border/(size - border)
1320 float dp1 = p1[0] + p1[1], dn1 = p1[0] - p1[1], ap1 = fabs(dp1), an1 = fabs(dn1),
1321 dp2 = p2[0] + p2[1], dn2 = p2[0] - p2[1], ap2 = fabs(dp2), an2 = fabs(dn2),
1322 dp3 = p3[0] + p3[1], dn3 = p3[0] - p3[1], ap3 = fabs(dp3), an3 = fabs(dn3);
1323 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1325 | (dp1 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1326 | (dp2 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2))
1327 | (dp3 >= 0 ? (1<<0)|(1<<2) : (2<<0)|(2<<2));
1328 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1330 | (dn1 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1331 | (dn2 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2))
1332 | (dn3 >= 0 ? (1<<0)|(2<<2) : (2<<0)|(1<<2));
1334 dp1 = p1[1] + p1[2], dn1 = p1[1] - p1[2], ap1 = fabs(dp1), an1 = fabs(dn1),
1335 dp2 = p2[1] + p2[2], dn2 = p2[1] - p2[2], ap2 = fabs(dp2), an2 = fabs(dn2),
1336 dp3 = p3[1] + p3[2], dn3 = p3[1] - p3[2], ap3 = fabs(dp3), an3 = fabs(dn3);
1337 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1339 | (dp1 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1340 | (dp2 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4))
1341 | (dp3 >= 0 ? (1<<2)|(1<<4) : (2<<2)|(2<<4));
1342 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1344 | (dn1 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1345 | (dn2 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4))
1346 | (dn3 >= 0 ? (1<<2)|(2<<4) : (2<<2)|(1<<4));
1348 dp1 = p1[2] + p1[0], dn1 = p1[2] - p1[0], ap1 = fabs(dp1), an1 = fabs(dn1),
1349 dp2 = p2[2] + p2[0], dn2 = p2[2] - p2[0], ap2 = fabs(dp2), an2 = fabs(dn2),
1350 dp3 = p3[2] + p3[0], dn3 = p3[2] - p3[0], ap3 = fabs(dp3), an3 = fabs(dn3);
1351 if(ap1 > bias*an1 && ap2 > bias*an2 && ap3 > bias*an3)
1353 | (dp1 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1354 | (dp2 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0))
1355 | (dp3 >= 0 ? (1<<4)|(1<<0) : (2<<4)|(2<<0));
1356 if(an1 > bias*ap1 && an2 > bias*ap2 && an3 > bias*ap3)
1358 | (dn1 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1359 | (dn2 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0))
1360 | (dn3 >= 0 ? (1<<4)|(2<<0) : (2<<4)|(1<<0));
1365 int R_Shadow_CalcSphereSideMask(const vec3_t p, float radius, float bias)
1367 // p is in the cubemap's local coordinate system
1368 // bias = border/(size - border)
1369 float dxyp = p[0] + p[1], dxyn = p[0] - p[1], axyp = fabs(dxyp), axyn = fabs(dxyn);
1370 float dyzp = p[1] + p[2], dyzn = p[1] - p[2], ayzp = fabs(dyzp), ayzn = fabs(dyzn);
1371 float dzxp = p[2] + p[0], dzxn = p[2] - p[0], azxp = fabs(dzxp), azxn = fabs(dzxn);
1373 if(axyp > bias*axyn + radius) mask &= dxyp < 0 ? ~((1<<0)|(1<<2)) : ~((2<<0)|(2<<2));
1374 if(axyn > bias*axyp + radius) mask &= dxyn < 0 ? ~((1<<0)|(2<<2)) : ~((2<<0)|(1<<2));
1375 if(ayzp > bias*ayzn + radius) mask &= dyzp < 0 ? ~((1<<2)|(1<<4)) : ~((2<<2)|(2<<4));
1376 if(ayzn > bias*ayzp + radius) mask &= dyzn < 0 ? ~((1<<2)|(2<<4)) : ~((2<<2)|(1<<4));
1377 if(azxp > bias*azxn + radius) mask &= dzxp < 0 ? ~((1<<4)|(1<<0)) : ~((2<<4)|(2<<0));
1378 if(azxn > bias*azxp + radius) mask &= dzxn < 0 ? ~((1<<4)|(2<<0)) : ~((2<<4)|(1<<0));
1382 void R_Shadow_ChooseSidesFromBox(int firsttriangle, int numtris, const float *invertex3f, const int *elements, const matrix4x4_t *worldtolight, const vec3_t projectorigin, const vec3_t projectdirection, const vec3_t lightmins, const vec3_t lightmaxs, const vec3_t surfacemins, const vec3_t surfacemaxs, int *totals)
1391 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1393 bias = r_shadow_shadowmapborder / (float)(r_shadow_shadowmapmaxsize - r_shadow_shadowmapborder);
1394 tend = firsttriangle + numtris;
1395 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1397 // surface box entirely inside light box, no box cull
1398 if (projectdirection)
1400 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1402 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1403 TriangleNormal(v[0], v[1], v[2], normal);
1404 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1406 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1407 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1408 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;
1409 shadowsides[numshadowsides] = mask;
1410 shadowsideslist[numshadowsides++] = t;
1416 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1418 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1419 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2]))
1421 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1422 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1423 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;
1424 shadowsides[numshadowsides] = mask;
1425 shadowsideslist[numshadowsides++] = t;
1432 // surface box not entirely inside light box, cull each triangle
1433 if (projectdirection)
1435 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1437 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1438 TriangleNormal(v[0], v[1], v[2], normal);
1439 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1440 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1442 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1443 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1444 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;
1445 shadowsides[numshadowsides] = mask;
1446 shadowsideslist[numshadowsides++] = t;
1452 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1454 v[0] = invertex3f + e[0] * 3, v[1] = invertex3f + e[1] * 3, v[2] = invertex3f + e[2] * 3;
1455 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1456 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1458 Matrix4x4_Transform(worldtolight, v[0], p[0]), Matrix4x4_Transform(worldtolight, v[1], p[1]), Matrix4x4_Transform(worldtolight, v[2], p[2]);
1459 mask = R_Shadow_CalcTriangleSideMask(p[0], p[1], p[2], bias);
1460 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;
1461 shadowsides[numshadowsides] = mask;
1462 shadowsideslist[numshadowsides++] = t;
1469 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)
1471 int i, j, outtriangles = 0;
1472 int *outelement3i[6];
1473 if (!numverts || !numsidetris || !r_shadow_compilingrtlight)
1475 outtriangles = sidetotals[0] + sidetotals[1] + sidetotals[2] + sidetotals[3] + sidetotals[4] + sidetotals[5];
1476 // make sure shadowelements is big enough for this mesh
1477 if (maxshadowtriangles < outtriangles)
1478 R_Shadow_ResizeShadowArrays(0, outtriangles, 0, 1);
1480 // compute the offset and size of the separate index lists for each cubemap side
1482 for (i = 0;i < 6;i++)
1484 outelement3i[i] = shadowelements + outtriangles * 3;
1485 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sideoffsets[i] = outtriangles;
1486 r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap->sidetotals[i] = sidetotals[i];
1487 outtriangles += sidetotals[i];
1490 // gather up the (sparse) triangles into separate index lists for each cubemap side
1491 for (i = 0;i < numsidetris;i++)
1493 const int *element = elements + sidetris[i] * 3;
1494 for (j = 0;j < 6;j++)
1496 if (sides[i] & (1 << j))
1498 outelement3i[j][0] = element[0];
1499 outelement3i[j][1] = element[1];
1500 outelement3i[j][2] = element[2];
1501 outelement3i[j] += 3;
1506 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_shadowmap, NULL, NULL, NULL, vertex3f, NULL, NULL, NULL, NULL, outtriangles, shadowelements);
1509 static void R_Shadow_MakeTextures_MakeCorona(void)
1513 unsigned char pixels[32][32][4];
1514 for (y = 0;y < 32;y++)
1516 dy = (y - 15.5f) * (1.0f / 16.0f);
1517 for (x = 0;x < 32;x++)
1519 dx = (x - 15.5f) * (1.0f / 16.0f);
1520 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1521 a = bound(0, a, 255);
1522 pixels[y][x][0] = a;
1523 pixels[y][x][1] = a;
1524 pixels[y][x][2] = a;
1525 pixels[y][x][3] = 255;
1528 r_shadow_lightcorona = R_LoadTexture2D(r_shadow_texturepool, "lightcorona", 32, 32, &pixels[0][0][0], TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_FORCELINEAR, NULL);
1531 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1533 float dist = sqrt(x*x+y*y+z*z);
1534 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1535 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1536 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1539 static void R_Shadow_MakeTextures(void)
1542 float intensity, dist;
1544 R_FreeTexturePool(&r_shadow_texturepool);
1545 r_shadow_texturepool = R_AllocTexturePool();
1546 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1547 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1548 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1549 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1550 for (x = 0;x <= ATTENTABLESIZE;x++)
1552 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1553 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1554 r_shadow_attentable[x] = bound(0, intensity, 1);
1556 // 1D gradient texture
1557 for (x = 0;x < ATTEN1DSIZE;x++)
1558 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1559 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);
1560 // 2D circle texture
1561 for (y = 0;y < ATTEN2DSIZE;y++)
1562 for (x = 0;x < ATTEN2DSIZE;x++)
1563 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);
1564 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);
1565 // 3D sphere texture
1566 if (r_shadow_texture3d.integer && gl_texture3d)
1568 for (z = 0;z < ATTEN3DSIZE;z++)
1569 for (y = 0;y < ATTEN3DSIZE;y++)
1570 for (x = 0;x < ATTEN3DSIZE;x++)
1571 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));
1572 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);
1575 r_shadow_attenuation3dtexture = NULL;
1578 R_Shadow_MakeTextures_MakeCorona();
1580 // Editor light sprites
1581 r_editlights_sprcursor = Draw_CachePic ("gfx/editlights/cursor");
1582 r_editlights_sprlight = Draw_CachePic ("gfx/editlights/light");
1583 r_editlights_sprnoshadowlight = Draw_CachePic ("gfx/editlights/noshadow");
1584 r_editlights_sprcubemaplight = Draw_CachePic ("gfx/editlights/cubemaplight");
1585 r_editlights_sprcubemapnoshadowlight = Draw_CachePic ("gfx/editlights/cubemapnoshadowlight");
1586 r_editlights_sprselection = Draw_CachePic ("gfx/editlights/selection");
1589 void R_Shadow_ValidateCvars(void)
1591 if (r_shadow_texture3d.integer && !gl_texture3d)
1592 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1593 if (gl_ext_separatestencil.integer && !gl_support_separatestencil)
1594 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
1595 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
1596 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1599 void R_Shadow_RenderMode_Begin(void)
1603 R_Shadow_ValidateCvars();
1605 if (!r_shadow_attenuation2dtexture
1606 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1607 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1608 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1609 R_Shadow_MakeTextures();
1612 R_Mesh_ColorPointer(NULL, 0, 0);
1613 R_Mesh_ResetTextureState();
1614 GL_BlendFunc(GL_ONE, GL_ZERO);
1615 GL_DepthRange(0, 1);
1616 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1618 GL_DepthMask(false);
1619 GL_Color(0, 0, 0, 1);
1620 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1622 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1624 if (gl_ext_separatestencil.integer)
1626 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
1627 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
1629 else if (gl_ext_stenciltwoside.integer)
1631 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
1632 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
1636 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
1637 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
1640 if (r_glsl.integer && gl_support_fragment_shader)
1641 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1642 else if (gl_dot3arb && gl_texturecubemap && r_textureunits.integer >= 2 && gl_combine.integer && gl_stencil)
1643 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_DOT3;
1645 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1648 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
1649 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
1650 r_shadow_drawbuffer = drawbuffer;
1651 r_shadow_readbuffer = readbuffer;
1652 r_shadow_cullface = r_refdef.view.cullface_back;
1655 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
1657 rsurface.rtlight = rtlight;
1660 void R_Shadow_RenderMode_Reset(void)
1663 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE)
1665 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1667 if (gl_support_ext_framebuffer_object)
1669 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);CHECKGLERROR
1671 qglDrawBuffer(r_shadow_drawbuffer);CHECKGLERROR
1672 qglReadBuffer(r_shadow_readbuffer);CHECKGLERROR
1673 R_SetViewport(&r_refdef.view.viewport);
1674 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
1675 R_Mesh_ColorPointer(NULL, 0, 0);
1676 R_Mesh_ResetTextureState();
1677 GL_DepthRange(0, 1);
1679 GL_DepthMask(false);
1680 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1681 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1682 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
1683 qglStencilMask(~0);CHECKGLERROR
1684 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
1685 qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
1686 r_refdef.view.cullface_back = r_shadow_cullface;
1687 GL_CullFace(r_refdef.view.cullface_back);
1688 GL_Color(1, 1, 1, 1);
1689 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
1690 GL_BlendFunc(GL_ONE, GL_ZERO);
1691 R_SetupGenericShader(false);
1692 r_shadow_usingshadowmaprect = false;
1693 r_shadow_usingshadowmapcube = false;
1694 r_shadow_usingshadowmap2d = false;
1698 void R_Shadow_ClearStencil(void)
1701 GL_Clear(GL_STENCIL_BUFFER_BIT);
1702 r_refdef.stats.lights_clears++;
1705 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
1707 r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
1708 if (r_shadow_rendermode == mode)
1711 R_Shadow_RenderMode_Reset();
1712 GL_ColorMask(0, 0, 0, 0);
1713 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1714 R_SetupDepthOrShadowShader();
1715 qglDepthFunc(GL_LESS);CHECKGLERROR
1716 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1717 r_shadow_rendermode = mode;
1722 case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
1723 GL_CullFace(GL_NONE);
1724 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1725 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1727 case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
1728 GL_CullFace(GL_NONE);
1729 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1730 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1732 case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
1733 GL_CullFace(GL_NONE);
1734 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1735 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
1736 qglStencilMask(~0);CHECKGLERROR
1737 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1738 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
1739 qglStencilMask(~0);CHECKGLERROR
1740 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1742 case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
1743 GL_CullFace(GL_NONE);
1744 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1745 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
1746 qglStencilMask(~0);CHECKGLERROR
1747 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1748 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
1749 qglStencilMask(~0);CHECKGLERROR
1750 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1755 static void R_Shadow_MakeVSDCT(void)
1757 // maps to a 2x3 texture rectangle with normalized coordinates
1762 // stores abs(dir.xy), offset.xy/2.5
1763 unsigned char data[4*6] =
1765 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
1766 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
1767 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
1768 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
1769 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
1770 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
1772 r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_ALWAYSPRECACHE | TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, NULL);
1775 void R_Shadow_RenderMode_ShadowMap(int side, qboolean clear, int size)
1780 float nearclip, farclip, bias;
1781 r_viewport_t viewport;
1783 maxsize = r_shadow_shadowmapmaxsize;
1784 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
1786 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
1787 r_shadow_shadowmap_parameters[2] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
1788 r_shadow_shadowmap_parameters[3] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
1789 r_shadow_shadowmapside = side;
1790 r_shadow_shadowmapsize = size;
1791 if (r_shadow_shadowmode == 1)
1793 // complex unrolled cube approach (more flexible)
1794 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
1795 R_Shadow_MakeVSDCT();
1796 if (!r_shadow_shadowmap2dtexture)
1799 int w = maxsize*2, h = gl_support_arb_texture_non_power_of_two ? maxsize*3 : maxsize*4;
1800 r_shadow_shadowmap2dtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "shadowmap", w, h, r_shadow_shadowmapprecision, r_shadow_shadowmapsampler);
1801 qglGenFramebuffersEXT(1, &r_shadow_fbo2d);CHECKGLERROR
1802 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbo2d);CHECKGLERROR
1803 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_shadowmap2dtexture), 0);CHECKGLERROR
1807 R_Shadow_RenderMode_Reset();
1808 if (r_shadow_shadowmap2dtexture)
1810 // render depth into the fbo, do not render color at all
1811 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbo2d);CHECKGLERROR
1812 qglDrawBuffer(GL_NONE);CHECKGLERROR
1813 qglReadBuffer(GL_NONE);CHECKGLERROR
1814 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
1815 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
1817 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
1818 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
1820 R_SetupDepthOrShadowShader();
1824 R_SetupShowDepthShader();
1825 qglClearColor(1,1,1,1);CHECKGLERROR
1827 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
1828 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
1829 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
1830 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
1831 r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
1832 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
1834 else if (r_shadow_shadowmode == 2)
1836 // complex unrolled cube approach (more flexible)
1837 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
1838 R_Shadow_MakeVSDCT();
1839 if (!r_shadow_shadowmaprectangletexture)
1842 r_shadow_shadowmaprectangletexture = R_LoadTextureShadowMapRectangle(r_shadow_texturepool, "shadowmap", maxsize*2, maxsize*3, r_shadow_shadowmapprecision, r_shadow_shadowmapsampler);
1843 qglGenFramebuffersEXT(1, &r_shadow_fborectangle);CHECKGLERROR
1844 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fborectangle);CHECKGLERROR
1845 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, R_GetTexture(r_shadow_shadowmaprectangletexture), 0);CHECKGLERROR
1849 R_Shadow_RenderMode_Reset();
1850 if (r_shadow_shadowmaprectangletexture)
1852 // render depth into the fbo, do not render color at all
1853 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fborectangle);CHECKGLERROR
1854 qglDrawBuffer(GL_NONE);CHECKGLERROR
1855 qglReadBuffer(GL_NONE);CHECKGLERROR
1856 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
1857 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
1859 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
1860 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
1862 R_SetupDepthOrShadowShader();
1866 R_SetupShowDepthShader();
1867 qglClearColor(1,1,1,1);CHECKGLERROR
1869 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
1870 r_shadow_shadowmap_texturescale[0] = 1.0f;
1871 r_shadow_shadowmap_texturescale[1] = 1.0f;
1872 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
1873 r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
1874 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE;
1876 else if (r_shadow_shadowmode == 3)
1878 // simple cube approach
1879 if (!r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod])
1882 r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod] = R_LoadTextureShadowMapCube(r_shadow_texturepool, "shadowmapcube", size, r_shadow_shadowmapprecision, r_shadow_shadowmapsampler);
1883 qglGenFramebuffersEXT(6, r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR
1884 for (i = 0;i < 6;i++)
1886 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbocubeside[r_shadow_shadowmaplod][i]);CHECKGLERROR
1887 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
1892 R_Shadow_RenderMode_Reset();
1893 if (r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod])
1895 // render depth into the fbo, do not render color at all
1896 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbocubeside[r_shadow_shadowmaplod][side]);CHECKGLERROR
1897 qglDrawBuffer(GL_NONE);CHECKGLERROR
1898 qglReadBuffer(GL_NONE);CHECKGLERROR
1899 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
1900 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
1902 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
1903 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
1905 R_SetupDepthOrShadowShader();
1909 R_SetupShowDepthShader();
1910 qglClearColor(1,1,1,1);CHECKGLERROR
1912 R_Viewport_InitCubeSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, nearclip, farclip, NULL);
1913 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]);
1914 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureWidth(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]);
1915 r_shadow_shadowmap_parameters[0] = 1.0f;
1916 r_shadow_shadowmap_parameters[1] = 1.0f;
1917 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE;
1920 R_SetViewport(&viewport);
1921 GL_PolygonOffset(0, 0);
1922 if(r_shadow_shadowmode >= 1 && r_shadow_shadowmode <= 2)
1924 static qboolean cullfront[6] = { false, true, false, true, true, false };
1925 if(cullfront[side]) r_refdef.view.cullface_back = r_refdef.view.cullface_front;
1927 GL_CullFace(r_refdef.view.cullface_back);
1928 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
1931 qglClearDepth(1);CHECKGLERROR
1934 qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
1938 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
1941 R_Shadow_RenderMode_Reset();
1942 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1945 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1949 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1950 // only draw light where this geometry was already rendered AND the
1951 // stencil is 128 (values other than this mean shadow)
1952 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
1954 r_shadow_rendermode = r_shadow_lightingrendermode;
1955 // do global setup needed for the chosen lighting mode
1956 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
1958 R_Mesh_TexBindCubeMap(GL20TU_CUBE, R_GetTexture(rsurface.rtlight->currentcubemap)); // light filter
1959 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
1963 if (r_shadow_shadowmode == 1)
1965 r_shadow_usingshadowmap2d = true;
1966 R_Mesh_TexBind(GL20TU_SHADOWMAP2D, R_GetTexture(r_shadow_shadowmap2dtexture));
1969 else if (r_shadow_shadowmode == 2)
1971 r_shadow_usingshadowmaprect = true;
1972 R_Mesh_TexBindRectangle(GL20TU_SHADOWMAPRECT, R_GetTexture(r_shadow_shadowmaprectangletexture));
1975 else if (r_shadow_shadowmode == 3)
1977 r_shadow_usingshadowmapcube = true;
1978 R_Mesh_TexBindCubeMap(GL20TU_SHADOWMAPCUBE, R_GetTexture(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]));
1982 if (r_shadow_shadowmapvsdct && (r_shadow_usingshadowmap2d || r_shadow_usingshadowmaprect))
1984 R_Mesh_TexBindCubeMap(GL20TU_CUBEPROJECTION, R_GetTexture(r_shadow_shadowmapvsdcttexture));
1989 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_VERTEX)
1990 R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
1991 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1995 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
1998 R_Shadow_RenderMode_Reset();
1999 GL_BlendFunc(GL_ONE, GL_ONE);
2000 GL_DepthRange(0, 1);
2001 GL_DepthTest(r_showshadowvolumes.integer < 2);
2002 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
2003 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
2004 GL_CullFace(GL_NONE);
2005 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
2008 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
2011 R_Shadow_RenderMode_Reset();
2012 GL_BlendFunc(GL_ONE, GL_ONE);
2013 GL_DepthRange(0, 1);
2014 GL_DepthTest(r_showlighting.integer < 2);
2015 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
2018 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2022 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
2023 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
2025 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
2028 void R_Shadow_RenderMode_End(void)
2031 R_Shadow_RenderMode_Reset();
2032 R_Shadow_RenderMode_ActiveLight(NULL);
2034 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
2035 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
2038 int bboxedges[12][2] =
2057 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
2059 int i, ix1, iy1, ix2, iy2;
2060 float x1, y1, x2, y2;
2062 float vertex[20][3];
2071 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
2072 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
2073 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
2074 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
2076 if (!r_shadow_scissor.integer)
2079 // if view is inside the light box, just say yes it's visible
2080 if (BoxesOverlap(r_refdef.view.origin, r_refdef.view.origin, mins, maxs))
2083 x1 = y1 = x2 = y2 = 0;
2085 // transform all corners that are infront of the nearclip plane
2086 VectorNegate(r_refdef.view.frustum[4].normal, plane4f);
2087 plane4f[3] = r_refdef.view.frustum[4].dist;
2089 for (i = 0;i < 8;i++)
2091 Vector4Set(corner[i], (i & 1) ? maxs[0] : mins[0], (i & 2) ? maxs[1] : mins[1], (i & 4) ? maxs[2] : mins[2], 1);
2092 dist[i] = DotProduct4(corner[i], plane4f);
2093 sign[i] = dist[i] > 0;
2096 VectorCopy(corner[i], vertex[numvertices]);
2100 // if some points are behind the nearclip, add clipped edge points to make
2101 // sure that the scissor boundary is complete
2102 if (numvertices > 0 && numvertices < 8)
2104 // add clipped edge points
2105 for (i = 0;i < 12;i++)
2107 j = bboxedges[i][0];
2108 k = bboxedges[i][1];
2109 if (sign[j] != sign[k])
2111 f = dist[j] / (dist[j] - dist[k]);
2112 VectorLerp(corner[j], f, corner[k], vertex[numvertices]);
2118 // if we have no points to check, the light is behind the view plane
2122 // if we have some points to transform, check what screen area is covered
2123 x1 = y1 = x2 = y2 = 0;
2125 //Con_Printf("%i vertices to transform...\n", numvertices);
2126 for (i = 0;i < numvertices;i++)
2128 VectorCopy(vertex[i], v);
2129 R_Viewport_TransformToScreen(&r_refdef.view.viewport, v, v2);
2130 //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]);
2133 if (x1 > v2[0]) x1 = v2[0];
2134 if (x2 < v2[0]) x2 = v2[0];
2135 if (y1 > v2[1]) y1 = v2[1];
2136 if (y2 < v2[1]) y2 = v2[1];
2145 // now convert the scissor rectangle to integer screen coordinates
2146 ix1 = (int)(x1 - 1.0f);
2147 iy1 = vid.height - (int)(y2 - 1.0f);
2148 ix2 = (int)(x2 + 1.0f);
2149 iy2 = vid.height - (int)(y1 + 1.0f);
2150 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
2152 // clamp it to the screen
2153 if (ix1 < r_refdef.view.viewport.x) ix1 = r_refdef.view.viewport.x;
2154 if (iy1 < r_refdef.view.viewport.y) iy1 = r_refdef.view.viewport.y;
2155 if (ix2 > r_refdef.view.viewport.x + r_refdef.view.viewport.width) ix2 = r_refdef.view.viewport.x + r_refdef.view.viewport.width;
2156 if (iy2 > r_refdef.view.viewport.y + r_refdef.view.viewport.height) iy2 = r_refdef.view.viewport.y + r_refdef.view.viewport.height;
2158 // if it is inside out, it's not visible
2159 if (ix2 <= ix1 || iy2 <= iy1)
2162 // the light area is visible, set up the scissor rectangle
2163 r_shadow_lightscissor[0] = ix1;
2164 r_shadow_lightscissor[1] = iy1;
2165 r_shadow_lightscissor[2] = ix2 - ix1;
2166 r_shadow_lightscissor[3] = iy2 - iy1;
2168 r_refdef.stats.lights_scissored++;
2172 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, int numtriangles, const int *element3i, const float *diffusecolor, const float *ambientcolor)
2174 float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
2175 float *normal3f = rsurface.normal3f + 3 * firstvertex;
2176 float *color4f = rsurface.array_color4f + 4 * firstvertex;
2177 float dist, dot, distintensity, shadeintensity, v[3], n[3];
2178 if (r_textureunits.integer >= 3)
2180 if (VectorLength2(diffusecolor) > 0)
2182 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2184 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2185 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2186 if ((dot = DotProduct(n, v)) < 0)
2188 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2189 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
2192 VectorCopy(ambientcolor, color4f);
2193 if (r_refdef.fogenabled)
2196 f = FogPoint_Model(vertex3f);
2197 VectorScale(color4f, f, color4f);
2204 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2206 VectorCopy(ambientcolor, color4f);
2207 if (r_refdef.fogenabled)
2210 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2211 f = FogPoint_Model(vertex3f);
2212 VectorScale(color4f, f, color4f);
2218 else if (r_textureunits.integer >= 2)
2220 if (VectorLength2(diffusecolor) > 0)
2222 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2224 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2225 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2227 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2228 if ((dot = DotProduct(n, v)) < 0)
2230 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2231 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2232 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2233 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2237 color4f[0] = ambientcolor[0] * distintensity;
2238 color4f[1] = ambientcolor[1] * distintensity;
2239 color4f[2] = ambientcolor[2] * distintensity;
2241 if (r_refdef.fogenabled)
2244 f = FogPoint_Model(vertex3f);
2245 VectorScale(color4f, f, color4f);
2249 VectorClear(color4f);
2255 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2257 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2258 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2260 color4f[0] = ambientcolor[0] * distintensity;
2261 color4f[1] = ambientcolor[1] * distintensity;
2262 color4f[2] = ambientcolor[2] * distintensity;
2263 if (r_refdef.fogenabled)
2266 f = FogPoint_Model(vertex3f);
2267 VectorScale(color4f, f, color4f);
2271 VectorClear(color4f);
2278 if (VectorLength2(diffusecolor) > 0)
2280 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2282 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2283 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2285 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2286 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2287 if ((dot = DotProduct(n, v)) < 0)
2289 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2290 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2291 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2292 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2296 color4f[0] = ambientcolor[0] * distintensity;
2297 color4f[1] = ambientcolor[1] * distintensity;
2298 color4f[2] = ambientcolor[2] * distintensity;
2300 if (r_refdef.fogenabled)
2303 f = FogPoint_Model(vertex3f);
2304 VectorScale(color4f, f, color4f);
2308 VectorClear(color4f);
2314 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2316 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2317 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2319 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2320 color4f[0] = ambientcolor[0] * distintensity;
2321 color4f[1] = ambientcolor[1] * distintensity;
2322 color4f[2] = ambientcolor[2] * distintensity;
2323 if (r_refdef.fogenabled)
2326 f = FogPoint_Model(vertex3f);
2327 VectorScale(color4f, f, color4f);
2331 VectorClear(color4f);
2338 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
2340 static void R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
2343 float *out3f = rsurface.array_texcoord3f + 3 * firstvertex;
2344 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
2345 const float *svector3f = rsurface.svector3f + 3 * firstvertex;
2346 const float *tvector3f = rsurface.tvector3f + 3 * firstvertex;
2347 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
2349 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
2351 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
2352 // the cubemap normalizes this for us
2353 out3f[0] = DotProduct(svector3f, lightdir);
2354 out3f[1] = DotProduct(tvector3f, lightdir);
2355 out3f[2] = DotProduct(normal3f, lightdir);
2359 static void R_Shadow_GenTexCoords_Specular_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
2362 float *out3f = rsurface.array_texcoord3f + 3 * firstvertex;
2363 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
2364 const float *svector3f = rsurface.svector3f + 3 * firstvertex;
2365 const float *tvector3f = rsurface.tvector3f + 3 * firstvertex;
2366 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
2367 float lightdir[3], eyedir[3], halfdir[3];
2368 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
2370 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
2371 VectorNormalize(lightdir);
2372 VectorSubtract(rsurface.modelorg, vertex3f, eyedir);
2373 VectorNormalize(eyedir);
2374 VectorAdd(lightdir, eyedir, halfdir);
2375 // the cubemap normalizes this for us
2376 out3f[0] = DotProduct(svector3f, halfdir);
2377 out3f[1] = DotProduct(tvector3f, halfdir);
2378 out3f[2] = DotProduct(normal3f, halfdir);
2382 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)
2384 // used to display how many times a surface is lit for level design purposes
2385 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2388 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)
2390 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2391 R_SetupSurfaceShader(lightcolorbase, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT);
2392 if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND))
2393 R_Mesh_ColorPointer(rsurface.modellightmapcolor4f, rsurface.modellightmapcolor4f_bufferobject, rsurface.modellightmapcolor4f_bufferoffset);
2395 R_Mesh_ColorPointer(NULL, 0, 0);
2396 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
2397 R_Mesh_TexMatrix(1, &rsurface.texture->currentbackgroundtexmatrix);
2398 R_Mesh_TexBind(GL20TU_NORMAL, R_GetTexture(rsurface.texture->currentskinframe->nmap));
2399 R_Mesh_TexBind(GL20TU_COLOR, R_GetTexture(rsurface.texture->basetexture));
2400 R_Mesh_TexBind(GL20TU_GLOSS, R_GetTexture(rsurface.texture->glosstexture));
2401 if (rsurface.texture->backgroundcurrentskinframe)
2403 R_Mesh_TexBind(GL20TU_SECONDARY_NORMAL, R_GetTexture(rsurface.texture->backgroundcurrentskinframe->nmap));
2404 R_Mesh_TexBind(GL20TU_SECONDARY_COLOR, R_GetTexture(rsurface.texture->backgroundbasetexture));
2405 R_Mesh_TexBind(GL20TU_SECONDARY_GLOSS, R_GetTexture(rsurface.texture->backgroundglosstexture));
2406 R_Mesh_TexBind(GL20TU_SECONDARY_GLOW, R_GetTexture(rsurface.texture->backgroundcurrentskinframe->glow));
2408 //R_Mesh_TexBindCubeMap(GL20TU_CUBE, R_GetTexture(rsurface.rtlight->currentcubemap));
2409 R_Mesh_TexBind(GL20TU_FOGMASK, R_GetTexture(r_texture_fogattenuation));
2410 if(rsurface.texture->colormapping)
2412 R_Mesh_TexBind(GL20TU_PANTS, R_GetTexture(rsurface.texture->currentskinframe->pants));
2413 R_Mesh_TexBind(GL20TU_SHIRT, R_GetTexture(rsurface.texture->currentskinframe->shirt));
2415 R_Mesh_TexBind(GL20TU_ATTENUATION, R_GetTexture(r_shadow_attenuationgradienttexture));
2416 R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
2417 R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset);
2418 R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset);
2419 R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset);
2420 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2422 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2424 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2425 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2427 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
2431 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)
2433 // shared final code for all the dot3 layers
2435 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2436 for (renders = 0;renders < 64 && (r > 0 || g > 0 || b > 0);renders++, r--, g--, b--)
2438 GL_Color(bound(0, r, 1), bound(0, g, 1), bound(0, b, 1), 1);
2439 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2443 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)
2446 // colorscale accounts for how much we multiply the brightness
2449 // mult is how many times the final pass of the lighting will be
2450 // performed to get more brightness than otherwise possible.
2452 // Limit mult to 64 for sanity sake.
2454 if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
2456 // 3 3D combine path (Geforce3, Radeon 8500)
2457 memset(&m, 0, sizeof(m));
2458 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2459 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2460 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2461 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2462 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2463 m.tex[1] = R_GetTexture(basetexture);
2464 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
2465 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
2466 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
2467 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
2468 m.texcubemap[2] = R_GetTexture(rsurface.rtlight->currentcubemap);
2469 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2470 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2471 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2472 m.texmatrix[2] = rsurface.entitytolight;
2473 GL_BlendFunc(GL_ONE, GL_ONE);
2475 else if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
2477 // 2 3D combine path (Geforce3, original Radeon)
2478 memset(&m, 0, sizeof(m));
2479 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2480 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2481 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2482 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2483 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2484 m.tex[1] = R_GetTexture(basetexture);
2485 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
2486 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
2487 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
2488 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
2489 GL_BlendFunc(GL_ONE, GL_ONE);
2491 else if (r_textureunits.integer >= 4 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2493 // 4 2D combine path (Geforce3, Radeon 8500)
2494 memset(&m, 0, sizeof(m));
2495 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2496 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2497 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2498 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2499 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2500 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2501 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2502 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2503 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2504 m.texmatrix[1] = rsurface.entitytoattenuationz;
2505 m.tex[2] = R_GetTexture(basetexture);
2506 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
2507 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
2508 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
2509 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
2510 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2512 m.texcubemap[3] = R_GetTexture(rsurface.rtlight->currentcubemap);
2513 m.pointer_texcoord3f[3] = rsurface.vertex3f;
2514 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
2515 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
2516 m.texmatrix[3] = rsurface.entitytolight;
2518 GL_BlendFunc(GL_ONE, GL_ONE);
2520 else if (r_textureunits.integer >= 3 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
2522 // 3 2D combine path (Geforce3, original Radeon)
2523 memset(&m, 0, sizeof(m));
2524 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2525 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2526 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2527 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2528 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2529 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2530 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2531 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2532 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2533 m.texmatrix[1] = rsurface.entitytoattenuationz;
2534 m.tex[2] = R_GetTexture(basetexture);
2535 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
2536 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
2537 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
2538 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
2539 GL_BlendFunc(GL_ONE, GL_ONE);
2543 // 2/2/2 2D combine path (any dot3 card)
2544 memset(&m, 0, sizeof(m));
2545 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2546 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2547 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2548 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2549 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2550 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2551 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2552 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2553 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2554 m.texmatrix[1] = rsurface.entitytoattenuationz;
2555 R_Mesh_TextureState(&m);
2556 GL_ColorMask(0,0,0,1);
2557 GL_BlendFunc(GL_ONE, GL_ZERO);
2558 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2561 memset(&m, 0, sizeof(m));
2562 m.tex[0] = R_GetTexture(basetexture);
2563 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2564 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2565 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2566 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2567 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2569 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2570 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2571 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2572 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2573 m.texmatrix[1] = rsurface.entitytolight;
2575 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2577 // this final code is shared
2578 R_Mesh_TextureState(&m);
2579 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);
2582 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)
2585 // colorscale accounts for how much we multiply the brightness
2588 // mult is how many times the final pass of the lighting will be
2589 // performed to get more brightness than otherwise possible.
2591 // Limit mult to 64 for sanity sake.
2593 // generate normalization cubemap texcoords
2594 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
2595 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
2597 // 3/2 3D combine path (Geforce3, Radeon 8500)
2598 memset(&m, 0, sizeof(m));
2599 m.tex[0] = R_GetTexture(normalmaptexture);
2600 m.texcombinergb[0] = GL_REPLACE;
2601 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2602 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2603 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2604 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2605 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2606 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2607 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2608 m.pointer_texcoord_bufferobject[1] = 0;
2609 m.pointer_texcoord_bufferoffset[1] = 0;
2610 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
2611 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2612 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2613 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2614 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
2615 R_Mesh_TextureState(&m);
2616 GL_ColorMask(0,0,0,1);
2617 GL_BlendFunc(GL_ONE, GL_ZERO);
2618 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2621 memset(&m, 0, sizeof(m));
2622 m.tex[0] = R_GetTexture(basetexture);
2623 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2624 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2625 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2626 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2627 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2629 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2630 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2631 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2632 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2633 m.texmatrix[1] = rsurface.entitytolight;
2635 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2637 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2639 // 1/2/2 3D combine path (original Radeon)
2640 memset(&m, 0, sizeof(m));
2641 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2642 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2643 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2644 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2645 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2646 R_Mesh_TextureState(&m);
2647 GL_ColorMask(0,0,0,1);
2648 GL_BlendFunc(GL_ONE, GL_ZERO);
2649 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2652 memset(&m, 0, sizeof(m));
2653 m.tex[0] = R_GetTexture(normalmaptexture);
2654 m.texcombinergb[0] = GL_REPLACE;
2655 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2656 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2657 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2658 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2659 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2660 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2661 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2662 m.pointer_texcoord_bufferobject[1] = 0;
2663 m.pointer_texcoord_bufferoffset[1] = 0;
2664 R_Mesh_TextureState(&m);
2665 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2666 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2669 memset(&m, 0, sizeof(m));
2670 m.tex[0] = R_GetTexture(basetexture);
2671 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2672 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2673 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2674 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2675 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2677 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2678 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2679 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2680 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2681 m.texmatrix[1] = rsurface.entitytolight;
2683 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2685 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
2687 // 2/2 3D combine path (original Radeon)
2688 memset(&m, 0, sizeof(m));
2689 m.tex[0] = R_GetTexture(normalmaptexture);
2690 m.texcombinergb[0] = GL_REPLACE;
2691 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2692 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2693 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2694 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2695 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2696 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2697 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2698 m.pointer_texcoord_bufferobject[1] = 0;
2699 m.pointer_texcoord_bufferoffset[1] = 0;
2700 R_Mesh_TextureState(&m);
2701 GL_ColorMask(0,0,0,1);
2702 GL_BlendFunc(GL_ONE, GL_ZERO);
2703 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2706 memset(&m, 0, sizeof(m));
2707 m.tex[0] = R_GetTexture(basetexture);
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.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2713 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2714 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2715 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2716 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2717 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2719 else if (r_textureunits.integer >= 4)
2721 // 4/2 2D combine path (Geforce3, Radeon 8500)
2722 memset(&m, 0, sizeof(m));
2723 m.tex[0] = R_GetTexture(normalmaptexture);
2724 m.texcombinergb[0] = GL_REPLACE;
2725 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2726 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2727 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2728 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2729 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2730 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2731 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2732 m.pointer_texcoord_bufferobject[1] = 0;
2733 m.pointer_texcoord_bufferoffset[1] = 0;
2734 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2735 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2736 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2737 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2738 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
2739 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
2740 m.pointer_texcoord3f[3] = rsurface.vertex3f;
2741 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
2742 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
2743 m.texmatrix[3] = rsurface.entitytoattenuationz;
2744 R_Mesh_TextureState(&m);
2745 GL_ColorMask(0,0,0,1);
2746 GL_BlendFunc(GL_ONE, GL_ZERO);
2747 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2750 memset(&m, 0, sizeof(m));
2751 m.tex[0] = R_GetTexture(basetexture);
2752 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2753 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2754 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2755 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2756 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2758 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2759 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2760 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2761 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2762 m.texmatrix[1] = rsurface.entitytolight;
2764 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2768 // 2/2/2 2D combine path (any dot3 card)
2769 memset(&m, 0, sizeof(m));
2770 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2771 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2772 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2773 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2774 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2775 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2776 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2777 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2778 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2779 m.texmatrix[1] = rsurface.entitytoattenuationz;
2780 R_Mesh_TextureState(&m);
2781 GL_ColorMask(0,0,0,1);
2782 GL_BlendFunc(GL_ONE, GL_ZERO);
2783 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2786 memset(&m, 0, sizeof(m));
2787 m.tex[0] = R_GetTexture(normalmaptexture);
2788 m.texcombinergb[0] = GL_REPLACE;
2789 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2790 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2791 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2792 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2793 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2794 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2795 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2796 m.pointer_texcoord_bufferobject[1] = 0;
2797 m.pointer_texcoord_bufferoffset[1] = 0;
2798 R_Mesh_TextureState(&m);
2799 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2800 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2803 memset(&m, 0, sizeof(m));
2804 m.tex[0] = R_GetTexture(basetexture);
2805 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2806 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2807 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2808 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2809 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2811 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2812 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2813 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2814 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2815 m.texmatrix[1] = rsurface.entitytolight;
2817 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2819 // this final code is shared
2820 R_Mesh_TextureState(&m);
2821 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);
2824 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)
2826 float glossexponent;
2828 // FIXME: detect blendsquare!
2829 //if (!gl_support_blendsquare)
2832 // generate normalization cubemap texcoords
2833 R_Shadow_GenTexCoords_Specular_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
2834 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2836 // 2/0/0/1/2 3D combine blendsquare path
2837 memset(&m, 0, sizeof(m));
2838 m.tex[0] = R_GetTexture(normalmaptexture);
2839 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2840 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2841 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2842 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2843 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2844 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2845 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2846 m.pointer_texcoord_bufferobject[1] = 0;
2847 m.pointer_texcoord_bufferoffset[1] = 0;
2848 R_Mesh_TextureState(&m);
2849 GL_ColorMask(0,0,0,1);
2850 // this squares the result
2851 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2852 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2854 // second and third pass
2855 R_Mesh_ResetTextureState();
2856 // square alpha in framebuffer a few times to make it shiny
2857 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2858 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2859 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2862 memset(&m, 0, sizeof(m));
2863 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2864 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2865 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2866 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2867 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2868 R_Mesh_TextureState(&m);
2869 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2870 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2873 memset(&m, 0, sizeof(m));
2874 m.tex[0] = R_GetTexture(glosstexture);
2875 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2876 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2877 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2878 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2879 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2881 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2882 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2883 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2884 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2885 m.texmatrix[1] = rsurface.entitytolight;
2887 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2889 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
2891 // 2/0/0/2 3D combine blendsquare path
2892 memset(&m, 0, sizeof(m));
2893 m.tex[0] = R_GetTexture(normalmaptexture);
2894 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2895 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2896 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2897 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2898 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2899 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2900 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2901 m.pointer_texcoord_bufferobject[1] = 0;
2902 m.pointer_texcoord_bufferoffset[1] = 0;
2903 R_Mesh_TextureState(&m);
2904 GL_ColorMask(0,0,0,1);
2905 // this squares the result
2906 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2907 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2909 // second and third pass
2910 R_Mesh_ResetTextureState();
2911 // square alpha in framebuffer a few times to make it shiny
2912 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2913 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2914 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2917 memset(&m, 0, sizeof(m));
2918 m.tex[0] = R_GetTexture(glosstexture);
2919 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2920 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2921 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2922 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2923 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2924 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2925 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2926 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2927 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2928 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2932 // 2/0/0/2/2 2D combine blendsquare path
2933 memset(&m, 0, sizeof(m));
2934 m.tex[0] = R_GetTexture(normalmaptexture);
2935 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2936 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2937 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2938 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2939 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2940 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2941 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2942 m.pointer_texcoord_bufferobject[1] = 0;
2943 m.pointer_texcoord_bufferoffset[1] = 0;
2944 R_Mesh_TextureState(&m);
2945 GL_ColorMask(0,0,0,1);
2946 // this squares the result
2947 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2948 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2950 // second and third pass
2951 R_Mesh_ResetTextureState();
2952 // square alpha in framebuffer a few times to make it shiny
2953 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2954 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2955 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2958 memset(&m, 0, sizeof(m));
2959 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2960 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2961 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2962 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2963 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2964 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2965 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2966 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2967 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2968 m.texmatrix[1] = rsurface.entitytoattenuationz;
2969 R_Mesh_TextureState(&m);
2970 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2971 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2974 memset(&m, 0, sizeof(m));
2975 m.tex[0] = R_GetTexture(glosstexture);
2976 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2977 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2978 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2979 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2980 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2982 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2983 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2984 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2985 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2986 m.texmatrix[1] = rsurface.entitytolight;
2988 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2990 // this final code is shared
2991 R_Mesh_TextureState(&m);
2992 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);
2995 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)
2997 // ARB path (any Geforce, any Radeon)
2998 qboolean doambient = ambientscale > 0;
2999 qboolean dodiffuse = diffusescale > 0;
3000 qboolean dospecular = specularscale > 0;
3001 if (!doambient && !dodiffuse && !dospecular)
3003 R_Mesh_ColorPointer(NULL, 0, 0);
3005 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, basetexture, ambientscale * r_refdef.view.colorscale);
3007 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, basetexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
3011 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorpants, pantstexture, ambientscale * r_refdef.view.colorscale);
3013 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorpants, pantstexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
3018 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorshirt, shirttexture, ambientscale * r_refdef.view.colorscale);
3020 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorshirt, shirttexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
3023 R_Shadow_RenderLighting_Light_Dot3_SpecularPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, glosstexture, normalmaptexture, specularscale * r_refdef.view.colorscale);
3026 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
3033 int newnumtriangles;
3037 int maxtriangles = 4096;
3038 int newelements[4096*3];
3039 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, numtriangles, element3i, diffusecolor2, ambientcolor2);
3040 for (renders = 0;renders < 64;renders++)
3045 newnumtriangles = 0;
3047 // due to low fillrate on the cards this vertex lighting path is
3048 // designed for, we manually cull all triangles that do not
3049 // contain a lit vertex
3050 // this builds batches of triangles from multiple surfaces and
3051 // renders them at once
3052 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
3054 if (VectorLength2(rsurface.array_color4f + e[0] * 4) + VectorLength2(rsurface.array_color4f + e[1] * 4) + VectorLength2(rsurface.array_color4f + e[2] * 4) >= 0.01)
3056 if (newnumtriangles)
3058 newfirstvertex = min(newfirstvertex, e[0]);
3059 newlastvertex = max(newlastvertex, e[0]);
3063 newfirstvertex = e[0];
3064 newlastvertex = e[0];
3066 newfirstvertex = min(newfirstvertex, e[1]);
3067 newlastvertex = max(newlastvertex, e[1]);
3068 newfirstvertex = min(newfirstvertex, e[2]);
3069 newlastvertex = max(newlastvertex, e[2]);
3075 if (newnumtriangles >= maxtriangles)
3077 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
3078 newnumtriangles = 0;
3084 if (newnumtriangles >= 1)
3086 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
3089 // if we couldn't find any lit triangles, exit early
3092 // now reduce the intensity for the next overbright pass
3093 // we have to clamp to 0 here incase the drivers have improper
3094 // handling of negative colors
3095 // (some old drivers even have improper handling of >1 color)
3097 for (i = 0, c = rsurface.array_color4f + 4 * firstvertex;i < numvertices;i++, c += 4)
3099 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
3101 c[0] = max(0, c[0] - 1);
3102 c[1] = max(0, c[1] - 1);
3103 c[2] = max(0, c[2] - 1);
3115 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)
3117 // OpenGL 1.1 path (anything)
3118 float ambientcolorbase[3], diffusecolorbase[3];
3119 float ambientcolorpants[3], diffusecolorpants[3];
3120 float ambientcolorshirt[3], diffusecolorshirt[3];
3122 VectorScale(lightcolorbase, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorbase);
3123 VectorScale(lightcolorbase, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorbase);
3124 VectorScale(lightcolorpants, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorpants);
3125 VectorScale(lightcolorpants, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorpants);
3126 VectorScale(lightcolorshirt, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorshirt);
3127 VectorScale(lightcolorshirt, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorshirt);
3128 memset(&m, 0, sizeof(m));
3129 m.tex[0] = R_GetTexture(basetexture);
3130 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
3131 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
3132 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
3133 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
3134 if (r_textureunits.integer >= 2)
3137 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
3138 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
3139 m.pointer_texcoord3f[1] = rsurface.vertex3f;
3140 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
3141 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
3142 if (r_textureunits.integer >= 3)
3144 // Voodoo4 or Kyro (or Geforce3/Radeon with gl_combine off)
3145 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
3146 m.texmatrix[2] = rsurface.entitytoattenuationz;
3147 m.pointer_texcoord3f[2] = rsurface.vertex3f;
3148 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
3149 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
3152 R_Mesh_TextureState(&m);
3153 //R_Mesh_TexBind(0, R_GetTexture(basetexture));
3154 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorbase, ambientcolorbase);
3157 R_Mesh_TexBind(0, R_GetTexture(pantstexture));
3158 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorpants, ambientcolorpants);
3162 R_Mesh_TexBind(0, R_GetTexture(shirttexture));
3163 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorshirt, ambientcolorshirt);
3167 extern cvar_t gl_lightmaps;
3168 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)
3170 float ambientscale, diffusescale, specularscale;
3171 vec3_t lightcolorbase, lightcolorpants, lightcolorshirt;
3173 // calculate colors to render this texture with
3174 lightcolorbase[0] = rsurface.rtlight->currentcolor[0] * rsurface.texture->dlightcolor[0];
3175 lightcolorbase[1] = rsurface.rtlight->currentcolor[1] * rsurface.texture->dlightcolor[1];
3176 lightcolorbase[2] = rsurface.rtlight->currentcolor[2] * rsurface.texture->dlightcolor[2];
3177 ambientscale = rsurface.rtlight->ambientscale;
3178 diffusescale = rsurface.rtlight->diffusescale;
3179 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
3180 if (!r_shadow_usenormalmap.integer)
3182 ambientscale += 1.0f * diffusescale;
3186 if ((ambientscale + diffusescale) * VectorLength2(lightcolorbase) + specularscale * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
3188 RSurf_SetupDepthAndCulling();
3189 nmap = rsurface.texture->currentskinframe->nmap;
3190 if (gl_lightmaps.integer)
3191 nmap = r_texture_blanknormalmap;
3192 if (rsurface.texture->colormapping && !gl_lightmaps.integer)
3194 qboolean dopants = rsurface.texture->currentskinframe->pants != NULL && VectorLength2(rsurface.colormap_pantscolor) >= (1.0f / 1048576.0f);
3195 qboolean doshirt = rsurface.texture->currentskinframe->shirt != NULL && VectorLength2(rsurface.colormap_shirtcolor) >= (1.0f / 1048576.0f);
3198 lightcolorpants[0] = lightcolorbase[0] * rsurface.colormap_pantscolor[0];
3199 lightcolorpants[1] = lightcolorbase[1] * rsurface.colormap_pantscolor[1];
3200 lightcolorpants[2] = lightcolorbase[2] * rsurface.colormap_pantscolor[2];
3203 VectorClear(lightcolorpants);
3206 lightcolorshirt[0] = lightcolorbase[0] * rsurface.colormap_shirtcolor[0];
3207 lightcolorshirt[1] = lightcolorbase[1] * rsurface.colormap_shirtcolor[1];
3208 lightcolorshirt[2] = lightcolorbase[2] * rsurface.colormap_shirtcolor[2];
3211 VectorClear(lightcolorshirt);
3212 switch (r_shadow_rendermode)
3214 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
3215 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
3216 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);
3218 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
3219 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);
3221 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
3222 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);
3224 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3225 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);
3228 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
3234 switch (r_shadow_rendermode)
3236 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
3237 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
3238 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);
3240 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
3241 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);
3243 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
3244 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);
3246 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3247 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);
3250 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
3256 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)
3258 matrix4x4_t tempmatrix = *matrix;
3259 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
3261 // if this light has been compiled before, free the associated data
3262 R_RTLight_Uncompile(rtlight);
3264 // clear it completely to avoid any lingering data
3265 memset(rtlight, 0, sizeof(*rtlight));
3267 // copy the properties
3268 rtlight->matrix_lighttoworld = tempmatrix;
3269 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
3270 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
3271 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
3272 VectorCopy(color, rtlight->color);
3273 rtlight->cubemapname[0] = 0;
3274 if (cubemapname && cubemapname[0])
3275 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
3276 rtlight->shadow = shadow;
3277 rtlight->corona = corona;
3278 rtlight->style = style;
3279 rtlight->isstatic = isstatic;
3280 rtlight->coronasizescale = coronasizescale;
3281 rtlight->ambientscale = ambientscale;
3282 rtlight->diffusescale = diffusescale;
3283 rtlight->specularscale = specularscale;
3284 rtlight->flags = flags;
3286 // compute derived data
3287 //rtlight->cullradius = rtlight->radius;
3288 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
3289 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3290 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3291 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3292 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3293 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3294 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3297 // compiles rtlight geometry
3298 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
3299 void R_RTLight_Compile(rtlight_t *rtlight)
3302 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
3303 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
3304 entity_render_t *ent = r_refdef.scene.worldentity;
3305 dp_model_t *model = r_refdef.scene.worldmodel;
3306 unsigned char *data;
3309 // compile the light
3310 rtlight->compiled = true;
3311 rtlight->shadowmode = rtlight->shadow ? r_shadow_shadowmode : -1;
3312 rtlight->static_numleafs = 0;
3313 rtlight->static_numleafpvsbytes = 0;
3314 rtlight->static_leaflist = NULL;
3315 rtlight->static_leafpvs = NULL;
3316 rtlight->static_numsurfaces = 0;
3317 rtlight->static_surfacelist = NULL;
3318 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3319 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3320 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3321 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3322 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3323 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3325 if (model && model->GetLightInfo)
3327 // this variable must be set for the CompileShadowVolume/CompileShadowMap code
3328 r_shadow_compilingrtlight = rtlight;
3329 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);
3330 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);
3331 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
3332 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
3333 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3334 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
3335 rtlight->static_numsurfaces = numsurfaces;
3336 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
3337 rtlight->static_numleafs = numleafs;
3338 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
3339 rtlight->static_numleafpvsbytes = numleafpvsbytes;
3340 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
3341 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
3342 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
3343 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
3344 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3345 if (rtlight->static_numsurfaces)
3346 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3347 if (rtlight->static_numleafs)
3348 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3349 if (rtlight->static_numleafpvsbytes)
3350 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3351 if (rtlight->static_numshadowtrispvsbytes)
3352 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3353 if (rtlight->static_numlighttrispvsbytes)
3354 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3355 if (rtlight->shadowmode <= 0)
3357 if (model->CompileShadowVolume && rtlight->shadow)
3358 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3362 if (model->CompileShadowMap && rtlight->shadow)
3363 model->CompileShadowMap(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3365 // now we're done compiling the rtlight
3366 r_shadow_compilingrtlight = NULL;
3370 // use smallest available cullradius - box radius or light radius
3371 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3372 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3374 shadowzpasstris = 0;
3375 if (rtlight->static_meshchain_shadow_zpass)
3376 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
3377 shadowzpasstris += mesh->numtriangles;
3379 shadowzfailtris = 0;
3380 if (rtlight->static_meshchain_shadow_zfail)
3381 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
3382 shadowzfailtris += mesh->numtriangles;
3385 if (rtlight->static_numlighttrispvsbytes)
3386 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3387 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3391 if (rtlight->static_numlighttrispvsbytes)
3392 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3393 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3396 if (developer.integer >= 10)
3397 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);
3400 void R_RTLight_Uncompile(rtlight_t *rtlight)
3402 if (rtlight->compiled)
3404 if (rtlight->static_meshchain_shadow_zpass)
3405 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
3406 rtlight->static_meshchain_shadow_zpass = NULL;
3407 if (rtlight->static_meshchain_shadow_zfail)
3408 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
3409 rtlight->static_meshchain_shadow_zfail = NULL;
3410 if (rtlight->static_meshchain_shadow_shadowmap)
3411 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_shadowmap);
3412 rtlight->static_meshchain_shadow_shadowmap = NULL;
3413 // these allocations are grouped
3414 if (rtlight->static_surfacelist)
3415 Mem_Free(rtlight->static_surfacelist);
3416 rtlight->static_numleafs = 0;
3417 rtlight->static_numleafpvsbytes = 0;
3418 rtlight->static_leaflist = NULL;
3419 rtlight->static_leafpvs = NULL;
3420 rtlight->static_numsurfaces = 0;
3421 rtlight->static_surfacelist = NULL;
3422 rtlight->static_numshadowtrispvsbytes = 0;
3423 rtlight->static_shadowtrispvs = NULL;
3424 rtlight->static_numlighttrispvsbytes = 0;
3425 rtlight->static_lighttrispvs = NULL;
3426 rtlight->compiled = false;
3430 void R_Shadow_UncompileWorldLights(void)
3434 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3435 for (lightindex = 0;lightindex < range;lightindex++)
3437 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3440 R_RTLight_Uncompile(&light->rtlight);
3444 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3448 // reset the count of frustum planes
3449 // see rsurface.rtlight_frustumplanes definition for how much this array
3451 rsurface.rtlight_numfrustumplanes = 0;
3453 // haven't implemented a culling path for ortho rendering
3454 if (!r_refdef.view.useperspective)
3456 // check if the light is on screen and copy the 4 planes if it is
3457 for (i = 0;i < 4;i++)
3458 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3461 for (i = 0;i < 4;i++)
3462 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_refdef.view.frustum[i];
3467 // generate a deformed frustum that includes the light origin, this is
3468 // used to cull shadow casting surfaces that can not possibly cast a
3469 // shadow onto the visible light-receiving surfaces, which can be a
3472 // if the light origin is onscreen the result will be 4 planes exactly
3473 // if the light origin is offscreen on only one axis the result will
3474 // be exactly 5 planes (split-side case)
3475 // if the light origin is offscreen on two axes the result will be
3476 // exactly 4 planes (stretched corner case)
3477 for (i = 0;i < 4;i++)
3479 // quickly reject standard frustum planes that put the light
3480 // origin outside the frustum
3481 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3484 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_refdef.view.frustum[i];
3486 // if all the standard frustum planes were accepted, the light is onscreen
3487 // otherwise we need to generate some more planes below...
3488 if (rsurface.rtlight_numfrustumplanes < 4)
3490 // at least one of the stock frustum planes failed, so we need to
3491 // create one or two custom planes to enclose the light origin
3492 for (i = 0;i < 4;i++)
3494 // create a plane using the view origin and light origin, and a
3495 // single point from the frustum corner set
3496 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3497 VectorNormalize(plane.normal);
3498 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3499 // see if this plane is backwards and flip it if so
3500 for (j = 0;j < 4;j++)
3501 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3505 VectorNegate(plane.normal, plane.normal);
3507 // flipped plane, test again to see if it is now valid
3508 for (j = 0;j < 4;j++)
3509 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3511 // if the plane is still not valid, then it is dividing the
3512 // frustum and has to be rejected
3516 // we have created a valid plane, compute extra info
3517 PlaneClassify(&plane);
3519 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3521 // if we've found 5 frustum planes then we have constructed a
3522 // proper split-side case and do not need to keep searching for
3523 // planes to enclose the light origin
3524 if (rsurface.rtlight_numfrustumplanes == 5)
3532 for (i = 0;i < rsurface.rtlight_numfrustumplanes;i++)
3534 plane = rsurface.rtlight_frustumplanes[i];
3535 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));
3540 // now add the light-space box planes if the light box is rotated, as any
3541 // caster outside the oriented light box is irrelevant (even if it passed
3542 // the worldspace light box, which is axial)
3543 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3545 for (i = 0;i < 6;i++)
3549 v[i >> 1] = (i & 1) ? -1 : 1;
3550 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3551 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3552 plane.dist = VectorNormalizeLength(plane.normal);
3553 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3554 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3560 // add the world-space reduced box planes
3561 for (i = 0;i < 6;i++)
3563 VectorClear(plane.normal);
3564 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3565 plane.dist = (i & 1) ? -rsurface.rtlight_cullmaxs[i >> 1] : rsurface.rtlight_cullmins[i >> 1];
3566 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3575 // reduce all plane distances to tightly fit the rtlight cull box, which
3577 VectorSet(points[0], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
3578 VectorSet(points[1], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
3579 VectorSet(points[2], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
3580 VectorSet(points[3], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
3581 VectorSet(points[4], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
3582 VectorSet(points[5], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
3583 VectorSet(points[6], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
3584 VectorSet(points[7], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
3585 oldnum = rsurface.rtlight_numfrustumplanes;
3586 rsurface.rtlight_numfrustumplanes = 0;
3587 for (j = 0;j < oldnum;j++)
3589 // find the nearest point on the box to this plane
3590 bestdist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[0]);
3591 for (i = 1;i < 8;i++)
3593 dist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[i]);
3594 if (bestdist > dist)
3597 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);
3598 // if the nearest point is near or behind the plane, we want this
3599 // plane, otherwise the plane is useless as it won't cull anything
3600 if (rsurface.rtlight_frustumplanes[j].dist < bestdist + 0.03125)
3602 PlaneClassify(&rsurface.rtlight_frustumplanes[j]);
3603 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = rsurface.rtlight_frustumplanes[j];
3610 void R_Shadow_DrawWorldShadow_ShadowMap(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3614 RSurf_ActiveWorldEntity();
3616 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3619 GL_CullFace(GL_NONE);
3620 mesh = rsurface.rtlight->static_meshchain_shadow_shadowmap;
3621 for (;mesh;mesh = mesh->next)
3623 if (!mesh->sidetotals[r_shadow_shadowmapside])
3625 r_refdef.stats.lights_shadowtriangles += mesh->sidetotals[r_shadow_shadowmapside];
3626 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
3627 R_Mesh_Draw(0, mesh->numverts, mesh->sideoffsets[r_shadow_shadowmapside], mesh->sidetotals[r_shadow_shadowmapside], mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3631 else if (r_refdef.scene.worldentity->model)
3632 r_refdef.scene.worldmodel->DrawShadowMap(r_shadow_shadowmapside, r_refdef.scene.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs);
3634 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3637 void R_Shadow_DrawWorldShadow(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3642 int surfacelistindex;
3643 msurface_t *surface;
3645 RSurf_ActiveWorldEntity();
3647 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3650 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
3651 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
3652 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
3653 for (;mesh;mesh = mesh->next)
3655 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
3656 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
3657 GL_LockArrays(0, mesh->numverts);
3658 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
3660 // increment stencil if frontface is infront of depthbuffer
3661 GL_CullFace(r_refdef.view.cullface_back);
3662 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
3663 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3664 // decrement stencil if backface is infront of depthbuffer
3665 GL_CullFace(r_refdef.view.cullface_front);
3666 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
3668 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
3670 // decrement stencil if backface is behind depthbuffer
3671 GL_CullFace(r_refdef.view.cullface_front);
3672 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
3673 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3674 // increment stencil if frontface is behind depthbuffer
3675 GL_CullFace(r_refdef.view.cullface_back);
3676 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
3678 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3679 GL_LockArrays(0, 0);
3683 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh && r_shadow_culltriangles.integer)
3685 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
3686 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
3688 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
3689 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
3690 if (CHECKPVSBIT(trispvs, t))
3691 shadowmarklist[numshadowmark++] = t;
3693 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);
3695 else if (numsurfaces)
3696 r_refdef.scene.worldmodel->DrawShadowVolume(r_refdef.scene.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs);
3698 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3701 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3703 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3704 vec_t relativeshadowradius;
3705 RSurf_ActiveModelEntity(ent, false, false);
3706 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3707 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3708 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3709 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3710 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3711 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3712 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3713 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3714 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D)
3716 vec3_t radius, worldorigin, lightorigin;
3717 VectorSubtract(ent->maxs, ent->mins, radius);
3718 VectorScale(radius, 0.5f, radius);
3719 VectorAdd(ent->mins, radius, worldorigin);
3720 Matrix4x4_Transform(&rsurface.rtlight->matrix_worldtolight, worldorigin, lightorigin);
3721 if (R_Shadow_CalcSphereSideMask(lightorigin, VectorLength(radius) / relativeshadowradius, r_shadow_shadowmapborder / (float)(r_shadow_shadowmapsize - r_shadow_shadowmapborder)) & (1 << r_shadow_shadowmapside))
3722 ent->model->DrawShadowMap(r_shadow_shadowmapside, ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3725 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3726 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3729 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3731 // set up properties for rendering light onto this entity
3732 RSurf_ActiveModelEntity(ent, true, true);
3733 GL_AlphaTest(false);
3734 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3735 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3736 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3737 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3738 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
3739 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
3742 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3744 if (!r_refdef.scene.worldmodel->DrawLight)
3747 // set up properties for rendering light onto this entity
3748 RSurf_ActiveWorldEntity();
3749 GL_AlphaTest(false);
3750 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3751 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3752 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3753 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3754 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
3755 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
3757 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, trispvs);
3759 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3762 void R_Shadow_DrawEntityLight(entity_render_t *ent)
3764 dp_model_t *model = ent->model;
3765 if (!model->DrawLight)
3768 R_Shadow_SetupEntityLight(ent);
3770 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3772 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3775 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
3779 int numleafs, numsurfaces;
3780 int *leaflist, *surfacelist;
3781 unsigned char *leafpvs, *shadowtrispvs, *lighttrispvs;
3782 int numlightentities;
3783 int numlightentities_noselfshadow;
3784 int numshadowentities;
3785 int numshadowentities_noselfshadow;
3786 static entity_render_t *lightentities[MAX_EDICTS];
3787 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3788 static entity_render_t *shadowentities[MAX_EDICTS];
3789 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3790 vec3_t nearestpoint;
3792 qboolean castshadows;
3795 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3796 // skip lights that are basically invisible (color 0 0 0)
3797 if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
3800 // loading is done before visibility checks because loading should happen
3801 // all at once at the start of a level, not when it stalls gameplay.
3802 // (especially important to benchmarks)
3804 if (rtlight->isstatic && (!rtlight->compiled || (rtlight->shadow && rtlight->shadowmode != r_shadow_shadowmode)) && r_shadow_realtime_world_compile.integer)
3806 if (rtlight->compiled)
3807 R_RTLight_Uncompile(rtlight);
3808 R_RTLight_Compile(rtlight);
3812 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
3814 // look up the light style value at this time
3815 f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3816 VectorScale(rtlight->color, f, rtlight->currentcolor);
3818 if (rtlight->selected)
3820 f = 2 + sin(realtime * M_PI * 4.0);
3821 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3825 // if lightstyle is currently off, don't draw the light
3826 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3829 // if the light box is offscreen, skip it
3830 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3833 VectorCopy(rtlight->cullmins, rsurface.rtlight_cullmins);
3834 VectorCopy(rtlight->cullmaxs, rsurface.rtlight_cullmaxs);
3836 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3838 // compiled light, world available and can receive realtime lighting
3839 // retrieve leaf information
3840 numleafs = rtlight->static_numleafs;
3841 leaflist = rtlight->static_leaflist;
3842 leafpvs = rtlight->static_leafpvs;
3843 numsurfaces = rtlight->static_numsurfaces;
3844 surfacelist = rtlight->static_surfacelist;
3845 shadowtrispvs = rtlight->static_shadowtrispvs;
3846 lighttrispvs = rtlight->static_lighttrispvs;
3848 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3850 // dynamic light, world available and can receive realtime lighting
3851 // calculate lit surfaces and leafs
3852 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);
3853 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);
3854 leaflist = r_shadow_buffer_leaflist;
3855 leafpvs = r_shadow_buffer_leafpvs;
3856 surfacelist = r_shadow_buffer_surfacelist;
3857 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3858 lighttrispvs = r_shadow_buffer_lighttrispvs;
3859 // if the reduced leaf bounds are offscreen, skip it
3860 if (R_CullBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
3871 shadowtrispvs = NULL;
3872 lighttrispvs = NULL;
3874 // check if light is illuminating any visible leafs
3877 for (i = 0;i < numleafs;i++)
3878 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3883 // set up a scissor rectangle for this light
3884 if (R_Shadow_ScissorForBBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
3887 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3889 // make a list of lit entities and shadow casting entities
3890 numlightentities = 0;
3891 numlightentities_noselfshadow = 0;
3892 numshadowentities = 0;
3893 numshadowentities_noselfshadow = 0;
3894 // add dynamic entities that are lit by the light
3895 if (r_drawentities.integer)
3897 for (i = 0;i < r_refdef.scene.numentities;i++)
3900 entity_render_t *ent = r_refdef.scene.entities[i];
3902 if (!BoxesOverlap(ent->mins, ent->maxs, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
3904 // skip the object entirely if it is not within the valid
3905 // shadow-casting region (which includes the lit region)
3906 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rsurface.rtlight_numfrustumplanes, rsurface.rtlight_frustumplanes))
3908 if (!(model = ent->model))
3910 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
3912 // this entity wants to receive light, is visible, and is
3913 // inside the light box
3914 // TODO: check if the surfaces in the model can receive light
3915 // so now check if it's in a leaf seen by the light
3916 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))
3918 if (ent->flags & RENDER_NOSELFSHADOW)
3919 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
3921 lightentities[numlightentities++] = ent;
3922 // since it is lit, it probably also casts a shadow...
3923 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3924 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3925 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3927 // note: exterior models without the RENDER_NOSELFSHADOW
3928 // flag still create a RENDER_NOSELFSHADOW shadow but
3929 // are lit normally, this means that they are
3930 // self-shadowing but do not shadow other
3931 // RENDER_NOSELFSHADOW entities such as the gun
3932 // (very weird, but keeps the player shadow off the gun)
3933 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3934 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3936 shadowentities[numshadowentities++] = ent;
3939 else if (ent->flags & RENDER_SHADOW)
3941 // this entity is not receiving light, but may still need to
3943 // TODO: check if the surfaces in the model can cast shadow
3944 // now check if it is in a leaf seen by the light
3945 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))
3947 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3948 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3949 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3951 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3952 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3954 shadowentities[numshadowentities++] = ent;
3960 // return if there's nothing at all to light
3961 if (!numlightentities && !numsurfaces)
3964 // don't let sound skip if going slow
3965 if (r_refdef.scene.extraupdate)
3968 // make this the active rtlight for rendering purposes
3969 R_Shadow_RenderMode_ActiveLight(rtlight);
3970 // count this light in the r_speeds
3971 r_refdef.stats.lights++;
3973 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
3975 // optionally draw visible shape of the shadow volumes
3976 // for performance analysis by level designers
3977 R_Shadow_RenderMode_VisibleShadowVolumes();
3979 R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
3980 for (i = 0;i < numshadowentities;i++)
3981 R_Shadow_DrawEntityShadow(shadowentities[i]);
3982 for (i = 0;i < numshadowentities_noselfshadow;i++)
3983 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3986 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
3988 // optionally draw the illuminated areas
3989 // for performance analysis by level designers
3990 R_Shadow_RenderMode_VisibleLighting(false, false);
3992 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3993 for (i = 0;i < numlightentities;i++)
3994 R_Shadow_DrawEntityLight(lightentities[i]);
3995 for (i = 0;i < numlightentities_noselfshadow;i++)
3996 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3999 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
4001 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
4002 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
4003 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
4004 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
4005 lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
4006 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapping_maxsize.integer);
4008 if (castshadows && r_shadow_shadowmode >= 1 && r_shadow_shadowmode <= 3 && r_glsl.integer && gl_support_fragment_shader)
4013 r_shadow_shadowmaplod = 0;
4014 for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
4015 if ((r_shadow_shadowmapping_maxsize.integer >> i) > lodlinear)
4016 r_shadow_shadowmaplod = i;
4018 size = r_shadow_shadowmode == 3 ? r_shadow_shadowmapping_maxsize.integer >> r_shadow_shadowmaplod : lodlinear;
4019 size = bound(1, size, 2048);
4021 //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
4023 // render shadow casters into 6 sided depth texture
4024 for (side = 0;side < 6;side++)
4026 R_Shadow_RenderMode_ShadowMap(side, true, size);
4028 R_Shadow_DrawWorldShadow_ShadowMap(numsurfaces, surfacelist, shadowtrispvs);
4029 for (i = 0;i < numshadowentities;i++)
4030 R_Shadow_DrawEntityShadow(shadowentities[i]);
4033 if (numlightentities_noselfshadow)
4035 // render lighting using the depth texture as shadowmap
4036 // draw lighting in the unmasked areas
4037 R_Shadow_RenderMode_Lighting(false, false, true);
4038 for (i = 0;i < numlightentities_noselfshadow;i++)
4039 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4042 // render shadow casters into 6 sided depth texture
4043 for (side = 0;side < 6;side++)
4045 R_Shadow_RenderMode_ShadowMap(side, false, size);
4046 for (i = 0;i < numshadowentities_noselfshadow;i++)
4047 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
4050 // render lighting using the depth texture as shadowmap
4051 // draw lighting in the unmasked areas
4052 R_Shadow_RenderMode_Lighting(false, false, true);
4053 // draw lighting in the unmasked areas
4055 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4056 for (i = 0;i < numlightentities;i++)
4057 R_Shadow_DrawEntityLight(lightentities[i]);
4059 else if (castshadows && gl_stencil)
4061 // draw stencil shadow volumes to mask off pixels that are in shadow
4062 // so that they won't receive lighting
4063 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
4064 R_Shadow_ClearStencil();
4066 R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
4067 for (i = 0;i < numshadowentities;i++)
4068 R_Shadow_DrawEntityShadow(shadowentities[i]);
4069 if (numlightentities_noselfshadow)
4071 // draw lighting in the unmasked areas
4072 R_Shadow_RenderMode_Lighting(true, false, false);
4073 for (i = 0;i < numlightentities_noselfshadow;i++)
4074 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4076 // optionally draw the illuminated areas
4077 // for performance analysis by level designers
4078 if (r_showlighting.integer && r_refdef.view.showdebug)
4080 R_Shadow_RenderMode_VisibleLighting(!r_showdisabledepthtest.integer, false);
4081 for (i = 0;i < numlightentities_noselfshadow;i++)
4082 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4085 for (i = 0;i < numshadowentities_noselfshadow;i++)
4086 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
4088 if (numsurfaces + numlightentities)
4090 // draw lighting in the unmasked areas
4091 R_Shadow_RenderMode_Lighting(true, false, false);
4093 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4094 for (i = 0;i < numlightentities;i++)
4095 R_Shadow_DrawEntityLight(lightentities[i]);
4100 if (numsurfaces + numlightentities)
4102 // draw lighting in the unmasked areas
4103 R_Shadow_RenderMode_Lighting(false, false, false);
4105 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
4106 for (i = 0;i < numlightentities;i++)
4107 R_Shadow_DrawEntityLight(lightentities[i]);
4108 for (i = 0;i < numlightentities_noselfshadow;i++)
4109 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
4114 void R_Shadow_DrawLightSprites(void);
4115 void R_ShadowVolumeLighting(qboolean visible)
4123 if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, 2048) ||
4124 (r_shadow_shadowmode != 0) != (r_shadow_shadowmapping.integer != 0) ||
4125 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0) ||
4126 r_shadow_shadowmaptexturetype != r_shadow_shadowmapping_texturetype.integer ||
4127 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
4128 r_shadow_shadowmapprecision != r_shadow_shadowmapping_precision.integer ||
4129 r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
4130 R_Shadow_FreeShadowMaps();
4132 if (r_editlights.integer)
4133 R_Shadow_DrawLightSprites();
4135 R_Shadow_RenderMode_Begin();
4137 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4138 if (r_shadow_debuglight.integer >= 0)
4140 lightindex = r_shadow_debuglight.integer;
4141 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4142 if (light && (light->flags & flag))
4143 R_DrawRTLight(&light->rtlight, visible);
4147 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4148 for (lightindex = 0;lightindex < range;lightindex++)
4150 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4151 if (light && (light->flags & flag))
4152 R_DrawRTLight(&light->rtlight, visible);
4155 if (r_refdef.scene.rtdlight)
4156 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
4157 R_DrawRTLight(r_refdef.scene.lights[lnum], visible);
4159 R_Shadow_RenderMode_End();
4162 extern const float r_screenvertex3f[12];
4163 extern void R_SetupView(qboolean allowwaterclippingplane);
4164 extern void R_ResetViewRendering3D(void);
4165 extern void R_ResetViewRendering2D(void);
4166 extern cvar_t r_shadows;
4167 extern cvar_t r_shadows_darken;
4168 extern cvar_t r_shadows_drawafterrtlighting;
4169 extern cvar_t r_shadows_castfrombmodels;
4170 extern cvar_t r_shadows_throwdistance;
4171 extern cvar_t r_shadows_throwdirection;
4172 void R_DrawModelShadows(void)
4175 float relativethrowdistance;
4176 entity_render_t *ent;
4177 vec3_t relativelightorigin;
4178 vec3_t relativelightdirection;
4179 vec3_t relativeshadowmins, relativeshadowmaxs;
4180 vec3_t tmp, shadowdir;
4182 if (!r_drawentities.integer || !gl_stencil)
4186 R_ResetViewRendering3D();
4187 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4188 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4189 R_Shadow_RenderMode_Begin();
4190 R_Shadow_RenderMode_ActiveLight(NULL);
4191 r_shadow_lightscissor[0] = r_refdef.view.x;
4192 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
4193 r_shadow_lightscissor[2] = r_refdef.view.width;
4194 r_shadow_lightscissor[3] = r_refdef.view.height;
4195 R_Shadow_RenderMode_StencilShadowVolumes(false);
4198 if (r_shadows.integer == 2)
4200 Math_atov(r_shadows_throwdirection.string, shadowdir);
4201 VectorNormalize(shadowdir);
4204 R_Shadow_ClearStencil();
4206 for (i = 0;i < r_refdef.scene.numentities;i++)
4208 ent = r_refdef.scene.entities[i];
4210 // cast shadows from anything of the map (submodels are optional)
4211 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4213 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4214 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
4215 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
4216 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
4217 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4220 if(ent->entitynumber != 0)
4222 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
4223 int entnum, entnum2, recursion;
4224 entnum = entnum2 = ent->entitynumber;
4225 for(recursion = 32; recursion > 0; --recursion)
4227 entnum2 = cl.entities[entnum].state_current.tagentity;
4228 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
4233 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
4235 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
4236 // transform into modelspace of OUR entity
4237 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
4238 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
4241 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4244 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4247 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
4248 RSurf_ActiveModelEntity(ent, false, false);
4249 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4250 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4254 // not really the right mode, but this will disable any silly stencil features
4255 R_Shadow_RenderMode_End();
4257 // set up ortho view for rendering this pass
4258 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4259 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4260 //GL_ScissorTest(true);
4261 //R_Mesh_Matrix(&identitymatrix);
4262 //R_Mesh_ResetTextureState();
4263 R_ResetViewRendering2D();
4264 R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
4265 R_Mesh_ColorPointer(NULL, 0, 0);
4266 R_SetupGenericShader(false);
4268 // set up a darkening blend on shadowed areas
4269 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4270 //GL_DepthRange(0, 1);
4271 //GL_DepthTest(false);
4272 //GL_DepthMask(false);
4273 //GL_PolygonOffset(0, 0);CHECKGLERROR
4274 GL_Color(0, 0, 0, r_shadows_darken.value);
4275 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4276 //qglDepthFunc(GL_ALWAYS);CHECKGLERROR
4277 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
4278 qglStencilMask(~0);CHECKGLERROR
4279 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
4280 qglStencilFunc(GL_NOTEQUAL, 128, ~0);CHECKGLERROR
4282 // apply the blend to the shadowed areas
4283 R_Mesh_Draw(0, 4, 0, 2, NULL, polygonelements, 0, 0);
4285 // restore the viewport
4286 R_SetViewport(&r_refdef.view.viewport);
4288 // restore other state to normal
4289 //R_Shadow_RenderMode_End();
4292 void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4295 vec3_t centerorigin;
4296 // if it's too close, skip it
4297 if (VectorLength(rtlight->color) < (1.0f / 256.0f))
4299 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4302 if (usequery && r_numqueries + 2 <= r_maxqueries)
4304 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4305 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4306 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4309 // 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
4310 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
4311 qglDepthFunc(GL_ALWAYS);
4312 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);
4313 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4314 qglDepthFunc(GL_LEQUAL);
4315 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
4316 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);
4317 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4320 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4323 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4326 GLint allpixels = 0, visiblepixels = 0;
4327 // now we have to check the query result
4328 if (rtlight->corona_queryindex_visiblepixels)
4331 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
4332 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
4334 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
4335 if (visiblepixels < 1 || allpixels < 1)
4337 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
4338 cscale *= rtlight->corona_visibility;
4342 // FIXME: these traces should scan all render entities instead of cl.world
4343 if (CL_TraceLine(r_refdef.view.origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
4346 VectorScale(rtlight->color, cscale, color);
4347 if (VectorLength(color) > (1.0f / 256.0f))
4348 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);
4351 void R_DrawCoronas(void)
4359 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4361 if (r_waterstate.renderingscene)
4363 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4364 R_Mesh_Matrix(&identitymatrix);
4366 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4368 // check occlusion of coronas
4369 // use GL_ARB_occlusion_query if available
4370 // otherwise use raytraces
4372 usequery = gl_support_arb_occlusion_query && r_coronas_occlusionquery.integer;
4375 GL_ColorMask(0,0,0,0);
4376 if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
4377 if (r_maxqueries < R_MAX_OCCLUSION_QUERIES)
4380 r_maxqueries = (range + r_refdef.scene.numlights) * 4;
4381 r_maxqueries = min(r_maxqueries, R_MAX_OCCLUSION_QUERIES);
4383 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
4387 for (lightindex = 0;lightindex < range;lightindex++)
4389 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4392 rtlight = &light->rtlight;
4393 rtlight->corona_visibility = 0;
4394 rtlight->corona_queryindex_visiblepixels = 0;
4395 rtlight->corona_queryindex_allpixels = 0;
4396 if (!(rtlight->flags & flag))
4398 if (rtlight->corona <= 0)
4400 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4402 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4404 for (i = 0;i < r_refdef.scene.numlights;i++)
4406 rtlight = r_refdef.scene.lights[i];
4407 rtlight->corona_visibility = 0;
4408 rtlight->corona_queryindex_visiblepixels = 0;
4409 rtlight->corona_queryindex_allpixels = 0;
4410 if (!(rtlight->flags & flag))
4412 if (rtlight->corona <= 0)
4414 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4417 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4419 // now draw the coronas using the query data for intensity info
4420 for (lightindex = 0;lightindex < range;lightindex++)
4422 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4425 rtlight = &light->rtlight;
4426 if (rtlight->corona_visibility <= 0)
4428 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4430 for (i = 0;i < r_refdef.scene.numlights;i++)
4432 rtlight = r_refdef.scene.lights[i];
4433 if (rtlight->corona_visibility <= 0)
4435 if (gl_flashblend.integer)
4436 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4438 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4444 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
4445 typedef struct suffixinfo_s
4448 qboolean flipx, flipy, flipdiagonal;
4451 static suffixinfo_t suffix[3][6] =
4454 {"px", false, false, false},
4455 {"nx", false, false, false},
4456 {"py", false, false, false},
4457 {"ny", false, false, false},
4458 {"pz", false, false, false},
4459 {"nz", false, false, false}
4462 {"posx", false, false, false},
4463 {"negx", false, false, false},
4464 {"posy", false, false, false},
4465 {"negy", false, false, false},
4466 {"posz", false, false, false},
4467 {"negz", false, false, false}
4470 {"rt", true, false, true},
4471 {"lf", false, true, true},
4472 {"ft", true, true, false},
4473 {"bk", false, false, false},
4474 {"up", true, false, true},
4475 {"dn", true, false, true}
4479 static int componentorder[4] = {0, 1, 2, 3};
4481 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
4483 int i, j, cubemapsize;
4484 unsigned char *cubemappixels, *image_buffer;
4485 rtexture_t *cubemaptexture;
4487 // must start 0 so the first loadimagepixels has no requested width/height
4489 cubemappixels = NULL;
4490 cubemaptexture = NULL;
4491 // keep trying different suffix groups (posx, px, rt) until one loads
4492 for (j = 0;j < 3 && !cubemappixels;j++)
4494 // load the 6 images in the suffix group
4495 for (i = 0;i < 6;i++)
4497 // generate an image name based on the base and and suffix
4498 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
4500 if ((image_buffer = loadimagepixelsbgra(name, false, false)))
4502 // an image loaded, make sure width and height are equal
4503 if (image_width == image_height && (!cubemappixels || image_width == cubemapsize))
4505 // if this is the first image to load successfully, allocate the cubemap memory
4506 if (!cubemappixels && image_width >= 1)
4508 cubemapsize = image_width;
4509 // note this clears to black, so unavailable sides are black
4510 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
4512 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
4514 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);
4517 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
4519 Mem_Free(image_buffer);
4523 // if a cubemap loaded, upload it
4526 if (developer_loading.integer)
4527 Con_Printf("loading cubemap \"%s\"\n", basename);
4529 if (!r_shadow_filters_texturepool)
4530 r_shadow_filters_texturepool = R_AllocTexturePool();
4531 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_BGRA, TEXF_PRECACHE | (gl_texturecompression_lightcubemaps.integer ? TEXF_COMPRESS : 0) | TEXF_FORCELINEAR, NULL);
4532 Mem_Free(cubemappixels);
4536 Con_DPrintf("failed to load cubemap \"%s\"\n", basename);
4537 if (developer_loading.integer)
4539 Con_Printf("(tried tried images ");
4540 for (j = 0;j < 3;j++)
4541 for (i = 0;i < 6;i++)
4542 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
4543 Con_Print(" and was unable to find any of them).\n");
4546 return cubemaptexture;
4549 rtexture_t *R_Shadow_Cubemap(const char *basename)
4552 for (i = 0;i < numcubemaps;i++)
4553 if (!strcasecmp(cubemaps[i].basename, basename))
4554 return cubemaps[i].texture ? cubemaps[i].texture : r_texture_whitecube;
4555 if (i >= MAX_CUBEMAPS)
4556 return r_texture_whitecube;
4558 strlcpy(cubemaps[i].basename, basename, sizeof(cubemaps[i].basename));
4559 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
4560 return cubemaps[i].texture;
4563 void R_Shadow_FreeCubemaps(void)
4566 for (i = 0;i < numcubemaps;i++)
4568 if (developer_loading.integer)
4569 Con_Printf("unloading cubemap \"%s\"\n", cubemaps[i].basename);
4570 if (cubemaps[i].texture)
4571 R_FreeTexture(cubemaps[i].texture);
4575 R_FreeTexturePool(&r_shadow_filters_texturepool);
4578 dlight_t *R_Shadow_NewWorldLight(void)
4580 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4583 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)
4586 // validate parameters
4587 if (style < 0 || style >= MAX_LIGHTSTYLES)
4589 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
4595 // copy to light properties
4596 VectorCopy(origin, light->origin);
4597 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4598 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4599 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4600 light->color[0] = max(color[0], 0);
4601 light->color[1] = max(color[1], 0);
4602 light->color[2] = max(color[2], 0);
4603 light->radius = max(radius, 0);
4604 light->style = style;
4605 light->shadow = shadowenable;
4606 light->corona = corona;
4607 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4608 light->coronasizescale = coronasizescale;
4609 light->ambientscale = ambientscale;
4610 light->diffusescale = diffusescale;
4611 light->specularscale = specularscale;
4612 light->flags = flags;
4614 // update renderable light data
4615 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4616 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);
4619 void R_Shadow_FreeWorldLight(dlight_t *light)
4621 if (r_shadow_selectedlight == light)
4622 r_shadow_selectedlight = NULL;
4623 R_RTLight_Uncompile(&light->rtlight);
4624 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4627 void R_Shadow_ClearWorldLights(void)
4631 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4632 for (lightindex = 0;lightindex < range;lightindex++)
4634 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4636 R_Shadow_FreeWorldLight(light);
4638 r_shadow_selectedlight = NULL;
4639 R_Shadow_FreeCubemaps();
4642 void R_Shadow_SelectLight(dlight_t *light)
4644 if (r_shadow_selectedlight)
4645 r_shadow_selectedlight->selected = false;
4646 r_shadow_selectedlight = light;
4647 if (r_shadow_selectedlight)
4648 r_shadow_selectedlight->selected = true;
4651 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4653 // this is never batched (there can be only one)
4654 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);
4657 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4664 // this is never batched (due to the ent parameter changing every time)
4665 // so numsurfaces == 1 and surfacelist[0] == lightnumber
4666 const dlight_t *light = (dlight_t *)ent;
4669 VectorScale(light->color, intensity, spritecolor);
4670 if (VectorLength(spritecolor) < 0.1732f)
4671 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
4672 if (VectorLength(spritecolor) > 1.0f)
4673 VectorNormalize(spritecolor);
4675 // draw light sprite
4676 if (light->cubemapname[0] && !light->shadow)
4677 pic = r_editlights_sprcubemapnoshadowlight;
4678 else if (light->cubemapname[0])
4679 pic = r_editlights_sprcubemaplight;
4680 else if (!light->shadow)
4681 pic = r_editlights_sprnoshadowlight;
4683 pic = r_editlights_sprlight;
4684 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);
4685 // draw selection sprite if light is selected
4686 if (light->selected)
4687 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);
4688 // VorteX todo: add normalmode/realtime mode light overlay sprites?
4691 void R_Shadow_DrawLightSprites(void)
4695 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4696 for (lightindex = 0;lightindex < range;lightindex++)
4698 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4700 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
4702 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
4705 void R_Shadow_SelectLightInView(void)
4707 float bestrating, rating, temp[3];
4711 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4714 for (lightindex = 0;lightindex < range;lightindex++)
4716 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4719 VectorSubtract(light->origin, r_refdef.view.origin, temp);
4720 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
4723 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
4724 if (bestrating < rating && CL_TraceLine(light->origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1.0f)
4726 bestrating = rating;
4731 R_Shadow_SelectLight(best);
4734 void R_Shadow_LoadWorldLights(void)
4736 int n, a, style, shadow, flags;
4737 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
4738 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
4739 if (cl.worldmodel == NULL)
4741 Con_Print("No map loaded.\n");
4744 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4745 strlcat (name, ".rtlights", sizeof (name));
4746 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4756 for (;COM_Parse(t, true) && strcmp(
4757 if (COM_Parse(t, true))
4759 if (com_token[0] == '!')
4762 origin[0] = atof(com_token+1);
4765 origin[0] = atof(com_token);
4770 while (*s && *s != '\n' && *s != '\r')
4776 // check for modifier flags
4783 #if _MSC_VER >= 1400
4784 #define sscanf sscanf_s
4786 cubemapname[sizeof(cubemapname)-1] = 0;
4787 #if MAX_QPATH != 128
4788 #error update this code if MAX_QPATH changes
4790 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
4791 #if _MSC_VER >= 1400
4792 , sizeof(cubemapname)
4794 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
4797 flags = LIGHTFLAG_REALTIMEMODE;
4805 coronasizescale = 0.25f;
4807 VectorClear(angles);
4810 if (a < 9 || !strcmp(cubemapname, "\"\""))
4812 // remove quotes on cubemapname
4813 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
4816 namelen = strlen(cubemapname) - 2;
4817 memmove(cubemapname, cubemapname + 1, namelen);
4818 cubemapname[namelen] = '\0';
4822 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);
4825 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4833 Con_Printf("invalid rtlights file \"%s\"\n", name);
4834 Mem_Free(lightsstring);
4838 void R_Shadow_SaveWorldLights(void)
4842 size_t bufchars, bufmaxchars;
4844 char name[MAX_QPATH];
4845 char line[MAX_INPUTLINE];
4846 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
4847 // I hate lines which are 3 times my screen size :( --blub
4850 if (cl.worldmodel == NULL)
4852 Con_Print("No map loaded.\n");
4855 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4856 strlcat (name, ".rtlights", sizeof (name));
4857 bufchars = bufmaxchars = 0;
4859 for (lightindex = 0;lightindex < range;lightindex++)
4861 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4864 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
4865 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);
4866 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
4867 dpsnprintf(line, sizeof(line), "%s%f %f %f %f %f %f %f %d \"%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]);
4869 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);
4870 if (bufchars + strlen(line) > bufmaxchars)
4872 bufmaxchars = bufchars + strlen(line) + 2048;
4874 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
4878 memcpy(buf, oldbuf, bufchars);
4884 memcpy(buf + bufchars, line, strlen(line));
4885 bufchars += strlen(line);
4889 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
4894 void R_Shadow_LoadLightsFile(void)
4897 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
4898 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
4899 if (cl.worldmodel == NULL)
4901 Con_Print("No map loaded.\n");
4904 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4905 strlcat (name, ".lights", sizeof (name));
4906 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4914 while (*s && *s != '\n' && *s != '\r')
4920 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);
4924 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);
4927 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
4928 radius = bound(15, radius, 4096);
4929 VectorScale(color, (2.0f / (8388608.0f)), color);
4930 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
4938 Con_Printf("invalid lights file \"%s\"\n", name);
4939 Mem_Free(lightsstring);
4943 // tyrlite/hmap2 light types in the delay field
4944 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
4946 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
4948 int entnum, style, islight, skin, pflags, effects, type, n;
4951 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
4952 char key[256], value[MAX_INPUTLINE];
4954 if (cl.worldmodel == NULL)
4956 Con_Print("No map loaded.\n");
4959 // try to load a .ent file first
4960 FS_StripExtension (cl.worldmodel->name, key, sizeof (key));
4961 strlcat (key, ".ent", sizeof (key));
4962 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
4963 // and if that is not found, fall back to the bsp file entity string
4965 data = cl.worldmodel->brush.entities;
4968 for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
4970 type = LIGHTTYPE_MINUSX;
4971 origin[0] = origin[1] = origin[2] = 0;
4972 originhack[0] = originhack[1] = originhack[2] = 0;
4973 angles[0] = angles[1] = angles[2] = 0;
4974 color[0] = color[1] = color[2] = 1;
4975 light[0] = light[1] = light[2] = 1;light[3] = 300;
4976 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
4986 if (!COM_ParseToken_Simple(&data, false, false))
4988 if (com_token[0] == '}')
4989 break; // end of entity
4990 if (com_token[0] == '_')
4991 strlcpy(key, com_token + 1, sizeof(key));
4993 strlcpy(key, com_token, sizeof(key));
4994 while (key[strlen(key)-1] == ' ') // remove trailing spaces
4995 key[strlen(key)-1] = 0;
4996 if (!COM_ParseToken_Simple(&data, false, false))
4998 strlcpy(value, com_token, sizeof(value));
5000 // now that we have the key pair worked out...
5001 if (!strcmp("light", key))
5003 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
5007 light[0] = vec[0] * (1.0f / 256.0f);
5008 light[1] = vec[0] * (1.0f / 256.0f);
5009 light[2] = vec[0] * (1.0f / 256.0f);
5015 light[0] = vec[0] * (1.0f / 255.0f);
5016 light[1] = vec[1] * (1.0f / 255.0f);
5017 light[2] = vec[2] * (1.0f / 255.0f);
5021 else if (!strcmp("delay", key))
5023 else if (!strcmp("origin", key))
5024 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
5025 else if (!strcmp("angle", key))
5026 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
5027 else if (!strcmp("angles", key))
5028 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
5029 else if (!strcmp("color", key))
5030 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
5031 else if (!strcmp("wait", key))
5032 fadescale = atof(value);
5033 else if (!strcmp("classname", key))
5035 if (!strncmp(value, "light", 5))
5038 if (!strcmp(value, "light_fluoro"))
5043 overridecolor[0] = 1;
5044 overridecolor[1] = 1;
5045 overridecolor[2] = 1;
5047 if (!strcmp(value, "light_fluorospark"))
5052 overridecolor[0] = 1;
5053 overridecolor[1] = 1;
5054 overridecolor[2] = 1;
5056 if (!strcmp(value, "light_globe"))
5061 overridecolor[0] = 1;
5062 overridecolor[1] = 0.8;
5063 overridecolor[2] = 0.4;
5065 if (!strcmp(value, "light_flame_large_yellow"))
5070 overridecolor[0] = 1;
5071 overridecolor[1] = 0.5;
5072 overridecolor[2] = 0.1;
5074 if (!strcmp(value, "light_flame_small_yellow"))
5079 overridecolor[0] = 1;
5080 overridecolor[1] = 0.5;
5081 overridecolor[2] = 0.1;
5083 if (!strcmp(value, "light_torch_small_white"))
5088 overridecolor[0] = 1;
5089 overridecolor[1] = 0.5;
5090 overridecolor[2] = 0.1;
5092 if (!strcmp(value, "light_torch_small_walltorch"))
5097 overridecolor[0] = 1;
5098 overridecolor[1] = 0.5;
5099 overridecolor[2] = 0.1;
5103 else if (!strcmp("style", key))
5104 style = atoi(value);
5105 else if (!strcmp("skin", key))
5106 skin = (int)atof(value);
5107 else if (!strcmp("pflags", key))
5108 pflags = (int)atof(value);
5109 else if (!strcmp("effects", key))
5110 effects = (int)atof(value);
5111 else if (cl.worldmodel->type == mod_brushq3)
5113 if (!strcmp("scale", key))
5114 lightscale = atof(value);
5115 if (!strcmp("fade", key))
5116 fadescale = atof(value);
5121 if (lightscale <= 0)
5125 if (color[0] == color[1] && color[0] == color[2])
5127 color[0] *= overridecolor[0];
5128 color[1] *= overridecolor[1];
5129 color[2] *= overridecolor[2];
5131 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
5132 color[0] = color[0] * light[0];
5133 color[1] = color[1] * light[1];
5134 color[2] = color[2] * light[2];
5137 case LIGHTTYPE_MINUSX:
5139 case LIGHTTYPE_RECIPX:
5141 VectorScale(color, (1.0f / 16.0f), color);
5143 case LIGHTTYPE_RECIPXX:
5145 VectorScale(color, (1.0f / 16.0f), color);
5148 case LIGHTTYPE_NONE:
5152 case LIGHTTYPE_MINUSXX:
5155 VectorAdd(origin, originhack, origin);
5157 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);
5160 Mem_Free(entfiledata);
5164 void R_Shadow_SetCursorLocationForView(void)
5167 vec3_t dest, endpos;
5169 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
5170 trace = CL_TraceLine(r_refdef.view.origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
5171 if (trace.fraction < 1)
5173 dist = trace.fraction * r_editlights_cursordistance.value;
5174 push = r_editlights_cursorpushback.value;
5178 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
5179 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
5183 VectorClear( endpos );
5185 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5186 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5187 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
5190 void R_Shadow_UpdateWorldLightSelection(void)
5192 if (r_editlights.integer)
5194 R_Shadow_SetCursorLocationForView();
5195 R_Shadow_SelectLightInView();
5198 R_Shadow_SelectLight(NULL);
5201 void R_Shadow_EditLights_Clear_f(void)
5203 R_Shadow_ClearWorldLights();
5206 void R_Shadow_EditLights_Reload_f(void)
5210 strlcpy(r_shadow_mapname, cl.worldmodel->name, sizeof(r_shadow_mapname));
5211 R_Shadow_ClearWorldLights();
5212 R_Shadow_LoadWorldLights();
5213 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5215 R_Shadow_LoadLightsFile();
5216 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5217 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5221 void R_Shadow_EditLights_Save_f(void)
5225 R_Shadow_SaveWorldLights();
5228 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
5230 R_Shadow_ClearWorldLights();
5231 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5234 void R_Shadow_EditLights_ImportLightsFile_f(void)
5236 R_Shadow_ClearWorldLights();
5237 R_Shadow_LoadLightsFile();
5240 void R_Shadow_EditLights_Spawn_f(void)
5243 if (!r_editlights.integer)
5245 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5248 if (Cmd_Argc() != 1)
5250 Con_Print("r_editlights_spawn does not take parameters\n");
5253 color[0] = color[1] = color[2] = 1;
5254 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5257 void R_Shadow_EditLights_Edit_f(void)
5259 vec3_t origin, angles, color;
5260 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5261 int style, shadows, flags, normalmode, realtimemode;
5262 char cubemapname[MAX_INPUTLINE];
5263 if (!r_editlights.integer)
5265 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5268 if (!r_shadow_selectedlight)
5270 Con_Print("No selected light.\n");
5273 VectorCopy(r_shadow_selectedlight->origin, origin);
5274 VectorCopy(r_shadow_selectedlight->angles, angles);
5275 VectorCopy(r_shadow_selectedlight->color, color);
5276 radius = r_shadow_selectedlight->radius;
5277 style = r_shadow_selectedlight->style;
5278 if (r_shadow_selectedlight->cubemapname)
5279 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5282 shadows = r_shadow_selectedlight->shadow;
5283 corona = r_shadow_selectedlight->corona;
5284 coronasizescale = r_shadow_selectedlight->coronasizescale;
5285 ambientscale = r_shadow_selectedlight->ambientscale;
5286 diffusescale = r_shadow_selectedlight->diffusescale;
5287 specularscale = r_shadow_selectedlight->specularscale;
5288 flags = r_shadow_selectedlight->flags;
5289 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5290 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5291 if (!strcmp(Cmd_Argv(1), "origin"))
5293 if (Cmd_Argc() != 5)
5295 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5298 origin[0] = atof(Cmd_Argv(2));
5299 origin[1] = atof(Cmd_Argv(3));
5300 origin[2] = atof(Cmd_Argv(4));
5302 else if (!strcmp(Cmd_Argv(1), "originx"))
5304 if (Cmd_Argc() != 3)
5306 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5309 origin[0] = atof(Cmd_Argv(2));
5311 else if (!strcmp(Cmd_Argv(1), "originy"))
5313 if (Cmd_Argc() != 3)
5315 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5318 origin[1] = atof(Cmd_Argv(2));
5320 else if (!strcmp(Cmd_Argv(1), "originz"))
5322 if (Cmd_Argc() != 3)
5324 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5327 origin[2] = atof(Cmd_Argv(2));
5329 else if (!strcmp(Cmd_Argv(1), "move"))
5331 if (Cmd_Argc() != 5)
5333 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5336 origin[0] += atof(Cmd_Argv(2));
5337 origin[1] += atof(Cmd_Argv(3));
5338 origin[2] += atof(Cmd_Argv(4));
5340 else if (!strcmp(Cmd_Argv(1), "movex"))
5342 if (Cmd_Argc() != 3)
5344 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5347 origin[0] += atof(Cmd_Argv(2));
5349 else if (!strcmp(Cmd_Argv(1), "movey"))
5351 if (Cmd_Argc() != 3)
5353 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5356 origin[1] += atof(Cmd_Argv(2));
5358 else if (!strcmp(Cmd_Argv(1), "movez"))
5360 if (Cmd_Argc() != 3)
5362 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5365 origin[2] += atof(Cmd_Argv(2));
5367 else if (!strcmp(Cmd_Argv(1), "angles"))
5369 if (Cmd_Argc() != 5)
5371 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5374 angles[0] = atof(Cmd_Argv(2));
5375 angles[1] = atof(Cmd_Argv(3));
5376 angles[2] = atof(Cmd_Argv(4));
5378 else if (!strcmp(Cmd_Argv(1), "anglesx"))
5380 if (Cmd_Argc() != 3)
5382 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5385 angles[0] = atof(Cmd_Argv(2));
5387 else if (!strcmp(Cmd_Argv(1), "anglesy"))
5389 if (Cmd_Argc() != 3)
5391 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5394 angles[1] = atof(Cmd_Argv(2));
5396 else if (!strcmp(Cmd_Argv(1), "anglesz"))
5398 if (Cmd_Argc() != 3)
5400 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5403 angles[2] = atof(Cmd_Argv(2));
5405 else if (!strcmp(Cmd_Argv(1), "color"))
5407 if (Cmd_Argc() != 5)
5409 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
5412 color[0] = atof(Cmd_Argv(2));
5413 color[1] = atof(Cmd_Argv(3));
5414 color[2] = atof(Cmd_Argv(4));
5416 else if (!strcmp(Cmd_Argv(1), "radius"))
5418 if (Cmd_Argc() != 3)
5420 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5423 radius = atof(Cmd_Argv(2));
5425 else if (!strcmp(Cmd_Argv(1), "colorscale"))
5427 if (Cmd_Argc() == 3)
5429 double scale = atof(Cmd_Argv(2));
5436 if (Cmd_Argc() != 5)
5438 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
5441 color[0] *= atof(Cmd_Argv(2));
5442 color[1] *= atof(Cmd_Argv(3));
5443 color[2] *= atof(Cmd_Argv(4));
5446 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
5448 if (Cmd_Argc() != 3)
5450 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5453 radius *= atof(Cmd_Argv(2));
5455 else if (!strcmp(Cmd_Argv(1), "style"))
5457 if (Cmd_Argc() != 3)
5459 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5462 style = atoi(Cmd_Argv(2));
5464 else if (!strcmp(Cmd_Argv(1), "cubemap"))
5468 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5471 if (Cmd_Argc() == 3)
5472 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
5476 else if (!strcmp(Cmd_Argv(1), "shadows"))
5478 if (Cmd_Argc() != 3)
5480 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5483 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5485 else if (!strcmp(Cmd_Argv(1), "corona"))
5487 if (Cmd_Argc() != 3)
5489 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5492 corona = atof(Cmd_Argv(2));
5494 else if (!strcmp(Cmd_Argv(1), "coronasize"))
5496 if (Cmd_Argc() != 3)
5498 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5501 coronasizescale = atof(Cmd_Argv(2));
5503 else if (!strcmp(Cmd_Argv(1), "ambient"))
5505 if (Cmd_Argc() != 3)
5507 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5510 ambientscale = atof(Cmd_Argv(2));
5512 else if (!strcmp(Cmd_Argv(1), "diffuse"))
5514 if (Cmd_Argc() != 3)
5516 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5519 diffusescale = atof(Cmd_Argv(2));
5521 else if (!strcmp(Cmd_Argv(1), "specular"))
5523 if (Cmd_Argc() != 3)
5525 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5528 specularscale = atof(Cmd_Argv(2));
5530 else if (!strcmp(Cmd_Argv(1), "normalmode"))
5532 if (Cmd_Argc() != 3)
5534 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5537 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5539 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
5541 if (Cmd_Argc() != 3)
5543 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5546 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5550 Con_Print("usage: r_editlights_edit [property] [value]\n");
5551 Con_Print("Selected light's properties:\n");
5552 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5553 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5554 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5555 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
5556 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
5557 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
5558 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5559 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
5560 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
5561 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
5562 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
5563 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
5564 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5565 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5568 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5569 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5572 void R_Shadow_EditLights_EditAll_f(void)
5578 if (!r_editlights.integer)
5580 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5584 // EditLights doesn't seem to have a "remove" command or something so:
5585 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5586 for (lightindex = 0;lightindex < range;lightindex++)
5588 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5591 R_Shadow_SelectLight(light);
5592 R_Shadow_EditLights_Edit_f();
5596 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
5598 int lightnumber, lightcount;
5599 size_t lightindex, range;
5603 if (!r_editlights.integer)
5605 x = vid_conwidth.value - 240;
5607 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
5610 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5611 for (lightindex = 0;lightindex < range;lightindex++)
5613 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5616 if (light == r_shadow_selectedlight)
5617 lightnumber = lightindex;
5620 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;
5621 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;
5623 if (r_shadow_selectedlight == NULL)
5625 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;
5626 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;
5627 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;
5628 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;
5629 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;
5630 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;
5631 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;
5632 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;
5633 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;
5634 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;
5635 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;
5636 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;
5637 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;
5638 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;
5639 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;
5642 void R_Shadow_EditLights_ToggleShadow_f(void)
5644 if (!r_editlights.integer)
5646 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5649 if (!r_shadow_selectedlight)
5651 Con_Print("No selected light.\n");
5654 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);
5657 void R_Shadow_EditLights_ToggleCorona_f(void)
5659 if (!r_editlights.integer)
5661 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5664 if (!r_shadow_selectedlight)
5666 Con_Print("No selected light.\n");
5669 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);
5672 void R_Shadow_EditLights_Remove_f(void)
5674 if (!r_editlights.integer)
5676 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
5679 if (!r_shadow_selectedlight)
5681 Con_Print("No selected light.\n");
5684 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
5685 r_shadow_selectedlight = NULL;
5688 void R_Shadow_EditLights_Help_f(void)
5691 "Documentation on r_editlights system:\n"
5693 "r_editlights : enable/disable editing mode\n"
5694 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
5695 "r_editlights_cursorpushback : push back cursor this far from surface\n"
5696 "r_editlights_cursorpushoff : push cursor off surface this far\n"
5697 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
5698 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
5700 "r_editlights_help : this help\n"
5701 "r_editlights_clear : remove all lights\n"
5702 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
5703 "r_editlights_save : save to .rtlights file\n"
5704 "r_editlights_spawn : create a light with default settings\n"
5705 "r_editlights_edit command : edit selected light - more documentation below\n"
5706 "r_editlights_remove : remove selected light\n"
5707 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
5708 "r_editlights_importlightentitiesfrommap : reload light entities\n"
5709 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
5711 "origin x y z : set light location\n"
5712 "originx x: set x component of light location\n"
5713 "originy y: set y component of light location\n"
5714 "originz z: set z component of light location\n"
5715 "move x y z : adjust light location\n"
5716 "movex x: adjust x component of light location\n"
5717 "movey y: adjust y component of light location\n"
5718 "movez z: adjust z component of light location\n"
5719 "angles x y z : set light angles\n"
5720 "anglesx x: set x component of light angles\n"
5721 "anglesy y: set y component of light angles\n"
5722 "anglesz z: set z component of light angles\n"
5723 "color r g b : set color of light (can be brighter than 1 1 1)\n"
5724 "radius radius : set radius (size) of light\n"
5725 "colorscale grey : multiply color of light (1 does nothing)\n"
5726 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
5727 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
5728 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
5729 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
5730 "cubemap basename : set filter cubemap of light (not yet supported)\n"
5731 "shadows 1/0 : turn on/off shadows\n"
5732 "corona n : set corona intensity\n"
5733 "coronasize n : set corona size (0-1)\n"
5734 "ambient n : set ambient intensity (0-1)\n"
5735 "diffuse n : set diffuse intensity (0-1)\n"
5736 "specular n : set specular intensity (0-1)\n"
5737 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
5738 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
5739 "<nothing> : print light properties to console\n"
5743 void R_Shadow_EditLights_CopyInfo_f(void)
5745 if (!r_editlights.integer)
5747 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
5750 if (!r_shadow_selectedlight)
5752 Con_Print("No selected light.\n");
5755 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
5756 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
5757 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
5758 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
5759 if (r_shadow_selectedlight->cubemapname)
5760 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
5762 r_shadow_bufferlight.cubemapname[0] = 0;
5763 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
5764 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
5765 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
5766 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
5767 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
5768 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
5769 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
5772 void R_Shadow_EditLights_PasteInfo_f(void)
5774 if (!r_editlights.integer)
5776 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
5779 if (!r_shadow_selectedlight)
5781 Con_Print("No selected light.\n");
5784 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);
5787 void R_Shadow_EditLights_Init(void)
5789 Cvar_RegisterVariable(&r_editlights);
5790 Cvar_RegisterVariable(&r_editlights_cursordistance);
5791 Cvar_RegisterVariable(&r_editlights_cursorpushback);
5792 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
5793 Cvar_RegisterVariable(&r_editlights_cursorgrid);
5794 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
5795 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
5796 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
5797 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)");
5798 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
5799 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
5800 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
5801 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)");
5802 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
5803 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
5804 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
5805 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
5806 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
5807 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
5808 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)");
5814 =============================================================================
5818 =============================================================================
5821 void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, int dynamic)
5823 VectorClear(diffusecolor);
5824 VectorClear(diffusenormal);
5826 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
5828 ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_refdef.scene.ambient * (2.0f / 128.0f);
5829 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
5832 VectorSet(ambientcolor, 1, 1, 1);
5839 for (i = 0;i < r_refdef.scene.numlights;i++)
5841 light = r_refdef.scene.lights[i];
5842 Matrix4x4_Transform(&light->matrix_worldtolight, p, v);
5843 f = 1 - VectorLength2(v);
5844 if (f > 0 && CL_TraceLine(p, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
5845 VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);