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 float r_shadow_shadowmap_texturescale[2];
175 float r_shadow_shadowmap_parameters[4];
176 int r_shadow_drawbuffer;
177 int r_shadow_readbuffer;
178 GLuint r_shadow_fborectangle;
179 GLuint r_shadow_fbocubeside[R_SHADOW_SHADOWMAP_NUMCUBEMAPS][6];
180 GLuint r_shadow_fbo2d;
181 int r_shadow_shadowmode;
182 int r_shadow_shadowmapfilterquality;
183 int r_shadow_shadowmaptexturetype;
184 int r_shadow_shadowmapprecision;
185 int r_shadow_shadowmapmaxsize;
186 qboolean r_shadow_shadowmapvsdct;
187 qboolean r_shadow_shadowmapsampler;
188 int r_shadow_shadowmappcf;
189 int r_shadow_shadowmapborder;
190 int r_shadow_lightscissor[4];
192 int maxshadowtriangles;
195 int maxshadowvertices;
196 float *shadowvertex3f;
209 int r_shadow_buffer_numleafpvsbytes;
210 unsigned char *r_shadow_buffer_visitingleafpvs;
211 unsigned char *r_shadow_buffer_leafpvs;
212 int *r_shadow_buffer_leaflist;
214 int r_shadow_buffer_numsurfacepvsbytes;
215 unsigned char *r_shadow_buffer_surfacepvs;
216 int *r_shadow_buffer_surfacelist;
218 int r_shadow_buffer_numshadowtrispvsbytes;
219 unsigned char *r_shadow_buffer_shadowtrispvs;
220 int r_shadow_buffer_numlighttrispvsbytes;
221 unsigned char *r_shadow_buffer_lighttrispvs;
223 rtexturepool_t *r_shadow_texturepool;
224 rtexture_t *r_shadow_attenuationgradienttexture;
225 rtexture_t *r_shadow_attenuation2dtexture;
226 rtexture_t *r_shadow_attenuation3dtexture;
227 rtexture_t *r_shadow_lightcorona;
228 rtexture_t *r_shadow_shadowmaprectangletexture;
229 rtexture_t *r_shadow_shadowmap2dtexture;
230 rtexture_t *r_shadow_shadowmapcubetexture[R_SHADOW_SHADOWMAP_NUMCUBEMAPS];
231 rtexture_t *r_shadow_shadowmapvsdcttexture;
232 int r_shadow_shadowmapsize; // changes for each light based on distance
233 int r_shadow_shadowmaplod; // changes for each light based on distance
235 // lights are reloaded when this changes
236 char r_shadow_mapname[MAX_QPATH];
238 // used only for light filters (cubemaps)
239 rtexturepool_t *r_shadow_filters_texturepool;
241 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"};
242 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"};
243 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
244 cvar_t r_shadow_usenormalmap = {CVAR_SAVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"};
245 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)"};
246 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"};
247 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
248 cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
249 cvar_t r_shadow_glossexact = {0, "r_shadow_glossexact", "0", "use exact reflection math for gloss (slightly slower, but should look a tad better)"};
250 cvar_t r_shadow_lightattenuationdividebias = {0, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"};
251 cvar_t r_shadow_lightattenuationlinearscale = {0, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"};
252 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
253 cvar_t r_shadow_lightradiusscale = {0, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
254 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1", "use portal culling to exactly determine lit triangles when compiling world lights"};
255 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000", "how far to cast shadows"};
256 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)"};
257 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
258 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
259 cvar_t r_shadow_realtime_dlight_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
260 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
261 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)"};
262 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"};
263 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
264 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
265 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"};
266 cvar_t r_shadow_realtime_world_compilesvbsp = {0, "r_shadow_realtime_world_compilesvbsp", "1", "enables svbsp optimization during compilation"};
267 cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "1", "enables portal-based culling optimization during compilation"};
268 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)"};
269 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"};
270 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"};
271 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)"};
272 cvar_t r_shadow_shadowmapping_precision = {CVAR_SAVE, "r_shadow_shadowmapping_precision", "24", "requested minimum shadowmap texture precision"};
273 cvar_t r_shadow_shadowmapping_vsdct = {CVAR_SAVE, "r_shadow_shadowmapping_vsdct", "1", "enables use of virtual shadow depth cube texture"};
274 cvar_t r_shadow_shadowmapping_minsize = {CVAR_SAVE, "r_shadow_shadowmapping_minsize", "32", "shadowmap size limit"};
275 cvar_t r_shadow_shadowmapping_maxsize = {CVAR_SAVE, "r_shadow_shadowmapping_maxsize", "512", "shadowmap size limit"};
276 cvar_t r_shadow_shadowmapping_lod_bias = {CVAR_SAVE, "r_shadow_shadowmapping_lod_bias", "16", "shadowmap size bias"};
277 cvar_t r_shadow_shadowmapping_lod_scale = {CVAR_SAVE, "r_shadow_shadowmapping_lod_scale", "128", "shadowmap size scaling parameter"};
278 cvar_t r_shadow_shadowmapping_bordersize = {CVAR_SAVE, "r_shadow_shadowmapping_bordersize", "4", "shadowmap size bias for filtering"};
279 cvar_t r_shadow_shadowmapping_nearclip = {CVAR_SAVE, "r_shadow_shadowmapping_nearclip", "1", "shadowmap nearclip in world units"};
280 cvar_t r_shadow_shadowmapping_bias = {CVAR_SAVE, "r_shadow_shadowmapping_bias", "0.03", "shadowmap bias parameter (this is multiplied by nearclip * 1024 / lodsize)"};
281 cvar_t r_shadow_culltriangles = {0, "r_shadow_culltriangles", "1", "performs more expensive tests to remove unnecessary triangles of lit surfaces"};
282 cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
283 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)"};
284 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)"};
285 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "1", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
286 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"};
287 cvar_t r_coronas_occlusionquery = {CVAR_SAVE, "r_coronas_occlusionquery", "1", "use GL_ARB_occlusion_query extension if supported (fades coronas according to visibility)"};
288 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
289 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
290 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
291 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
292 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
293 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
294 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
295 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
296 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
298 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
299 #define ATTENTABLESIZE 256
300 // 1D gradient, 2D circle and 3D sphere attenuation textures
301 #define ATTEN1DSIZE 32
302 #define ATTEN2DSIZE 64
303 #define ATTEN3DSIZE 32
305 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
306 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
307 static float r_shadow_attentable[ATTENTABLESIZE+1];
309 rtlight_t *r_shadow_compilingrtlight;
310 static memexpandablearray_t r_shadow_worldlightsarray;
311 dlight_t *r_shadow_selectedlight;
312 dlight_t r_shadow_bufferlight;
313 vec3_t r_editlights_cursorlocation;
315 extern int con_vislines;
317 typedef struct cubemapinfo_s
324 #define MAX_CUBEMAPS 256
325 static int numcubemaps;
326 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
328 void R_Shadow_UncompileWorldLights(void);
329 void R_Shadow_ClearWorldLights(void);
330 void R_Shadow_SaveWorldLights(void);
331 void R_Shadow_LoadWorldLights(void);
332 void R_Shadow_LoadLightsFile(void);
333 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
334 void R_Shadow_EditLights_Reload_f(void);
335 void R_Shadow_ValidateCvars(void);
336 static void R_Shadow_MakeTextures(void);
338 // VorteX: custom editor light sprites
339 #define EDLIGHTSPRSIZE 8
340 cachepic_t *r_editlights_sprcursor;
341 cachepic_t *r_editlights_sprlight;
342 cachepic_t *r_editlights_sprnoshadowlight;
343 cachepic_t *r_editlights_sprcubemaplight;
344 cachepic_t *r_editlights_sprcubemapnoshadowlight;
345 cachepic_t *r_editlights_sprselection;
347 void R_Shadow_SetShadowMode(void)
349 r_shadow_shadowmapmaxsize = bound(1, r_shadow_shadowmapping_maxsize.integer, 2048);
350 r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer != 0;
351 r_shadow_shadowmapfilterquality = r_shadow_shadowmapping_filterquality.integer;
352 r_shadow_shadowmaptexturetype = r_shadow_shadowmapping_texturetype.integer;
353 r_shadow_shadowmapprecision = r_shadow_shadowmapping_precision.integer;
354 r_shadow_shadowmapborder = bound(0, r_shadow_shadowmapping_bordersize.integer, 16);
355 r_shadow_shadowmaplod = -1;
356 r_shadow_shadowmapsampler = false;
357 r_shadow_shadowmappcf = 0;
358 r_shadow_shadowmode = 0;
359 if(r_shadow_shadowmapping.integer)
361 if(r_shadow_shadowmapfilterquality < 0)
363 if(strstr(gl_vendor, "NVIDIA"))
365 r_shadow_shadowmapsampler = gl_support_arb_shadow;
366 r_shadow_shadowmappcf = 1;
368 else if(gl_support_amd_texture_texture4 || gl_support_arb_texture_gather)
369 r_shadow_shadowmappcf = 1;
370 else if(strstr(gl_vendor, "ATI"))
371 r_shadow_shadowmappcf = 1;
373 r_shadow_shadowmapsampler = gl_support_arb_shadow;
377 switch (r_shadow_shadowmapfilterquality)
380 r_shadow_shadowmapsampler = gl_support_arb_shadow;
383 r_shadow_shadowmapsampler = gl_support_arb_shadow;
384 r_shadow_shadowmappcf = 1;
387 r_shadow_shadowmappcf = 1;
390 r_shadow_shadowmappcf = 2;
394 r_shadow_shadowmode = r_shadow_shadowmaptexturetype;
395 if(r_shadow_shadowmode <= 0)
397 if((gl_support_amd_texture_texture4 || gl_support_arb_texture_gather) && r_shadow_shadowmappcf && !r_shadow_shadowmapsampler)
398 r_shadow_shadowmode = 1;
399 else if(gl_texturerectangle)
400 r_shadow_shadowmode = 2;
402 r_shadow_shadowmode = 1;
407 void R_Shadow_FreeShadowMaps(void)
411 R_Shadow_SetShadowMode();
413 if (r_shadow_fborectangle)
414 qglDeleteFramebuffersEXT(1, &r_shadow_fborectangle);
415 r_shadow_fborectangle = 0;
419 qglDeleteFramebuffersEXT(1, &r_shadow_fbo2d);
422 for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
423 if (r_shadow_fbocubeside[i][0])
424 qglDeleteFramebuffersEXT(6, r_shadow_fbocubeside[i]);
425 memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
428 if (r_shadow_shadowmaprectangletexture)
429 R_FreeTexture(r_shadow_shadowmaprectangletexture);
430 r_shadow_shadowmaprectangletexture = NULL;
432 if (r_shadow_shadowmap2dtexture)
433 R_FreeTexture(r_shadow_shadowmap2dtexture);
434 r_shadow_shadowmap2dtexture = NULL;
436 for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
437 if (r_shadow_shadowmapcubetexture[i])
438 R_FreeTexture(r_shadow_shadowmapcubetexture[i]);
439 memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
441 if (r_shadow_shadowmapvsdcttexture)
442 R_FreeTexture(r_shadow_shadowmapvsdcttexture);
443 r_shadow_shadowmapvsdcttexture = NULL;
448 void r_shadow_start(void)
450 // allocate vertex processing arrays
452 r_shadow_attenuationgradienttexture = NULL;
453 r_shadow_attenuation2dtexture = NULL;
454 r_shadow_attenuation3dtexture = NULL;
455 r_shadow_shadowmode = 0;
456 r_shadow_shadowmaprectangletexture = NULL;
457 r_shadow_shadowmap2dtexture = NULL;
458 memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
459 r_shadow_shadowmapvsdcttexture = NULL;
460 r_shadow_shadowmapmaxsize = 0;
461 r_shadow_shadowmapsize = 0;
462 r_shadow_shadowmaplod = 0;
463 r_shadow_shadowmapfilterquality = 0;
464 r_shadow_shadowmaptexturetype = 0;
465 r_shadow_shadowmapprecision = 0;
466 r_shadow_shadowmapvsdct = false;
467 r_shadow_shadowmapsampler = false;
468 r_shadow_shadowmappcf = 0;
469 r_shadow_fborectangle = 0;
471 memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
473 R_Shadow_FreeShadowMaps();
475 r_shadow_texturepool = NULL;
476 r_shadow_filters_texturepool = NULL;
477 R_Shadow_ValidateCvars();
478 R_Shadow_MakeTextures();
479 maxshadowtriangles = 0;
480 shadowelements = NULL;
481 maxshadowvertices = 0;
482 shadowvertex3f = NULL;
490 shadowmarklist = NULL;
492 r_shadow_buffer_numleafpvsbytes = 0;
493 r_shadow_buffer_visitingleafpvs = NULL;
494 r_shadow_buffer_leafpvs = NULL;
495 r_shadow_buffer_leaflist = NULL;
496 r_shadow_buffer_numsurfacepvsbytes = 0;
497 r_shadow_buffer_surfacepvs = NULL;
498 r_shadow_buffer_surfacelist = NULL;
499 r_shadow_buffer_numshadowtrispvsbytes = 0;
500 r_shadow_buffer_shadowtrispvs = NULL;
501 r_shadow_buffer_numlighttrispvsbytes = 0;
502 r_shadow_buffer_lighttrispvs = NULL;
505 void r_shadow_shutdown(void)
508 R_Shadow_UncompileWorldLights();
510 R_Shadow_FreeShadowMaps();
514 r_shadow_attenuationgradienttexture = NULL;
515 r_shadow_attenuation2dtexture = NULL;
516 r_shadow_attenuation3dtexture = NULL;
517 R_FreeTexturePool(&r_shadow_texturepool);
518 R_FreeTexturePool(&r_shadow_filters_texturepool);
519 maxshadowtriangles = 0;
521 Mem_Free(shadowelements);
522 shadowelements = NULL;
524 Mem_Free(shadowvertex3f);
525 shadowvertex3f = NULL;
528 Mem_Free(vertexupdate);
531 Mem_Free(vertexremap);
537 Mem_Free(shadowmark);
540 Mem_Free(shadowmarklist);
541 shadowmarklist = NULL;
543 r_shadow_buffer_numleafpvsbytes = 0;
544 if (r_shadow_buffer_visitingleafpvs)
545 Mem_Free(r_shadow_buffer_visitingleafpvs);
546 r_shadow_buffer_visitingleafpvs = NULL;
547 if (r_shadow_buffer_leafpvs)
548 Mem_Free(r_shadow_buffer_leafpvs);
549 r_shadow_buffer_leafpvs = NULL;
550 if (r_shadow_buffer_leaflist)
551 Mem_Free(r_shadow_buffer_leaflist);
552 r_shadow_buffer_leaflist = NULL;
553 r_shadow_buffer_numsurfacepvsbytes = 0;
554 if (r_shadow_buffer_surfacepvs)
555 Mem_Free(r_shadow_buffer_surfacepvs);
556 r_shadow_buffer_surfacepvs = NULL;
557 if (r_shadow_buffer_surfacelist)
558 Mem_Free(r_shadow_buffer_surfacelist);
559 r_shadow_buffer_surfacelist = NULL;
560 r_shadow_buffer_numshadowtrispvsbytes = 0;
561 if (r_shadow_buffer_shadowtrispvs)
562 Mem_Free(r_shadow_buffer_shadowtrispvs);
563 r_shadow_buffer_numlighttrispvsbytes = 0;
564 if (r_shadow_buffer_lighttrispvs)
565 Mem_Free(r_shadow_buffer_lighttrispvs);
568 void r_shadow_newmap(void)
570 if (cl.worldmodel && strncmp(cl.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
571 R_Shadow_EditLights_Reload_f();
574 void R_Shadow_Help_f(void)
577 "Documentation on r_shadow system:\n"
579 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
580 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
581 "r_shadow_debuglight : render only this light number (-1 = all)\n"
582 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
583 "r_shadow_gloss2intensity : brightness of forced gloss\n"
584 "r_shadow_glossintensity : brightness of textured gloss\n"
585 "r_shadow_lightattenuationlinearscale : used to generate attenuation texture\n"
586 "r_shadow_lightattenuationdividebias : used to generate attenuation texture\n"
587 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
588 "r_shadow_lightradiusscale : scale rendering radius of all lights\n"
589 "r_shadow_portallight : use portal visibility for static light precomputation\n"
590 "r_shadow_projectdistance : shadow volume projection distance\n"
591 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
592 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
593 "r_shadow_realtime_world : use high quality world lighting mode\n"
594 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
595 "r_shadow_realtime_world_shadows : cast shadows from world lights\n"
596 "r_shadow_realtime_world_compile : compile surface/visibility information\n"
597 "r_shadow_realtime_world_compileshadow : compile shadow geometry\n"
598 "r_shadow_scissor : use scissor optimization\n"
599 "r_shadow_polygonfactor : nudge shadow volumes closer/further\n"
600 "r_shadow_polygonoffset : nudge shadow volumes closer/further\n"
601 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
602 "r_showlighting : useful for performance testing; bright = slow!\n"
603 "r_showshadowvolumes : useful for performance testing; bright = slow!\n"
605 "r_shadow_help : this help\n"
609 void R_Shadow_Init(void)
611 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
612 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
613 Cvar_RegisterVariable(&r_shadow_usenormalmap);
614 Cvar_RegisterVariable(&r_shadow_debuglight);
615 Cvar_RegisterVariable(&r_shadow_gloss);
616 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
617 Cvar_RegisterVariable(&r_shadow_glossintensity);
618 Cvar_RegisterVariable(&r_shadow_glossexponent);
619 Cvar_RegisterVariable(&r_shadow_glossexact);
620 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
621 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
622 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
623 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
624 Cvar_RegisterVariable(&r_shadow_portallight);
625 Cvar_RegisterVariable(&r_shadow_projectdistance);
626 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
627 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
628 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
629 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
630 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
631 Cvar_RegisterVariable(&r_shadow_realtime_world);
632 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
633 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
634 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
635 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
636 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
637 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
638 Cvar_RegisterVariable(&r_shadow_scissor);
639 Cvar_RegisterVariable(&r_shadow_shadowmapping);
640 Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
641 Cvar_RegisterVariable(&r_shadow_shadowmapping_texturetype);
642 Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
643 Cvar_RegisterVariable(&r_shadow_shadowmapping_precision);
644 Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
645 Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
646 Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
647 Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
648 Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
649 Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
650 Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
651 Cvar_RegisterVariable(&r_shadow_culltriangles);
652 Cvar_RegisterVariable(&r_shadow_polygonfactor);
653 Cvar_RegisterVariable(&r_shadow_polygonoffset);
654 Cvar_RegisterVariable(&r_shadow_texture3d);
655 Cvar_RegisterVariable(&r_coronas);
656 Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
657 Cvar_RegisterVariable(&r_coronas_occlusionquery);
658 Cvar_RegisterVariable(&gl_flashblend);
659 Cvar_RegisterVariable(&gl_ext_separatestencil);
660 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
661 if (gamemode == GAME_TENEBRAE)
663 Cvar_SetValue("r_shadow_gloss", 2);
664 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
666 Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f, "prints documentation on console commands and variables used by realtime lighting and shadowing system");
667 R_Shadow_EditLights_Init();
668 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
669 maxshadowtriangles = 0;
670 shadowelements = NULL;
671 maxshadowvertices = 0;
672 shadowvertex3f = NULL;
680 shadowmarklist = NULL;
682 r_shadow_buffer_numleafpvsbytes = 0;
683 r_shadow_buffer_visitingleafpvs = NULL;
684 r_shadow_buffer_leafpvs = NULL;
685 r_shadow_buffer_leaflist = NULL;
686 r_shadow_buffer_numsurfacepvsbytes = 0;
687 r_shadow_buffer_surfacepvs = NULL;
688 r_shadow_buffer_surfacelist = NULL;
689 r_shadow_buffer_shadowtrispvs = NULL;
690 r_shadow_buffer_lighttrispvs = NULL;
691 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
694 matrix4x4_t matrix_attenuationxyz =
697 {0.5, 0.0, 0.0, 0.5},
698 {0.0, 0.5, 0.0, 0.5},
699 {0.0, 0.0, 0.5, 0.5},
704 matrix4x4_t matrix_attenuationz =
707 {0.0, 0.0, 0.5, 0.5},
708 {0.0, 0.0, 0.0, 0.5},
709 {0.0, 0.0, 0.0, 0.5},
714 void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles)
716 // make sure shadowelements is big enough for this volume
717 if (maxshadowtriangles < numtriangles)
719 maxshadowtriangles = numtriangles;
721 Mem_Free(shadowelements);
722 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[24]));
724 // make sure shadowvertex3f is big enough for this volume
725 if (maxshadowvertices < numvertices)
727 maxshadowvertices = numvertices;
729 Mem_Free(shadowvertex3f);
730 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[6]));
734 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
736 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
737 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
738 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
739 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
740 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
742 if (r_shadow_buffer_visitingleafpvs)
743 Mem_Free(r_shadow_buffer_visitingleafpvs);
744 if (r_shadow_buffer_leafpvs)
745 Mem_Free(r_shadow_buffer_leafpvs);
746 if (r_shadow_buffer_leaflist)
747 Mem_Free(r_shadow_buffer_leaflist);
748 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
749 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
750 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
751 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
753 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
755 if (r_shadow_buffer_surfacepvs)
756 Mem_Free(r_shadow_buffer_surfacepvs);
757 if (r_shadow_buffer_surfacelist)
758 Mem_Free(r_shadow_buffer_surfacelist);
759 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
760 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
761 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
763 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
765 if (r_shadow_buffer_shadowtrispvs)
766 Mem_Free(r_shadow_buffer_shadowtrispvs);
767 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
768 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
770 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
772 if (r_shadow_buffer_lighttrispvs)
773 Mem_Free(r_shadow_buffer_lighttrispvs);
774 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
775 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
779 void R_Shadow_PrepareShadowMark(int numtris)
781 // make sure shadowmark is big enough for this volume
782 if (maxshadowmark < numtris)
784 maxshadowmark = numtris;
786 Mem_Free(shadowmark);
788 Mem_Free(shadowmarklist);
789 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
790 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
794 // if shadowmarkcount wrapped we clear the array and adjust accordingly
795 if (shadowmarkcount == 0)
798 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
803 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)
806 int outtriangles = 0, outvertices = 0;
809 float ratio, direction[3], projectvector[3];
811 if (projectdirection)
812 VectorScale(projectdirection, projectdistance, projectvector);
814 VectorClear(projectvector);
816 // create the vertices
817 if (projectdirection)
819 for (i = 0;i < numshadowmarktris;i++)
821 element = inelement3i + shadowmarktris[i] * 3;
822 for (j = 0;j < 3;j++)
824 if (vertexupdate[element[j]] != vertexupdatenum)
826 vertexupdate[element[j]] = vertexupdatenum;
827 vertexremap[element[j]] = outvertices;
828 vertex = invertex3f + element[j] * 3;
829 // project one copy of the vertex according to projectvector
830 VectorCopy(vertex, outvertex3f);
831 VectorAdd(vertex, projectvector, (outvertex3f + 3));
840 for (i = 0;i < numshadowmarktris;i++)
842 element = inelement3i + shadowmarktris[i] * 3;
843 for (j = 0;j < 3;j++)
845 if (vertexupdate[element[j]] != vertexupdatenum)
847 vertexupdate[element[j]] = vertexupdatenum;
848 vertexremap[element[j]] = outvertices;
849 vertex = invertex3f + element[j] * 3;
850 // project one copy of the vertex to the sphere radius of the light
851 // (FIXME: would projecting it to the light box be better?)
852 VectorSubtract(vertex, projectorigin, direction);
853 ratio = projectdistance / VectorLength(direction);
854 VectorCopy(vertex, outvertex3f);
855 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
863 if (r_shadow_frontsidecasting.integer)
865 for (i = 0;i < numshadowmarktris;i++)
867 int remappedelement[3];
869 const int *neighbortriangle;
871 markindex = shadowmarktris[i] * 3;
872 element = inelement3i + markindex;
873 neighbortriangle = inneighbor3i + markindex;
874 // output the front and back triangles
875 outelement3i[0] = vertexremap[element[0]];
876 outelement3i[1] = vertexremap[element[1]];
877 outelement3i[2] = vertexremap[element[2]];
878 outelement3i[3] = vertexremap[element[2]] + 1;
879 outelement3i[4] = vertexremap[element[1]] + 1;
880 outelement3i[5] = vertexremap[element[0]] + 1;
884 // output the sides (facing outward from this triangle)
885 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
887 remappedelement[0] = vertexremap[element[0]];
888 remappedelement[1] = vertexremap[element[1]];
889 outelement3i[0] = remappedelement[1];
890 outelement3i[1] = remappedelement[0];
891 outelement3i[2] = remappedelement[0] + 1;
892 outelement3i[3] = remappedelement[1];
893 outelement3i[4] = remappedelement[0] + 1;
894 outelement3i[5] = remappedelement[1] + 1;
899 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
901 remappedelement[1] = vertexremap[element[1]];
902 remappedelement[2] = vertexremap[element[2]];
903 outelement3i[0] = remappedelement[2];
904 outelement3i[1] = remappedelement[1];
905 outelement3i[2] = remappedelement[1] + 1;
906 outelement3i[3] = remappedelement[2];
907 outelement3i[4] = remappedelement[1] + 1;
908 outelement3i[5] = remappedelement[2] + 1;
913 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
915 remappedelement[0] = vertexremap[element[0]];
916 remappedelement[2] = vertexremap[element[2]];
917 outelement3i[0] = remappedelement[0];
918 outelement3i[1] = remappedelement[2];
919 outelement3i[2] = remappedelement[2] + 1;
920 outelement3i[3] = remappedelement[0];
921 outelement3i[4] = remappedelement[2] + 1;
922 outelement3i[5] = remappedelement[0] + 1;
931 for (i = 0;i < numshadowmarktris;i++)
933 int remappedelement[3];
935 const int *neighbortriangle;
937 markindex = shadowmarktris[i] * 3;
938 element = inelement3i + markindex;
939 neighbortriangle = inneighbor3i + markindex;
940 // output the front and back triangles
941 outelement3i[0] = vertexremap[element[2]];
942 outelement3i[1] = vertexremap[element[1]];
943 outelement3i[2] = vertexremap[element[0]];
944 outelement3i[3] = vertexremap[element[0]] + 1;
945 outelement3i[4] = vertexremap[element[1]] + 1;
946 outelement3i[5] = vertexremap[element[2]] + 1;
950 // output the sides (facing outward from this triangle)
951 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
953 remappedelement[0] = vertexremap[element[0]];
954 remappedelement[1] = vertexremap[element[1]];
955 outelement3i[0] = remappedelement[0];
956 outelement3i[1] = remappedelement[1];
957 outelement3i[2] = remappedelement[1] + 1;
958 outelement3i[3] = remappedelement[0];
959 outelement3i[4] = remappedelement[1] + 1;
960 outelement3i[5] = remappedelement[0] + 1;
965 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
967 remappedelement[1] = vertexremap[element[1]];
968 remappedelement[2] = vertexremap[element[2]];
969 outelement3i[0] = remappedelement[1];
970 outelement3i[1] = remappedelement[2];
971 outelement3i[2] = remappedelement[2] + 1;
972 outelement3i[3] = remappedelement[1];
973 outelement3i[4] = remappedelement[2] + 1;
974 outelement3i[5] = remappedelement[1] + 1;
979 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
981 remappedelement[0] = vertexremap[element[0]];
982 remappedelement[2] = vertexremap[element[2]];
983 outelement3i[0] = remappedelement[2];
984 outelement3i[1] = remappedelement[0];
985 outelement3i[2] = remappedelement[0] + 1;
986 outelement3i[3] = remappedelement[2];
987 outelement3i[4] = remappedelement[0] + 1;
988 outelement3i[5] = remappedelement[2] + 1;
996 *outnumvertices = outvertices;
1000 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)
1003 int outtriangles = 0, outvertices = 0;
1005 const float *vertex;
1006 float ratio, direction[3], projectvector[3];
1009 if (projectdirection)
1010 VectorScale(projectdirection, projectdistance, projectvector);
1012 VectorClear(projectvector);
1014 for (i = 0;i < numshadowmarktris;i++)
1016 int remappedelement[3];
1018 const int *neighbortriangle;
1020 markindex = shadowmarktris[i] * 3;
1021 neighbortriangle = inneighbor3i + markindex;
1022 side[0] = shadowmark[neighbortriangle[0]] == shadowmarkcount;
1023 side[1] = shadowmark[neighbortriangle[1]] == shadowmarkcount;
1024 side[2] = shadowmark[neighbortriangle[2]] == shadowmarkcount;
1025 if (side[0] + side[1] + side[2] == 0)
1029 element = inelement3i + markindex;
1031 // create the vertices
1032 for (j = 0;j < 3;j++)
1034 if (side[j] + side[j+1] == 0)
1037 if (vertexupdate[k] != vertexupdatenum)
1039 vertexupdate[k] = vertexupdatenum;
1040 vertexremap[k] = outvertices;
1041 vertex = invertex3f + k * 3;
1042 VectorCopy(vertex, outvertex3f);
1043 if (projectdirection)
1045 // project one copy of the vertex according to projectvector
1046 VectorAdd(vertex, projectvector, (outvertex3f + 3));
1050 // project one copy of the vertex to the sphere radius of the light
1051 // (FIXME: would projecting it to the light box be better?)
1052 VectorSubtract(vertex, projectorigin, direction);
1053 ratio = projectdistance / VectorLength(direction);
1054 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1061 // output the sides (facing outward from this triangle)
1064 remappedelement[0] = vertexremap[element[0]];
1065 remappedelement[1] = vertexremap[element[1]];
1066 outelement3i[0] = remappedelement[1];
1067 outelement3i[1] = remappedelement[0];
1068 outelement3i[2] = remappedelement[0] + 1;
1069 outelement3i[3] = remappedelement[1];
1070 outelement3i[4] = remappedelement[0] + 1;
1071 outelement3i[5] = remappedelement[1] + 1;
1078 remappedelement[1] = vertexremap[element[1]];
1079 remappedelement[2] = vertexremap[element[2]];
1080 outelement3i[0] = remappedelement[2];
1081 outelement3i[1] = remappedelement[1];
1082 outelement3i[2] = remappedelement[1] + 1;
1083 outelement3i[3] = remappedelement[2];
1084 outelement3i[4] = remappedelement[1] + 1;
1085 outelement3i[5] = remappedelement[2] + 1;
1092 remappedelement[0] = vertexremap[element[0]];
1093 remappedelement[2] = vertexremap[element[2]];
1094 outelement3i[0] = remappedelement[0];
1095 outelement3i[1] = remappedelement[2];
1096 outelement3i[2] = remappedelement[2] + 1;
1097 outelement3i[3] = remappedelement[0];
1098 outelement3i[4] = remappedelement[2] + 1;
1099 outelement3i[5] = remappedelement[0] + 1;
1106 *outnumvertices = outvertices;
1107 return outtriangles;
1110 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)
1116 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1118 tend = firsttriangle + numtris;
1119 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1121 // surface box entirely inside light box, no box cull
1122 if (projectdirection)
1124 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1126 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
1127 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1128 shadowmarklist[numshadowmark++] = t;
1133 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1134 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
1135 shadowmarklist[numshadowmark++] = t;
1140 // surface box not entirely inside light box, cull each triangle
1141 if (projectdirection)
1143 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1145 v[0] = invertex3f + e[0] * 3;
1146 v[1] = invertex3f + e[1] * 3;
1147 v[2] = invertex3f + e[2] * 3;
1148 TriangleNormal(v[0], v[1], v[2], normal);
1149 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1150 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1151 shadowmarklist[numshadowmark++] = t;
1156 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1158 v[0] = invertex3f + e[0] * 3;
1159 v[1] = invertex3f + e[1] * 3;
1160 v[2] = invertex3f + e[2] * 3;
1161 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1162 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1163 shadowmarklist[numshadowmark++] = t;
1169 qboolean R_Shadow_UseZPass(vec3_t mins, vec3_t maxs)
1174 if (r_shadow_compilingrtlight || !r_shadow_frontsidecasting.integer || !r_shadow_usezpassifpossible.integer)
1176 // check if the shadow volume intersects the near plane
1178 // a ray between the eye and light origin may intersect the caster,
1179 // indicating that the shadow may touch the eye location, however we must
1180 // test the near plane (a polygon), not merely the eye location, so it is
1181 // easiest to enlarge the caster bounding shape slightly for this.
1187 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)
1189 int i, tris, outverts;
1190 if (projectdistance < 0.1)
1192 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
1195 if (!numverts || !nummarktris)
1197 // make sure shadowelements is big enough for this volume
1198 if (maxshadowtriangles < nummarktris || maxshadowvertices < numverts)
1199 R_Shadow_ResizeShadowArrays((numverts + 255) & ~255, (nummarktris + 255) & ~255);
1201 if (maxvertexupdate < numverts)
1203 maxvertexupdate = numverts;
1205 Mem_Free(vertexupdate);
1207 Mem_Free(vertexremap);
1208 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1209 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1210 vertexupdatenum = 0;
1213 if (vertexupdatenum == 0)
1215 vertexupdatenum = 1;
1216 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
1217 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
1220 for (i = 0;i < nummarktris;i++)
1221 shadowmark[marktris[i]] = shadowmarkcount;
1223 if (r_shadow_compilingrtlight)
1225 // if we're compiling an rtlight, capture the mesh
1226 //tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1227 //Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zpass, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1228 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1229 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zfail, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1233 // decide which type of shadow to generate and set stencil mode
1234 R_Shadow_RenderMode_StencilShadowVolumes(R_Shadow_UseZPass(trismins, trismaxs));
1235 // generate the sides or a solid volume, depending on type
1236 if (r_shadow_rendermode >= R_SHADOW_RENDERMODE_ZPASS_STENCIL && r_shadow_rendermode <= R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE)
1237 tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1239 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1240 r_refdef.stats.lights_dynamicshadowtriangles += tris;
1241 r_refdef.stats.lights_shadowtriangles += tris;
1243 R_Mesh_VertexPointer(shadowvertex3f, 0, 0);
1244 GL_LockArrays(0, outverts);
1245 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
1247 // increment stencil if frontface is infront of depthbuffer
1248 GL_CullFace(r_refdef.view.cullface_front);
1249 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1250 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1251 // decrement stencil if backface is infront of depthbuffer
1252 GL_CullFace(r_refdef.view.cullface_back);
1253 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1255 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
1257 // decrement stencil if backface is behind depthbuffer
1258 GL_CullFace(r_refdef.view.cullface_front);
1259 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1260 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1261 // increment stencil if frontface is behind depthbuffer
1262 GL_CullFace(r_refdef.view.cullface_back);
1263 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1265 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1266 GL_LockArrays(0, 0);
1271 void R_Shadow_ShadowMapFromList(int numverts, int numtris, const float *vertex3f, int vertex3f_bufferobject, int vertex3f_bufferoffset, const int *elements, int nummarktris, const int *marktris)
1273 int i, tris = nummarktris;
1276 if (!numverts || !nummarktris)
1278 // make sure shadowelements is big enough for this mesh
1279 if (maxshadowtriangles < nummarktris || maxshadowvertices < numverts)
1280 R_Shadow_ResizeShadowArrays((numverts + 255) & ~255, (nummarktris + 255) & ~255);
1282 // gather up the (sparse) triangles into one array
1283 outelement3i = shadowelements;
1284 for (i = 0;i < nummarktris;i++)
1286 element = elements + marktris[i] * 3;
1287 outelement3i[0] = element[0];
1288 outelement3i[1] = element[1];
1289 outelement3i[2] = element[2];
1293 r_refdef.stats.lights_dynamicshadowtriangles += tris;
1294 r_refdef.stats.lights_shadowtriangles += tris;
1295 R_Mesh_VertexPointer(vertex3f, vertex3f_bufferobject, vertex3f_bufferoffset);
1296 R_Mesh_Draw(0, numverts, 0, tris, shadowelements, NULL, 0, 0);
1299 static void R_Shadow_MakeTextures_MakeCorona(void)
1303 unsigned char pixels[32][32][4];
1304 for (y = 0;y < 32;y++)
1306 dy = (y - 15.5f) * (1.0f / 16.0f);
1307 for (x = 0;x < 32;x++)
1309 dx = (x - 15.5f) * (1.0f / 16.0f);
1310 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1311 a = bound(0, a, 255);
1312 pixels[y][x][0] = a;
1313 pixels[y][x][1] = a;
1314 pixels[y][x][2] = a;
1315 pixels[y][x][3] = 255;
1318 r_shadow_lightcorona = R_LoadTexture2D(r_shadow_texturepool, "lightcorona", 32, 32, &pixels[0][0][0], TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_FORCELINEAR, NULL);
1321 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1323 float dist = sqrt(x*x+y*y+z*z);
1324 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1325 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1326 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1329 static void R_Shadow_MakeTextures(void)
1332 float intensity, dist;
1334 R_FreeTexturePool(&r_shadow_texturepool);
1335 r_shadow_texturepool = R_AllocTexturePool();
1336 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1337 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1338 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1339 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1340 for (x = 0;x <= ATTENTABLESIZE;x++)
1342 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1343 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1344 r_shadow_attentable[x] = bound(0, intensity, 1);
1346 // 1D gradient texture
1347 for (x = 0;x < ATTEN1DSIZE;x++)
1348 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1349 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);
1350 // 2D circle texture
1351 for (y = 0;y < ATTEN2DSIZE;y++)
1352 for (x = 0;x < ATTEN2DSIZE;x++)
1353 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);
1354 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);
1355 // 3D sphere texture
1356 if (r_shadow_texture3d.integer && gl_texture3d)
1358 for (z = 0;z < ATTEN3DSIZE;z++)
1359 for (y = 0;y < ATTEN3DSIZE;y++)
1360 for (x = 0;x < ATTEN3DSIZE;x++)
1361 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));
1362 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);
1365 r_shadow_attenuation3dtexture = NULL;
1368 R_Shadow_MakeTextures_MakeCorona();
1370 // Editor light sprites
1371 r_editlights_sprcursor = Draw_CachePic ("gfx/editlights/cursor");
1372 r_editlights_sprlight = Draw_CachePic ("gfx/editlights/light");
1373 r_editlights_sprnoshadowlight = Draw_CachePic ("gfx/editlights/noshadow");
1374 r_editlights_sprcubemaplight = Draw_CachePic ("gfx/editlights/cubemaplight");
1375 r_editlights_sprcubemapnoshadowlight = Draw_CachePic ("gfx/editlights/cubemapnoshadowlight");
1376 r_editlights_sprselection = Draw_CachePic ("gfx/editlights/selection");
1379 void R_Shadow_ValidateCvars(void)
1381 if (r_shadow_texture3d.integer && !gl_texture3d)
1382 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1383 if (gl_ext_separatestencil.integer && !gl_support_separatestencil)
1384 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
1385 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
1386 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1389 void R_Shadow_RenderMode_Begin(void)
1393 R_Shadow_ValidateCvars();
1395 if (!r_shadow_attenuation2dtexture
1396 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1397 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1398 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1399 R_Shadow_MakeTextures();
1402 R_Mesh_ColorPointer(NULL, 0, 0);
1403 R_Mesh_ResetTextureState();
1404 GL_BlendFunc(GL_ONE, GL_ZERO);
1405 GL_DepthRange(0, 1);
1406 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1408 GL_DepthMask(false);
1409 GL_Color(0, 0, 0, 1);
1410 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1412 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1414 if (gl_ext_separatestencil.integer)
1416 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
1417 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
1419 else if (gl_ext_stenciltwoside.integer)
1421 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
1422 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
1426 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
1427 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
1430 if (r_glsl.integer && gl_support_fragment_shader)
1431 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1432 else if (gl_dot3arb && gl_texturecubemap && r_textureunits.integer >= 2 && gl_combine.integer && gl_stencil)
1433 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_DOT3;
1435 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1438 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
1439 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
1440 r_shadow_drawbuffer = drawbuffer;
1441 r_shadow_readbuffer = readbuffer;
1444 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
1446 rsurface.rtlight = rtlight;
1449 void R_Shadow_RenderMode_Reset(void)
1452 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE)
1454 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1456 if (gl_support_ext_framebuffer_object)
1458 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);CHECKGLERROR
1460 qglDrawBuffer(r_shadow_drawbuffer);CHECKGLERROR
1461 qglReadBuffer(r_shadow_readbuffer);CHECKGLERROR
1462 R_SetViewport(&r_refdef.view.viewport);
1463 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
1464 R_Mesh_ColorPointer(NULL, 0, 0);
1465 R_Mesh_ResetTextureState();
1466 GL_DepthRange(0, 1);
1468 GL_DepthMask(false);
1469 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1470 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1471 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
1472 qglStencilMask(~0);CHECKGLERROR
1473 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
1474 qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
1475 GL_CullFace(r_refdef.view.cullface_back);
1476 GL_Color(1, 1, 1, 1);
1477 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
1478 GL_BlendFunc(GL_ONE, GL_ZERO);
1479 R_SetupGenericShader(false);
1480 r_shadow_usingshadowmaprect = false;
1481 r_shadow_usingshadowmapcube = false;
1482 r_shadow_usingshadowmap2d = false;
1486 void R_Shadow_ClearStencil(void)
1489 GL_Clear(GL_STENCIL_BUFFER_BIT);
1490 r_refdef.stats.lights_clears++;
1493 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
1495 r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
1496 if (r_shadow_rendermode == mode)
1499 R_Shadow_RenderMode_Reset();
1500 GL_ColorMask(0, 0, 0, 0);
1501 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1502 R_SetupDepthOrShadowShader();
1503 qglDepthFunc(GL_LESS);CHECKGLERROR
1504 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1505 r_shadow_rendermode = mode;
1510 case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
1511 GL_CullFace(GL_NONE);
1512 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1513 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1515 case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
1516 GL_CullFace(GL_NONE);
1517 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1518 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1520 case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
1521 GL_CullFace(GL_NONE);
1522 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1523 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
1524 qglStencilMask(~0);CHECKGLERROR
1525 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1526 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
1527 qglStencilMask(~0);CHECKGLERROR
1528 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1530 case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
1531 GL_CullFace(GL_NONE);
1532 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1533 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
1534 qglStencilMask(~0);CHECKGLERROR
1535 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1536 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
1537 qglStencilMask(~0);CHECKGLERROR
1538 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1543 static void R_Shadow_MakeVSDCT(void)
1545 // maps to a 2x3 texture rectangle with normalized coordinates
1550 // stores abs(dir.xy), offset.xy/2.5
1551 unsigned char data[4*6] =
1553 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
1554 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
1555 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
1556 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
1557 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
1558 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
1560 r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_ALWAYSPRECACHE | TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, NULL);
1563 void R_Shadow_RenderMode_ShadowMap(int side, qboolean clear, int size)
1568 float nearclip, farclip, bias;
1569 r_viewport_t viewport;
1571 maxsize = r_shadow_shadowmapmaxsize;
1572 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
1574 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
1575 r_shadow_shadowmap_parameters[2] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
1576 r_shadow_shadowmap_parameters[3] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
1577 if (r_shadow_shadowmode == 1)
1579 // complex unrolled cube approach (more flexible)
1580 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
1581 R_Shadow_MakeVSDCT();
1582 if (!r_shadow_shadowmap2dtexture)
1585 int w = maxsize*2, h = gl_support_arb_texture_non_power_of_two ? maxsize*3 : maxsize*4;
1586 r_shadow_shadowmap2dtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "shadowmap", w, h, r_shadow_shadowmapprecision, r_shadow_shadowmapsampler);
1587 qglGenFramebuffersEXT(1, &r_shadow_fbo2d);CHECKGLERROR
1588 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbo2d);CHECKGLERROR
1589 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_shadowmap2dtexture), 0);CHECKGLERROR
1593 R_Shadow_RenderMode_Reset();
1594 if (r_shadow_shadowmap2dtexture)
1596 // render depth into the fbo, do not render color at all
1597 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbo2d);CHECKGLERROR
1598 qglDrawBuffer(GL_NONE);CHECKGLERROR
1599 qglReadBuffer(GL_NONE);CHECKGLERROR
1600 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
1601 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
1603 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
1604 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
1606 R_SetupDepthOrShadowShader();
1610 R_SetupShowDepthShader();
1611 qglClearColor(1,1,1,1);CHECKGLERROR
1613 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
1614 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
1615 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
1616 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
1617 r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
1618 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
1620 else if (r_shadow_shadowmode == 2)
1622 // complex unrolled cube approach (more flexible)
1623 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
1624 R_Shadow_MakeVSDCT();
1625 if (!r_shadow_shadowmaprectangletexture)
1628 r_shadow_shadowmaprectangletexture = R_LoadTextureShadowMapRectangle(r_shadow_texturepool, "shadowmap", maxsize*2, maxsize*3, r_shadow_shadowmapprecision, r_shadow_shadowmapsampler);
1629 qglGenFramebuffersEXT(1, &r_shadow_fborectangle);CHECKGLERROR
1630 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fborectangle);CHECKGLERROR
1631 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, R_GetTexture(r_shadow_shadowmaprectangletexture), 0);CHECKGLERROR
1635 R_Shadow_RenderMode_Reset();
1636 if (r_shadow_shadowmaprectangletexture)
1638 // render depth into the fbo, do not render color at all
1639 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fborectangle);CHECKGLERROR
1640 qglDrawBuffer(GL_NONE);CHECKGLERROR
1641 qglReadBuffer(GL_NONE);CHECKGLERROR
1642 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
1643 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
1645 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
1646 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
1648 R_SetupDepthOrShadowShader();
1652 R_SetupShowDepthShader();
1653 qglClearColor(1,1,1,1);CHECKGLERROR
1655 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
1656 r_shadow_shadowmap_texturescale[0] = 1.0f;
1657 r_shadow_shadowmap_texturescale[1] = 1.0f;
1658 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
1659 r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
1660 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE;
1662 else if (r_shadow_shadowmode == 3)
1664 // simple cube approach
1665 if (!r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod])
1668 r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod] = R_LoadTextureShadowMapCube(r_shadow_texturepool, "shadowmapcube", size, r_shadow_shadowmapprecision, r_shadow_shadowmapsampler);
1669 qglGenFramebuffersEXT(6, r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR
1670 for (i = 0;i < 6;i++)
1672 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbocubeside[r_shadow_shadowmaplod][i]);CHECKGLERROR
1673 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
1678 R_Shadow_RenderMode_Reset();
1679 if (r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod])
1681 // render depth into the fbo, do not render color at all
1682 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbocubeside[r_shadow_shadowmaplod][side]);CHECKGLERROR
1683 qglDrawBuffer(GL_NONE);CHECKGLERROR
1684 qglReadBuffer(GL_NONE);CHECKGLERROR
1685 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
1686 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
1688 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
1689 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
1691 R_SetupDepthOrShadowShader();
1695 R_SetupShowDepthShader();
1696 qglClearColor(1,1,1,1);CHECKGLERROR
1698 R_Viewport_InitCubeSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, nearclip, farclip, NULL);
1699 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]);
1700 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureWidth(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]);
1701 r_shadow_shadowmap_parameters[0] = 1.0f;
1702 r_shadow_shadowmap_parameters[1] = 1.0f;
1703 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE;
1706 R_SetViewport(&viewport);
1707 GL_PolygonOffset(0, 0);
1709 if(r_shadow_shadowmode >= 1 && r_shadow_shadowmode <= 2)
1711 static qboolean cullback[6] = { true, false, true, false, false, true };
1712 GL_CullFace(cullback[side] ? r_refdef.view.cullface_back : r_refdef.view.cullface_front);
1714 else if(r_shadow_shadowmode == 3)
1715 GL_CullFace(r_refdef.view.cullface_back);
1717 GL_CullFace(GL_NONE);
1719 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
1722 qglClearDepth(1);CHECKGLERROR
1725 qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
1729 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
1732 R_Shadow_RenderMode_Reset();
1733 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1736 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1740 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1741 // only draw light where this geometry was already rendered AND the
1742 // stencil is 128 (values other than this mean shadow)
1743 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
1745 r_shadow_rendermode = r_shadow_lightingrendermode;
1746 // do global setup needed for the chosen lighting mode
1747 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
1749 R_Mesh_TexBindCubeMap(GL20TU_CUBE, R_GetTexture(rsurface.rtlight->currentcubemap)); // light filter
1750 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
1754 if (r_shadow_shadowmode == 1)
1756 r_shadow_usingshadowmap2d = true;
1757 R_Mesh_TexBind(GL20TU_SHADOWMAP2D, R_GetTexture(r_shadow_shadowmap2dtexture));
1760 else if (r_shadow_shadowmode == 2)
1762 r_shadow_usingshadowmaprect = true;
1763 R_Mesh_TexBindRectangle(GL20TU_SHADOWMAPRECT, R_GetTexture(r_shadow_shadowmaprectangletexture));
1766 else if (r_shadow_shadowmode == 3)
1768 r_shadow_usingshadowmapcube = true;
1769 R_Mesh_TexBindCubeMap(GL20TU_SHADOWMAPCUBE, R_GetTexture(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]));
1773 if (r_shadow_shadowmapvsdct && (r_shadow_usingshadowmap2d || r_shadow_usingshadowmaprect))
1775 R_Mesh_TexBindCubeMap(GL20TU_CUBEPROJECTION, R_GetTexture(r_shadow_shadowmapvsdcttexture));
1780 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_VERTEX)
1781 R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
1782 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1786 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
1789 R_Shadow_RenderMode_Reset();
1790 GL_BlendFunc(GL_ONE, GL_ONE);
1791 GL_DepthRange(0, 1);
1792 GL_DepthTest(r_showshadowvolumes.integer < 2);
1793 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
1794 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1795 GL_CullFace(GL_NONE);
1796 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
1799 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
1802 R_Shadow_RenderMode_Reset();
1803 GL_BlendFunc(GL_ONE, GL_ONE);
1804 GL_DepthRange(0, 1);
1805 GL_DepthTest(r_showlighting.integer < 2);
1806 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
1809 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1813 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1814 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
1816 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
1819 void R_Shadow_RenderMode_End(void)
1822 R_Shadow_RenderMode_Reset();
1823 R_Shadow_RenderMode_ActiveLight(NULL);
1825 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1826 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1829 int bboxedges[12][2] =
1848 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
1850 int i, ix1, iy1, ix2, iy2;
1851 float x1, y1, x2, y2;
1853 float vertex[20][3];
1862 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
1863 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
1864 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
1865 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
1867 if (!r_shadow_scissor.integer)
1870 // if view is inside the light box, just say yes it's visible
1871 if (BoxesOverlap(r_refdef.view.origin, r_refdef.view.origin, mins, maxs))
1874 x1 = y1 = x2 = y2 = 0;
1876 // transform all corners that are infront of the nearclip plane
1877 VectorNegate(r_refdef.view.frustum[4].normal, plane4f);
1878 plane4f[3] = r_refdef.view.frustum[4].dist;
1880 for (i = 0;i < 8;i++)
1882 Vector4Set(corner[i], (i & 1) ? maxs[0] : mins[0], (i & 2) ? maxs[1] : mins[1], (i & 4) ? maxs[2] : mins[2], 1);
1883 dist[i] = DotProduct4(corner[i], plane4f);
1884 sign[i] = dist[i] > 0;
1887 VectorCopy(corner[i], vertex[numvertices]);
1891 // if some points are behind the nearclip, add clipped edge points to make
1892 // sure that the scissor boundary is complete
1893 if (numvertices > 0 && numvertices < 8)
1895 // add clipped edge points
1896 for (i = 0;i < 12;i++)
1898 j = bboxedges[i][0];
1899 k = bboxedges[i][1];
1900 if (sign[j] != sign[k])
1902 f = dist[j] / (dist[j] - dist[k]);
1903 VectorLerp(corner[j], f, corner[k], vertex[numvertices]);
1909 // if we have no points to check, the light is behind the view plane
1913 // if we have some points to transform, check what screen area is covered
1914 x1 = y1 = x2 = y2 = 0;
1916 //Con_Printf("%i vertices to transform...\n", numvertices);
1917 for (i = 0;i < numvertices;i++)
1919 VectorCopy(vertex[i], v);
1920 R_Viewport_TransformToScreen(&r_refdef.view.viewport, v, v2);
1921 //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]);
1924 if (x1 > v2[0]) x1 = v2[0];
1925 if (x2 < v2[0]) x2 = v2[0];
1926 if (y1 > v2[1]) y1 = v2[1];
1927 if (y2 < v2[1]) y2 = v2[1];
1936 // now convert the scissor rectangle to integer screen coordinates
1937 ix1 = (int)(x1 - 1.0f);
1938 iy1 = vid.height - (int)(y2 - 1.0f);
1939 ix2 = (int)(x2 + 1.0f);
1940 iy2 = vid.height - (int)(y1 + 1.0f);
1941 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1943 // clamp it to the screen
1944 if (ix1 < r_refdef.view.viewport.x) ix1 = r_refdef.view.viewport.x;
1945 if (iy1 < r_refdef.view.viewport.y) iy1 = r_refdef.view.viewport.y;
1946 if (ix2 > r_refdef.view.viewport.x + r_refdef.view.viewport.width) ix2 = r_refdef.view.viewport.x + r_refdef.view.viewport.width;
1947 if (iy2 > r_refdef.view.viewport.y + r_refdef.view.viewport.height) iy2 = r_refdef.view.viewport.y + r_refdef.view.viewport.height;
1949 // if it is inside out, it's not visible
1950 if (ix2 <= ix1 || iy2 <= iy1)
1953 // the light area is visible, set up the scissor rectangle
1954 r_shadow_lightscissor[0] = ix1;
1955 r_shadow_lightscissor[1] = iy1;
1956 r_shadow_lightscissor[2] = ix2 - ix1;
1957 r_shadow_lightscissor[3] = iy2 - iy1;
1959 r_refdef.stats.lights_scissored++;
1963 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, int numtriangles, const int *element3i, const float *diffusecolor, const float *ambientcolor)
1965 float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
1966 float *normal3f = rsurface.normal3f + 3 * firstvertex;
1967 float *color4f = rsurface.array_color4f + 4 * firstvertex;
1968 float dist, dot, distintensity, shadeintensity, v[3], n[3];
1969 if (r_textureunits.integer >= 3)
1971 if (VectorLength2(diffusecolor) > 0)
1973 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1975 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1976 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
1977 if ((dot = DotProduct(n, v)) < 0)
1979 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1980 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
1983 VectorCopy(ambientcolor, color4f);
1984 if (r_refdef.fogenabled)
1987 f = FogPoint_Model(vertex3f);
1988 VectorScale(color4f, f, color4f);
1995 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1997 VectorCopy(ambientcolor, color4f);
1998 if (r_refdef.fogenabled)
2001 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2002 f = FogPoint_Model(vertex3f);
2003 VectorScale(color4f, f, color4f);
2009 else if (r_textureunits.integer >= 2)
2011 if (VectorLength2(diffusecolor) > 0)
2013 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2015 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2016 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2018 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2019 if ((dot = DotProduct(n, v)) < 0)
2021 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2022 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2023 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2024 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2028 color4f[0] = ambientcolor[0] * distintensity;
2029 color4f[1] = ambientcolor[1] * distintensity;
2030 color4f[2] = ambientcolor[2] * distintensity;
2032 if (r_refdef.fogenabled)
2035 f = FogPoint_Model(vertex3f);
2036 VectorScale(color4f, f, color4f);
2040 VectorClear(color4f);
2046 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2048 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2049 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2051 color4f[0] = ambientcolor[0] * distintensity;
2052 color4f[1] = ambientcolor[1] * distintensity;
2053 color4f[2] = ambientcolor[2] * distintensity;
2054 if (r_refdef.fogenabled)
2057 f = FogPoint_Model(vertex3f);
2058 VectorScale(color4f, f, color4f);
2062 VectorClear(color4f);
2069 if (VectorLength2(diffusecolor) > 0)
2071 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2073 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2074 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2076 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2077 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2078 if ((dot = DotProduct(n, v)) < 0)
2080 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2081 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2082 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2083 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2087 color4f[0] = ambientcolor[0] * distintensity;
2088 color4f[1] = ambientcolor[1] * distintensity;
2089 color4f[2] = ambientcolor[2] * distintensity;
2091 if (r_refdef.fogenabled)
2094 f = FogPoint_Model(vertex3f);
2095 VectorScale(color4f, f, color4f);
2099 VectorClear(color4f);
2105 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2107 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2108 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2110 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2111 color4f[0] = ambientcolor[0] * distintensity;
2112 color4f[1] = ambientcolor[1] * distintensity;
2113 color4f[2] = ambientcolor[2] * distintensity;
2114 if (r_refdef.fogenabled)
2117 f = FogPoint_Model(vertex3f);
2118 VectorScale(color4f, f, color4f);
2122 VectorClear(color4f);
2129 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
2131 static void R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
2134 float *out3f = rsurface.array_texcoord3f + 3 * firstvertex;
2135 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
2136 const float *svector3f = rsurface.svector3f + 3 * firstvertex;
2137 const float *tvector3f = rsurface.tvector3f + 3 * firstvertex;
2138 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
2140 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
2142 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
2143 // the cubemap normalizes this for us
2144 out3f[0] = DotProduct(svector3f, lightdir);
2145 out3f[1] = DotProduct(tvector3f, lightdir);
2146 out3f[2] = DotProduct(normal3f, lightdir);
2150 static void R_Shadow_GenTexCoords_Specular_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
2153 float *out3f = rsurface.array_texcoord3f + 3 * firstvertex;
2154 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
2155 const float *svector3f = rsurface.svector3f + 3 * firstvertex;
2156 const float *tvector3f = rsurface.tvector3f + 3 * firstvertex;
2157 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
2158 float lightdir[3], eyedir[3], halfdir[3];
2159 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
2161 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
2162 VectorNormalize(lightdir);
2163 VectorSubtract(rsurface.modelorg, vertex3f, eyedir);
2164 VectorNormalize(eyedir);
2165 VectorAdd(lightdir, eyedir, halfdir);
2166 // the cubemap normalizes this for us
2167 out3f[0] = DotProduct(svector3f, halfdir);
2168 out3f[1] = DotProduct(tvector3f, halfdir);
2169 out3f[2] = DotProduct(normal3f, halfdir);
2173 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)
2175 // used to display how many times a surface is lit for level design purposes
2176 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2179 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)
2181 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2182 R_SetupSurfaceShader(lightcolorbase, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT);
2183 if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND))
2184 R_Mesh_ColorPointer(rsurface.modellightmapcolor4f, rsurface.modellightmapcolor4f_bufferobject, rsurface.modellightmapcolor4f_bufferoffset);
2186 R_Mesh_ColorPointer(NULL, 0, 0);
2187 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
2188 R_Mesh_TexMatrix(1, &rsurface.texture->currentbackgroundtexmatrix);
2189 R_Mesh_TexBind(GL20TU_NORMAL, R_GetTexture(rsurface.texture->currentskinframe->nmap));
2190 R_Mesh_TexBind(GL20TU_COLOR, R_GetTexture(rsurface.texture->basetexture));
2191 R_Mesh_TexBind(GL20TU_GLOSS, R_GetTexture(rsurface.texture->glosstexture));
2192 if (rsurface.texture->backgroundcurrentskinframe)
2194 R_Mesh_TexBind(GL20TU_SECONDARY_NORMAL, R_GetTexture(rsurface.texture->backgroundcurrentskinframe->nmap));
2195 R_Mesh_TexBind(GL20TU_SECONDARY_COLOR, R_GetTexture(rsurface.texture->backgroundbasetexture));
2196 R_Mesh_TexBind(GL20TU_SECONDARY_GLOSS, R_GetTexture(rsurface.texture->backgroundglosstexture));
2197 R_Mesh_TexBind(GL20TU_SECONDARY_GLOW, R_GetTexture(rsurface.texture->backgroundcurrentskinframe->glow));
2199 //R_Mesh_TexBindCubeMap(GL20TU_CUBE, R_GetTexture(rsurface.rtlight->currentcubemap));
2200 R_Mesh_TexBind(GL20TU_FOGMASK, R_GetTexture(r_texture_fogattenuation));
2201 if(rsurface.texture->colormapping)
2203 R_Mesh_TexBind(GL20TU_PANTS, R_GetTexture(rsurface.texture->currentskinframe->pants));
2204 R_Mesh_TexBind(GL20TU_SHIRT, R_GetTexture(rsurface.texture->currentskinframe->shirt));
2206 R_Mesh_TexBind(GL20TU_ATTENUATION, R_GetTexture(r_shadow_attenuationgradienttexture));
2207 R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
2208 R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset);
2209 R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset);
2210 R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset);
2211 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2213 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2215 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2216 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2218 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
2222 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)
2224 // shared final code for all the dot3 layers
2226 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2227 for (renders = 0;renders < 64 && (r > 0 || g > 0 || b > 0);renders++, r--, g--, b--)
2229 GL_Color(bound(0, r, 1), bound(0, g, 1), bound(0, b, 1), 1);
2230 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2234 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)
2237 // colorscale accounts for how much we multiply the brightness
2240 // mult is how many times the final pass of the lighting will be
2241 // performed to get more brightness than otherwise possible.
2243 // Limit mult to 64 for sanity sake.
2245 if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
2247 // 3 3D combine path (Geforce3, Radeon 8500)
2248 memset(&m, 0, sizeof(m));
2249 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2250 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2251 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2252 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2253 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2254 m.tex[1] = R_GetTexture(basetexture);
2255 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
2256 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
2257 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
2258 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
2259 m.texcubemap[2] = R_GetTexture(rsurface.rtlight->currentcubemap);
2260 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2261 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2262 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2263 m.texmatrix[2] = rsurface.entitytolight;
2264 GL_BlendFunc(GL_ONE, GL_ONE);
2266 else if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
2268 // 2 3D combine path (Geforce3, original Radeon)
2269 memset(&m, 0, sizeof(m));
2270 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2271 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2272 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2273 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2274 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2275 m.tex[1] = R_GetTexture(basetexture);
2276 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
2277 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
2278 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
2279 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
2280 GL_BlendFunc(GL_ONE, GL_ONE);
2282 else if (r_textureunits.integer >= 4 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2284 // 4 2D combine path (Geforce3, Radeon 8500)
2285 memset(&m, 0, sizeof(m));
2286 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2287 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2288 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2289 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2290 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2291 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2292 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2293 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2294 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2295 m.texmatrix[1] = rsurface.entitytoattenuationz;
2296 m.tex[2] = R_GetTexture(basetexture);
2297 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
2298 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
2299 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
2300 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
2301 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2303 m.texcubemap[3] = R_GetTexture(rsurface.rtlight->currentcubemap);
2304 m.pointer_texcoord3f[3] = rsurface.vertex3f;
2305 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
2306 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
2307 m.texmatrix[3] = rsurface.entitytolight;
2309 GL_BlendFunc(GL_ONE, GL_ONE);
2311 else if (r_textureunits.integer >= 3 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
2313 // 3 2D combine path (Geforce3, original Radeon)
2314 memset(&m, 0, sizeof(m));
2315 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2316 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2317 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2318 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2319 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2320 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2321 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2322 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2323 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2324 m.texmatrix[1] = rsurface.entitytoattenuationz;
2325 m.tex[2] = R_GetTexture(basetexture);
2326 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
2327 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
2328 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
2329 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
2330 GL_BlendFunc(GL_ONE, GL_ONE);
2334 // 2/2/2 2D combine path (any dot3 card)
2335 memset(&m, 0, sizeof(m));
2336 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2337 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2338 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2339 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2340 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2341 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2342 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2343 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2344 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2345 m.texmatrix[1] = rsurface.entitytoattenuationz;
2346 R_Mesh_TextureState(&m);
2347 GL_ColorMask(0,0,0,1);
2348 GL_BlendFunc(GL_ONE, GL_ZERO);
2349 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2352 memset(&m, 0, sizeof(m));
2353 m.tex[0] = R_GetTexture(basetexture);
2354 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2355 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2356 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2357 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2358 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2360 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2361 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2362 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2363 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2364 m.texmatrix[1] = rsurface.entitytolight;
2366 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2368 // this final code is shared
2369 R_Mesh_TextureState(&m);
2370 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);
2373 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)
2376 // colorscale accounts for how much we multiply the brightness
2379 // mult is how many times the final pass of the lighting will be
2380 // performed to get more brightness than otherwise possible.
2382 // Limit mult to 64 for sanity sake.
2384 // generate normalization cubemap texcoords
2385 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
2386 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
2388 // 3/2 3D combine path (Geforce3, Radeon 8500)
2389 memset(&m, 0, sizeof(m));
2390 m.tex[0] = R_GetTexture(normalmaptexture);
2391 m.texcombinergb[0] = GL_REPLACE;
2392 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2393 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2394 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2395 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2396 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2397 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2398 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2399 m.pointer_texcoord_bufferobject[1] = 0;
2400 m.pointer_texcoord_bufferoffset[1] = 0;
2401 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
2402 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2403 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2404 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2405 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
2406 R_Mesh_TextureState(&m);
2407 GL_ColorMask(0,0,0,1);
2408 GL_BlendFunc(GL_ONE, GL_ZERO);
2409 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2412 memset(&m, 0, sizeof(m));
2413 m.tex[0] = R_GetTexture(basetexture);
2414 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2415 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2416 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2417 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2418 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2420 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2421 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2422 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2423 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2424 m.texmatrix[1] = rsurface.entitytolight;
2426 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2428 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2430 // 1/2/2 3D combine path (original Radeon)
2431 memset(&m, 0, sizeof(m));
2432 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2433 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2434 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2435 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2436 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2437 R_Mesh_TextureState(&m);
2438 GL_ColorMask(0,0,0,1);
2439 GL_BlendFunc(GL_ONE, GL_ZERO);
2440 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2443 memset(&m, 0, sizeof(m));
2444 m.tex[0] = R_GetTexture(normalmaptexture);
2445 m.texcombinergb[0] = GL_REPLACE;
2446 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2447 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2448 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2449 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2450 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2451 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2452 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2453 m.pointer_texcoord_bufferobject[1] = 0;
2454 m.pointer_texcoord_bufferoffset[1] = 0;
2455 R_Mesh_TextureState(&m);
2456 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2457 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2460 memset(&m, 0, sizeof(m));
2461 m.tex[0] = R_GetTexture(basetexture);
2462 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2463 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2464 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2465 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2466 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2468 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2469 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2470 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2471 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2472 m.texmatrix[1] = rsurface.entitytolight;
2474 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2476 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
2478 // 2/2 3D combine path (original Radeon)
2479 memset(&m, 0, sizeof(m));
2480 m.tex[0] = R_GetTexture(normalmaptexture);
2481 m.texcombinergb[0] = GL_REPLACE;
2482 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2483 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2484 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2485 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2486 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2487 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2488 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2489 m.pointer_texcoord_bufferobject[1] = 0;
2490 m.pointer_texcoord_bufferoffset[1] = 0;
2491 R_Mesh_TextureState(&m);
2492 GL_ColorMask(0,0,0,1);
2493 GL_BlendFunc(GL_ONE, GL_ZERO);
2494 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2497 memset(&m, 0, sizeof(m));
2498 m.tex[0] = R_GetTexture(basetexture);
2499 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2500 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2501 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2502 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2503 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2504 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2505 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2506 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2507 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2508 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2510 else if (r_textureunits.integer >= 4)
2512 // 4/2 2D combine path (Geforce3, Radeon 8500)
2513 memset(&m, 0, sizeof(m));
2514 m.tex[0] = R_GetTexture(normalmaptexture);
2515 m.texcombinergb[0] = GL_REPLACE;
2516 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2517 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2518 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2519 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2520 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2521 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2522 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2523 m.pointer_texcoord_bufferobject[1] = 0;
2524 m.pointer_texcoord_bufferoffset[1] = 0;
2525 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2526 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2527 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2528 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2529 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
2530 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
2531 m.pointer_texcoord3f[3] = rsurface.vertex3f;
2532 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
2533 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
2534 m.texmatrix[3] = rsurface.entitytoattenuationz;
2535 R_Mesh_TextureState(&m);
2536 GL_ColorMask(0,0,0,1);
2537 GL_BlendFunc(GL_ONE, GL_ZERO);
2538 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2541 memset(&m, 0, sizeof(m));
2542 m.tex[0] = R_GetTexture(basetexture);
2543 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2544 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2545 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2546 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2547 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2549 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2550 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2551 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2552 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2553 m.texmatrix[1] = rsurface.entitytolight;
2555 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2559 // 2/2/2 2D combine path (any dot3 card)
2560 memset(&m, 0, sizeof(m));
2561 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2562 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2563 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2564 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2565 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2566 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2567 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2568 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2569 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2570 m.texmatrix[1] = rsurface.entitytoattenuationz;
2571 R_Mesh_TextureState(&m);
2572 GL_ColorMask(0,0,0,1);
2573 GL_BlendFunc(GL_ONE, GL_ZERO);
2574 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2577 memset(&m, 0, sizeof(m));
2578 m.tex[0] = R_GetTexture(normalmaptexture);
2579 m.texcombinergb[0] = GL_REPLACE;
2580 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2581 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2582 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2583 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2584 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2585 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2586 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2587 m.pointer_texcoord_bufferobject[1] = 0;
2588 m.pointer_texcoord_bufferoffset[1] = 0;
2589 R_Mesh_TextureState(&m);
2590 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2591 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2594 memset(&m, 0, sizeof(m));
2595 m.tex[0] = R_GetTexture(basetexture);
2596 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2597 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2598 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2599 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2600 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2602 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2603 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2604 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2605 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2606 m.texmatrix[1] = rsurface.entitytolight;
2608 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2610 // this final code is shared
2611 R_Mesh_TextureState(&m);
2612 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);
2615 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)
2617 float glossexponent;
2619 // FIXME: detect blendsquare!
2620 //if (!gl_support_blendsquare)
2623 // generate normalization cubemap texcoords
2624 R_Shadow_GenTexCoords_Specular_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
2625 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2627 // 2/0/0/1/2 3D combine blendsquare path
2628 memset(&m, 0, sizeof(m));
2629 m.tex[0] = R_GetTexture(normalmaptexture);
2630 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2631 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2632 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2633 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2634 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2635 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2636 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2637 m.pointer_texcoord_bufferobject[1] = 0;
2638 m.pointer_texcoord_bufferoffset[1] = 0;
2639 R_Mesh_TextureState(&m);
2640 GL_ColorMask(0,0,0,1);
2641 // this squares the result
2642 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2643 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2645 // second and third pass
2646 R_Mesh_ResetTextureState();
2647 // square alpha in framebuffer a few times to make it shiny
2648 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2649 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2650 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2653 memset(&m, 0, sizeof(m));
2654 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2655 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2656 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2657 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2658 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2659 R_Mesh_TextureState(&m);
2660 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2661 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2664 memset(&m, 0, sizeof(m));
2665 m.tex[0] = R_GetTexture(glosstexture);
2666 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2667 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2668 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2669 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2670 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2672 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2673 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2674 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2675 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2676 m.texmatrix[1] = rsurface.entitytolight;
2678 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2680 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
2682 // 2/0/0/2 3D combine blendsquare path
2683 memset(&m, 0, sizeof(m));
2684 m.tex[0] = R_GetTexture(normalmaptexture);
2685 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2686 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2687 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2688 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2689 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2690 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2691 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2692 m.pointer_texcoord_bufferobject[1] = 0;
2693 m.pointer_texcoord_bufferoffset[1] = 0;
2694 R_Mesh_TextureState(&m);
2695 GL_ColorMask(0,0,0,1);
2696 // this squares the result
2697 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2698 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2700 // second and third pass
2701 R_Mesh_ResetTextureState();
2702 // square alpha in framebuffer a few times to make it shiny
2703 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2704 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2705 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2708 memset(&m, 0, sizeof(m));
2709 m.tex[0] = R_GetTexture(glosstexture);
2710 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2711 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2712 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2713 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2714 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2715 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2716 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2717 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2718 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2719 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2723 // 2/0/0/2/2 2D combine blendsquare path
2724 memset(&m, 0, sizeof(m));
2725 m.tex[0] = R_GetTexture(normalmaptexture);
2726 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2727 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2728 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2729 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2730 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2731 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2732 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2733 m.pointer_texcoord_bufferobject[1] = 0;
2734 m.pointer_texcoord_bufferoffset[1] = 0;
2735 R_Mesh_TextureState(&m);
2736 GL_ColorMask(0,0,0,1);
2737 // this squares the result
2738 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2739 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2741 // second and third pass
2742 R_Mesh_ResetTextureState();
2743 // square alpha in framebuffer a few times to make it shiny
2744 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2745 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2746 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2749 memset(&m, 0, sizeof(m));
2750 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2751 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2752 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2753 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2754 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2755 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2756 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2757 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2758 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2759 m.texmatrix[1] = rsurface.entitytoattenuationz;
2760 R_Mesh_TextureState(&m);
2761 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2762 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2765 memset(&m, 0, sizeof(m));
2766 m.tex[0] = R_GetTexture(glosstexture);
2767 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2768 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2769 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2770 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2771 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2773 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2774 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2775 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2776 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2777 m.texmatrix[1] = rsurface.entitytolight;
2779 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2781 // this final code is shared
2782 R_Mesh_TextureState(&m);
2783 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);
2786 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)
2788 // ARB path (any Geforce, any Radeon)
2789 qboolean doambient = ambientscale > 0;
2790 qboolean dodiffuse = diffusescale > 0;
2791 qboolean dospecular = specularscale > 0;
2792 if (!doambient && !dodiffuse && !dospecular)
2794 R_Mesh_ColorPointer(NULL, 0, 0);
2796 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, basetexture, ambientscale * r_refdef.view.colorscale);
2798 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, basetexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
2802 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorpants, pantstexture, ambientscale * r_refdef.view.colorscale);
2804 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorpants, pantstexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
2809 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorshirt, shirttexture, ambientscale * r_refdef.view.colorscale);
2811 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorshirt, shirttexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
2814 R_Shadow_RenderLighting_Light_Dot3_SpecularPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, glosstexture, normalmaptexture, specularscale * r_refdef.view.colorscale);
2817 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
2824 int newnumtriangles;
2828 int maxtriangles = 4096;
2829 int newelements[4096*3];
2830 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, numtriangles, element3i, diffusecolor2, ambientcolor2);
2831 for (renders = 0;renders < 64;renders++)
2836 newnumtriangles = 0;
2838 // due to low fillrate on the cards this vertex lighting path is
2839 // designed for, we manually cull all triangles that do not
2840 // contain a lit vertex
2841 // this builds batches of triangles from multiple surfaces and
2842 // renders them at once
2843 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
2845 if (VectorLength2(rsurface.array_color4f + e[0] * 4) + VectorLength2(rsurface.array_color4f + e[1] * 4) + VectorLength2(rsurface.array_color4f + e[2] * 4) >= 0.01)
2847 if (newnumtriangles)
2849 newfirstvertex = min(newfirstvertex, e[0]);
2850 newlastvertex = max(newlastvertex, e[0]);
2854 newfirstvertex = e[0];
2855 newlastvertex = e[0];
2857 newfirstvertex = min(newfirstvertex, e[1]);
2858 newlastvertex = max(newlastvertex, e[1]);
2859 newfirstvertex = min(newfirstvertex, e[2]);
2860 newlastvertex = max(newlastvertex, e[2]);
2866 if (newnumtriangles >= maxtriangles)
2868 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
2869 newnumtriangles = 0;
2875 if (newnumtriangles >= 1)
2877 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
2880 // if we couldn't find any lit triangles, exit early
2883 // now reduce the intensity for the next overbright pass
2884 // we have to clamp to 0 here incase the drivers have improper
2885 // handling of negative colors
2886 // (some old drivers even have improper handling of >1 color)
2888 for (i = 0, c = rsurface.array_color4f + 4 * firstvertex;i < numvertices;i++, c += 4)
2890 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
2892 c[0] = max(0, c[0] - 1);
2893 c[1] = max(0, c[1] - 1);
2894 c[2] = max(0, c[2] - 1);
2906 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)
2908 // OpenGL 1.1 path (anything)
2909 float ambientcolorbase[3], diffusecolorbase[3];
2910 float ambientcolorpants[3], diffusecolorpants[3];
2911 float ambientcolorshirt[3], diffusecolorshirt[3];
2913 VectorScale(lightcolorbase, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorbase);
2914 VectorScale(lightcolorbase, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorbase);
2915 VectorScale(lightcolorpants, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorpants);
2916 VectorScale(lightcolorpants, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorpants);
2917 VectorScale(lightcolorshirt, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorshirt);
2918 VectorScale(lightcolorshirt, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorshirt);
2919 memset(&m, 0, sizeof(m));
2920 m.tex[0] = R_GetTexture(basetexture);
2921 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2922 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2923 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2924 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2925 if (r_textureunits.integer >= 2)
2928 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2929 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2930 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2931 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2932 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2933 if (r_textureunits.integer >= 3)
2935 // Voodoo4 or Kyro (or Geforce3/Radeon with gl_combine off)
2936 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2937 m.texmatrix[2] = rsurface.entitytoattenuationz;
2938 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2939 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2940 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2943 R_Mesh_TextureState(&m);
2944 //R_Mesh_TexBind(0, R_GetTexture(basetexture));
2945 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorbase, ambientcolorbase);
2948 R_Mesh_TexBind(0, R_GetTexture(pantstexture));
2949 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorpants, ambientcolorpants);
2953 R_Mesh_TexBind(0, R_GetTexture(shirttexture));
2954 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorshirt, ambientcolorshirt);
2958 extern cvar_t gl_lightmaps;
2959 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)
2961 float ambientscale, diffusescale, specularscale;
2962 vec3_t lightcolorbase, lightcolorpants, lightcolorshirt;
2964 // calculate colors to render this texture with
2965 lightcolorbase[0] = rsurface.rtlight->currentcolor[0] * rsurface.texture->dlightcolor[0];
2966 lightcolorbase[1] = rsurface.rtlight->currentcolor[1] * rsurface.texture->dlightcolor[1];
2967 lightcolorbase[2] = rsurface.rtlight->currentcolor[2] * rsurface.texture->dlightcolor[2];
2968 ambientscale = rsurface.rtlight->ambientscale;
2969 diffusescale = rsurface.rtlight->diffusescale;
2970 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
2971 if (!r_shadow_usenormalmap.integer)
2973 ambientscale += 1.0f * diffusescale;
2977 if ((ambientscale + diffusescale) * VectorLength2(lightcolorbase) + specularscale * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
2979 RSurf_SetupDepthAndCulling();
2980 nmap = rsurface.texture->currentskinframe->nmap;
2981 if (gl_lightmaps.integer)
2982 nmap = r_texture_blanknormalmap;
2983 if (rsurface.texture->colormapping && !gl_lightmaps.integer)
2985 qboolean dopants = rsurface.texture->currentskinframe->pants != NULL && VectorLength2(rsurface.colormap_pantscolor) >= (1.0f / 1048576.0f);
2986 qboolean doshirt = rsurface.texture->currentskinframe->shirt != NULL && VectorLength2(rsurface.colormap_shirtcolor) >= (1.0f / 1048576.0f);
2989 lightcolorpants[0] = lightcolorbase[0] * rsurface.colormap_pantscolor[0];
2990 lightcolorpants[1] = lightcolorbase[1] * rsurface.colormap_pantscolor[1];
2991 lightcolorpants[2] = lightcolorbase[2] * rsurface.colormap_pantscolor[2];
2994 VectorClear(lightcolorpants);
2997 lightcolorshirt[0] = lightcolorbase[0] * rsurface.colormap_shirtcolor[0];
2998 lightcolorshirt[1] = lightcolorbase[1] * rsurface.colormap_shirtcolor[1];
2999 lightcolorshirt[2] = lightcolorbase[2] * rsurface.colormap_shirtcolor[2];
3002 VectorClear(lightcolorshirt);
3003 switch (r_shadow_rendermode)
3005 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
3006 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
3007 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);
3009 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
3010 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);
3012 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
3013 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);
3015 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3016 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);
3019 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
3025 switch (r_shadow_rendermode)
3027 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
3028 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
3029 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);
3031 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
3032 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);
3034 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
3035 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);
3037 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3038 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);
3041 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
3047 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)
3049 matrix4x4_t tempmatrix = *matrix;
3050 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
3052 // if this light has been compiled before, free the associated data
3053 R_RTLight_Uncompile(rtlight);
3055 // clear it completely to avoid any lingering data
3056 memset(rtlight, 0, sizeof(*rtlight));
3058 // copy the properties
3059 rtlight->matrix_lighttoworld = tempmatrix;
3060 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
3061 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
3062 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
3063 VectorCopy(color, rtlight->color);
3064 rtlight->cubemapname[0] = 0;
3065 if (cubemapname && cubemapname[0])
3066 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
3067 rtlight->shadow = shadow;
3068 rtlight->corona = corona;
3069 rtlight->style = style;
3070 rtlight->isstatic = isstatic;
3071 rtlight->coronasizescale = coronasizescale;
3072 rtlight->ambientscale = ambientscale;
3073 rtlight->diffusescale = diffusescale;
3074 rtlight->specularscale = specularscale;
3075 rtlight->flags = flags;
3077 // compute derived data
3078 //rtlight->cullradius = rtlight->radius;
3079 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
3080 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3081 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3082 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3083 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3084 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3085 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3088 // compiles rtlight geometry
3089 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
3090 void R_RTLight_Compile(rtlight_t *rtlight)
3093 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
3094 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
3095 entity_render_t *ent = r_refdef.scene.worldentity;
3096 dp_model_t *model = r_refdef.scene.worldmodel;
3097 unsigned char *data;
3100 // compile the light
3101 rtlight->compiled = true;
3102 rtlight->static_numleafs = 0;
3103 rtlight->static_numleafpvsbytes = 0;
3104 rtlight->static_leaflist = NULL;
3105 rtlight->static_leafpvs = NULL;
3106 rtlight->static_numsurfaces = 0;
3107 rtlight->static_surfacelist = NULL;
3108 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3109 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3110 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3111 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3112 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3113 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3115 if (model && model->GetLightInfo)
3117 // this variable must be set for the CompileShadowVolume code
3118 r_shadow_compilingrtlight = rtlight;
3119 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);
3120 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);
3121 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
3122 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
3123 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3124 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
3125 rtlight->static_numsurfaces = numsurfaces;
3126 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
3127 rtlight->static_numleafs = numleafs;
3128 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
3129 rtlight->static_numleafpvsbytes = numleafpvsbytes;
3130 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
3131 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
3132 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
3133 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
3134 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3135 if (rtlight->static_numsurfaces)
3136 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3137 if (rtlight->static_numleafs)
3138 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3139 if (rtlight->static_numleafpvsbytes)
3140 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3141 if (rtlight->static_numshadowtrispvsbytes)
3142 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3143 if (rtlight->static_numlighttrispvsbytes)
3144 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3145 if (model->CompileShadowVolume && rtlight->shadow)
3146 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3147 // now we're done compiling the rtlight
3148 r_shadow_compilingrtlight = NULL;
3152 // use smallest available cullradius - box radius or light radius
3153 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3154 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3156 shadowzpasstris = 0;
3157 if (rtlight->static_meshchain_shadow_zpass)
3158 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
3159 shadowzpasstris += mesh->numtriangles;
3161 shadowzfailtris = 0;
3162 if (rtlight->static_meshchain_shadow_zfail)
3163 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
3164 shadowzfailtris += mesh->numtriangles;
3167 if (rtlight->static_numlighttrispvsbytes)
3168 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3169 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3173 if (rtlight->static_numlighttrispvsbytes)
3174 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3175 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3178 if (developer.integer >= 10)
3179 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);
3182 void R_RTLight_Uncompile(rtlight_t *rtlight)
3184 if (rtlight->compiled)
3186 if (rtlight->static_meshchain_shadow_zpass)
3187 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
3188 rtlight->static_meshchain_shadow_zpass = NULL;
3189 if (rtlight->static_meshchain_shadow_zfail)
3190 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
3191 rtlight->static_meshchain_shadow_zfail = NULL;
3192 // these allocations are grouped
3193 if (rtlight->static_surfacelist)
3194 Mem_Free(rtlight->static_surfacelist);
3195 rtlight->static_numleafs = 0;
3196 rtlight->static_numleafpvsbytes = 0;
3197 rtlight->static_leaflist = NULL;
3198 rtlight->static_leafpvs = NULL;
3199 rtlight->static_numsurfaces = 0;
3200 rtlight->static_surfacelist = NULL;
3201 rtlight->static_numshadowtrispvsbytes = 0;
3202 rtlight->static_shadowtrispvs = NULL;
3203 rtlight->static_numlighttrispvsbytes = 0;
3204 rtlight->static_lighttrispvs = NULL;
3205 rtlight->compiled = false;
3209 void R_Shadow_UncompileWorldLights(void)
3213 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3214 for (lightindex = 0;lightindex < range;lightindex++)
3216 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3219 R_RTLight_Uncompile(&light->rtlight);
3223 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3227 // reset the count of frustum planes
3228 // see rsurface.rtlight_frustumplanes definition for how much this array
3230 rsurface.rtlight_numfrustumplanes = 0;
3232 // haven't implemented a culling path for ortho rendering
3233 if (!r_refdef.view.useperspective)
3235 // check if the light is on screen and copy the 4 planes if it is
3236 for (i = 0;i < 4;i++)
3237 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3240 for (i = 0;i < 4;i++)
3241 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_refdef.view.frustum[i];
3246 // generate a deformed frustum that includes the light origin, this is
3247 // used to cull shadow casting surfaces that can not possibly cast a
3248 // shadow onto the visible light-receiving surfaces, which can be a
3251 // if the light origin is onscreen the result will be 4 planes exactly
3252 // if the light origin is offscreen on only one axis the result will
3253 // be exactly 5 planes (split-side case)
3254 // if the light origin is offscreen on two axes the result will be
3255 // exactly 4 planes (stretched corner case)
3256 for (i = 0;i < 4;i++)
3258 // quickly reject standard frustum planes that put the light
3259 // origin outside the frustum
3260 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3263 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_refdef.view.frustum[i];
3265 // if all the standard frustum planes were accepted, the light is onscreen
3266 // otherwise we need to generate some more planes below...
3267 if (rsurface.rtlight_numfrustumplanes < 4)
3269 // at least one of the stock frustum planes failed, so we need to
3270 // create one or two custom planes to enclose the light origin
3271 for (i = 0;i < 4;i++)
3273 // create a plane using the view origin and light origin, and a
3274 // single point from the frustum corner set
3275 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3276 VectorNormalize(plane.normal);
3277 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3278 // see if this plane is backwards and flip it if so
3279 for (j = 0;j < 4;j++)
3280 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3284 VectorNegate(plane.normal, plane.normal);
3286 // flipped plane, test again to see if it is now valid
3287 for (j = 0;j < 4;j++)
3288 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3290 // if the plane is still not valid, then it is dividing the
3291 // frustum and has to be rejected
3295 // we have created a valid plane, compute extra info
3296 PlaneClassify(&plane);
3298 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3300 // if we've found 5 frustum planes then we have constructed a
3301 // proper split-side case and do not need to keep searching for
3302 // planes to enclose the light origin
3303 if (rsurface.rtlight_numfrustumplanes == 5)
3311 for (i = 0;i < rsurface.rtlight_numfrustumplanes;i++)
3313 plane = rsurface.rtlight_frustumplanes[i];
3314 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));
3319 // now add the light-space box planes if the light box is rotated, as any
3320 // caster outside the oriented light box is irrelevant (even if it passed
3321 // the worldspace light box, which is axial)
3322 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3324 for (i = 0;i < 6;i++)
3328 v[i >> 1] = (i & 1) ? -1 : 1;
3329 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3330 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3331 plane.dist = VectorNormalizeLength(plane.normal);
3332 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3333 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3339 // add the world-space reduced box planes
3340 for (i = 0;i < 6;i++)
3342 VectorClear(plane.normal);
3343 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3344 plane.dist = (i & 1) ? -rsurface.rtlight_cullmaxs[i >> 1] : rsurface.rtlight_cullmins[i >> 1];
3345 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3354 // reduce all plane distances to tightly fit the rtlight cull box, which
3356 VectorSet(points[0], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
3357 VectorSet(points[1], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
3358 VectorSet(points[2], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
3359 VectorSet(points[3], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
3360 VectorSet(points[4], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
3361 VectorSet(points[5], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
3362 VectorSet(points[6], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
3363 VectorSet(points[7], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
3364 oldnum = rsurface.rtlight_numfrustumplanes;
3365 rsurface.rtlight_numfrustumplanes = 0;
3366 for (j = 0;j < oldnum;j++)
3368 // find the nearest point on the box to this plane
3369 bestdist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[0]);
3370 for (i = 1;i < 8;i++)
3372 dist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[i]);
3373 if (bestdist > dist)
3376 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);
3377 // if the nearest point is near or behind the plane, we want this
3378 // plane, otherwise the plane is useless as it won't cull anything
3379 if (rsurface.rtlight_frustumplanes[j].dist < bestdist + 0.03125)
3381 PlaneClassify(&rsurface.rtlight_frustumplanes[j]);
3382 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = rsurface.rtlight_frustumplanes[j];
3389 void R_Shadow_DrawWorldShadow(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3394 int surfacelistindex;
3395 msurface_t *surface;
3397 RSurf_ActiveWorldEntity();
3398 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D)
3400 if (r_refdef.scene.worldentity->model)
3401 r_refdef.scene.worldmodel->DrawShadowMap(r_refdef.scene.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs);
3402 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3406 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3409 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
3410 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
3411 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
3412 for (;mesh;mesh = mesh->next)
3414 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
3415 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
3416 GL_LockArrays(0, mesh->numverts);
3417 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
3419 // increment stencil if frontface is infront of depthbuffer
3420 GL_CullFace(r_refdef.view.cullface_back);
3421 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
3422 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3423 // decrement stencil if backface is infront of depthbuffer
3424 GL_CullFace(r_refdef.view.cullface_front);
3425 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
3427 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
3429 // decrement stencil if backface is behind depthbuffer
3430 GL_CullFace(r_refdef.view.cullface_front);
3431 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
3432 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3433 // increment stencil if frontface is behind depthbuffer
3434 GL_CullFace(r_refdef.view.cullface_back);
3435 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
3437 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3438 GL_LockArrays(0, 0);
3442 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh && r_shadow_culltriangles.integer)
3444 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
3445 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
3447 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
3448 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
3449 if (CHECKPVSBIT(trispvs, t))
3450 shadowmarklist[numshadowmark++] = t;
3452 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);
3454 else if (numsurfaces)
3455 r_refdef.scene.worldmodel->DrawShadowVolume(r_refdef.scene.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs);
3457 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3460 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3462 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3463 vec_t relativeshadowradius;
3464 RSurf_ActiveModelEntity(ent, false, false);
3465 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3466 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3467 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3468 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3469 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3470 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3471 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3472 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3473 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D)
3474 ent->model->DrawShadowMap(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3476 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3477 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3480 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3482 // set up properties for rendering light onto this entity
3483 RSurf_ActiveModelEntity(ent, true, true);
3484 GL_AlphaTest(false);
3485 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3486 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3487 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3488 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3489 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
3490 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
3493 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3495 if (!r_refdef.scene.worldmodel->DrawLight)
3498 // set up properties for rendering light onto this entity
3499 RSurf_ActiveWorldEntity();
3500 GL_AlphaTest(false);
3501 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3502 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3503 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3504 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3505 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
3506 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
3508 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, trispvs);
3510 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3513 void R_Shadow_DrawEntityLight(entity_render_t *ent)
3515 dp_model_t *model = ent->model;
3516 if (!model->DrawLight)
3519 R_Shadow_SetupEntityLight(ent);
3521 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3523 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3527 {{ 0, 0, 0}, "px", true, true, true},
3528 {{ 0, 90, 0}, "py", false, true, false},
3529 {{ 0, 180, 0}, "nx", false, false, true},
3530 {{ 0, 270, 0}, "ny", true, false, false},
3531 {{-90, 180, 0}, "pz", false, false, true},
3532 {{ 90, 180, 0}, "nz", false, false, true}
3535 static const double shadowviewmat16[6][4][4] =
3575 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
3579 int numleafs, numsurfaces;
3580 int *leaflist, *surfacelist;
3581 unsigned char *leafpvs, *shadowtrispvs, *lighttrispvs;
3582 int numlightentities;
3583 int numlightentities_noselfshadow;
3584 int numshadowentities;
3585 int numshadowentities_noselfshadow;
3586 static entity_render_t *lightentities[MAX_EDICTS];
3587 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3588 static entity_render_t *shadowentities[MAX_EDICTS];
3589 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3590 vec3_t nearestpoint;
3592 qboolean castshadows;
3595 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3596 // skip lights that are basically invisible (color 0 0 0)
3597 if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
3600 // loading is done before visibility checks because loading should happen
3601 // all at once at the start of a level, not when it stalls gameplay.
3602 // (especially important to benchmarks)
3604 if (rtlight->isstatic && !rtlight->compiled && r_shadow_realtime_world_compile.integer)
3605 R_RTLight_Compile(rtlight);
3607 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
3609 // look up the light style value at this time
3610 f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3611 VectorScale(rtlight->color, f, rtlight->currentcolor);
3613 if (rtlight->selected)
3615 f = 2 + sin(realtime * M_PI * 4.0);
3616 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3620 // if lightstyle is currently off, don't draw the light
3621 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3624 // if the light box is offscreen, skip it
3625 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3628 VectorCopy(rtlight->cullmins, rsurface.rtlight_cullmins);
3629 VectorCopy(rtlight->cullmaxs, rsurface.rtlight_cullmaxs);
3631 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3633 // compiled light, world available and can receive realtime lighting
3634 // retrieve leaf information
3635 numleafs = rtlight->static_numleafs;
3636 leaflist = rtlight->static_leaflist;
3637 leafpvs = rtlight->static_leafpvs;
3638 numsurfaces = rtlight->static_numsurfaces;
3639 surfacelist = rtlight->static_surfacelist;
3640 shadowtrispvs = rtlight->static_shadowtrispvs;
3641 lighttrispvs = rtlight->static_lighttrispvs;
3643 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3645 // dynamic light, world available and can receive realtime lighting
3646 // calculate lit surfaces and leafs
3647 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);
3648 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);
3649 leaflist = r_shadow_buffer_leaflist;
3650 leafpvs = r_shadow_buffer_leafpvs;
3651 surfacelist = r_shadow_buffer_surfacelist;
3652 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3653 lighttrispvs = r_shadow_buffer_lighttrispvs;
3654 // if the reduced leaf bounds are offscreen, skip it
3655 if (R_CullBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
3666 shadowtrispvs = NULL;
3667 lighttrispvs = NULL;
3669 // check if light is illuminating any visible leafs
3672 for (i = 0;i < numleafs;i++)
3673 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3678 // set up a scissor rectangle for this light
3679 if (R_Shadow_ScissorForBBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
3682 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3684 // make a list of lit entities and shadow casting entities
3685 numlightentities = 0;
3686 numlightentities_noselfshadow = 0;
3687 numshadowentities = 0;
3688 numshadowentities_noselfshadow = 0;
3689 // add dynamic entities that are lit by the light
3690 if (r_drawentities.integer)
3692 for (i = 0;i < r_refdef.scene.numentities;i++)
3695 entity_render_t *ent = r_refdef.scene.entities[i];
3697 if (!BoxesOverlap(ent->mins, ent->maxs, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
3699 // skip the object entirely if it is not within the valid
3700 // shadow-casting region (which includes the lit region)
3701 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rsurface.rtlight_numfrustumplanes, rsurface.rtlight_frustumplanes))
3703 if (!(model = ent->model))
3705 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
3707 // this entity wants to receive light, is visible, and is
3708 // inside the light box
3709 // TODO: check if the surfaces in the model can receive light
3710 // so now check if it's in a leaf seen by the light
3711 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))
3713 if (ent->flags & RENDER_NOSELFSHADOW)
3714 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
3716 lightentities[numlightentities++] = ent;
3717 // since it is lit, it probably also casts a shadow...
3718 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3719 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3720 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3722 // note: exterior models without the RENDER_NOSELFSHADOW
3723 // flag still create a RENDER_NOSELFSHADOW shadow but
3724 // are lit normally, this means that they are
3725 // self-shadowing but do not shadow other
3726 // RENDER_NOSELFSHADOW entities such as the gun
3727 // (very weird, but keeps the player shadow off the gun)
3728 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3729 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3731 shadowentities[numshadowentities++] = ent;
3734 else if (ent->flags & RENDER_SHADOW)
3736 // this entity is not receiving light, but may still need to
3738 // TODO: check if the surfaces in the model can cast shadow
3739 // now check if it is in a leaf seen by the light
3740 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))
3742 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3743 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3744 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3746 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3747 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3749 shadowentities[numshadowentities++] = ent;
3755 // return if there's nothing at all to light
3756 if (!numlightentities && !numsurfaces)
3759 // don't let sound skip if going slow
3760 if (r_refdef.scene.extraupdate)
3763 // make this the active rtlight for rendering purposes
3764 R_Shadow_RenderMode_ActiveLight(rtlight);
3765 // count this light in the r_speeds
3766 r_refdef.stats.lights++;
3768 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
3770 // optionally draw visible shape of the shadow volumes
3771 // for performance analysis by level designers
3772 R_Shadow_RenderMode_VisibleShadowVolumes();
3774 R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
3775 for (i = 0;i < numshadowentities;i++)
3776 R_Shadow_DrawEntityShadow(shadowentities[i]);
3777 for (i = 0;i < numshadowentities_noselfshadow;i++)
3778 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3781 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
3783 // optionally draw the illuminated areas
3784 // for performance analysis by level designers
3785 R_Shadow_RenderMode_VisibleLighting(false, false);
3787 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3788 for (i = 0;i < numlightentities;i++)
3789 R_Shadow_DrawEntityLight(lightentities[i]);
3790 for (i = 0;i < numlightentities_noselfshadow;i++)
3791 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3794 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
3796 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
3797 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
3798 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
3799 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
3800 lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
3801 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapping_maxsize.integer);
3803 if (castshadows && r_shadow_shadowmode >= 1 && r_shadow_shadowmode <= 3 && r_glsl.integer && gl_support_fragment_shader)
3808 r_shadow_shadowmaplod = 0;
3809 for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
3810 if ((r_shadow_shadowmapping_maxsize.integer >> i) > lodlinear)
3811 r_shadow_shadowmaplod = i;
3813 size = r_shadow_shadowmode == 3 ? r_shadow_shadowmapping_maxsize.integer >> r_shadow_shadowmaplod : lodlinear;
3814 size = bound(1, size, 2048);
3816 //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
3818 // render shadow casters into 6 sided depth texture
3819 for (side = 0;side < 6;side++)
3821 R_Shadow_RenderMode_ShadowMap(side, true, size);
3823 R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
3824 for (i = 0;i < numshadowentities;i++)
3825 R_Shadow_DrawEntityShadow(shadowentities[i]);
3828 if (numlightentities_noselfshadow)
3830 // render lighting using the depth texture as shadowmap
3831 // draw lighting in the unmasked areas
3832 R_Shadow_RenderMode_Lighting(false, false, true);
3833 for (i = 0;i < numlightentities_noselfshadow;i++)
3834 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3837 // render shadow casters into 6 sided depth texture
3838 for (side = 0;side < 6;side++)
3840 R_Shadow_RenderMode_ShadowMap(side, false, size);
3841 for (i = 0;i < numshadowentities_noselfshadow;i++)
3842 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3845 // render lighting using the depth texture as shadowmap
3846 // draw lighting in the unmasked areas
3847 R_Shadow_RenderMode_Lighting(false, false, true);
3848 // draw lighting in the unmasked areas
3850 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3851 for (i = 0;i < numlightentities;i++)
3852 R_Shadow_DrawEntityLight(lightentities[i]);
3854 else if (castshadows && gl_stencil)
3856 // draw stencil shadow volumes to mask off pixels that are in shadow
3857 // so that they won't receive lighting
3858 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
3859 R_Shadow_ClearStencil();
3861 R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
3862 for (i = 0;i < numshadowentities;i++)
3863 R_Shadow_DrawEntityShadow(shadowentities[i]);
3864 if (numlightentities_noselfshadow)
3866 // draw lighting in the unmasked areas
3867 R_Shadow_RenderMode_Lighting(true, false, false);
3868 for (i = 0;i < numlightentities_noselfshadow;i++)
3869 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3871 // optionally draw the illuminated areas
3872 // for performance analysis by level designers
3873 if (r_showlighting.integer && r_refdef.view.showdebug)
3875 R_Shadow_RenderMode_VisibleLighting(!r_showdisabledepthtest.integer, false);
3876 for (i = 0;i < numlightentities_noselfshadow;i++)
3877 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3880 for (i = 0;i < numshadowentities_noselfshadow;i++)
3881 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3883 if (numsurfaces + numlightentities)
3885 // draw lighting in the unmasked areas
3886 R_Shadow_RenderMode_Lighting(true, false, false);
3888 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3889 for (i = 0;i < numlightentities;i++)
3890 R_Shadow_DrawEntityLight(lightentities[i]);
3895 if (numsurfaces + numlightentities)
3897 // draw lighting in the unmasked areas
3898 R_Shadow_RenderMode_Lighting(false, false, false);
3900 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3901 for (i = 0;i < numlightentities;i++)
3902 R_Shadow_DrawEntityLight(lightentities[i]);
3903 for (i = 0;i < numlightentities_noselfshadow;i++)
3904 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3909 void R_Shadow_DrawLightSprites(void);
3910 void R_ShadowVolumeLighting(qboolean visible)
3918 if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, 2048) ||
3919 (r_shadow_shadowmode != 0) != (r_shadow_shadowmapping.integer != 0) ||
3920 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0) ||
3921 r_shadow_shadowmaptexturetype != r_shadow_shadowmapping_texturetype.integer ||
3922 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
3923 r_shadow_shadowmapprecision != r_shadow_shadowmapping_precision.integer ||
3924 r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
3925 R_Shadow_FreeShadowMaps();
3927 if (r_editlights.integer)
3928 R_Shadow_DrawLightSprites();
3930 R_Shadow_RenderMode_Begin();
3932 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3933 if (r_shadow_debuglight.integer >= 0)
3935 lightindex = r_shadow_debuglight.integer;
3936 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3937 if (light && (light->flags & flag))
3938 R_DrawRTLight(&light->rtlight, visible);
3942 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3943 for (lightindex = 0;lightindex < range;lightindex++)
3945 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3946 if (light && (light->flags & flag))
3947 R_DrawRTLight(&light->rtlight, visible);
3950 if (r_refdef.scene.rtdlight)
3951 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
3952 R_DrawRTLight(r_refdef.scene.lights[lnum], visible);
3954 R_Shadow_RenderMode_End();
3957 extern const float r_screenvertex3f[12];
3958 extern void R_SetupView(qboolean allowwaterclippingplane);
3959 extern void R_ResetViewRendering3D(void);
3960 extern void R_ResetViewRendering2D(void);
3961 extern cvar_t r_shadows;
3962 extern cvar_t r_shadows_darken;
3963 extern cvar_t r_shadows_drawafterrtlighting;
3964 extern cvar_t r_shadows_castfrombmodels;
3965 extern cvar_t r_shadows_throwdistance;
3966 extern cvar_t r_shadows_throwdirection;
3967 void R_DrawModelShadows(void)
3970 float relativethrowdistance;
3971 entity_render_t *ent;
3972 vec3_t relativelightorigin;
3973 vec3_t relativelightdirection;
3974 vec3_t relativeshadowmins, relativeshadowmaxs;
3975 vec3_t tmp, shadowdir;
3977 if (!r_drawentities.integer || !gl_stencil)
3981 R_ResetViewRendering3D();
3982 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
3983 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
3984 R_Shadow_RenderMode_Begin();
3985 R_Shadow_RenderMode_ActiveLight(NULL);
3986 r_shadow_lightscissor[0] = r_refdef.view.x;
3987 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
3988 r_shadow_lightscissor[2] = r_refdef.view.width;
3989 r_shadow_lightscissor[3] = r_refdef.view.height;
3990 R_Shadow_RenderMode_StencilShadowVolumes(false);
3993 if (r_shadows.integer == 2)
3995 Math_atov(r_shadows_throwdirection.string, shadowdir);
3996 VectorNormalize(shadowdir);
3999 R_Shadow_ClearStencil();
4001 for (i = 0;i < r_refdef.scene.numentities;i++)
4003 ent = r_refdef.scene.entities[i];
4005 // cast shadows from anything of the map (submodels are optional)
4006 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4008 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4009 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
4010 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
4011 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
4012 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4015 if(ent->entitynumber != 0)
4017 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
4018 int entnum, entnum2, recursion;
4019 entnum = entnum2 = ent->entitynumber;
4020 for(recursion = 32; recursion > 0; --recursion)
4022 entnum2 = cl.entities[entnum].state_current.tagentity;
4023 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
4028 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
4030 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
4031 // transform into modelspace of OUR entity
4032 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
4033 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
4036 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4039 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4042 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
4043 RSurf_ActiveModelEntity(ent, false, false);
4044 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4045 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4049 // not really the right mode, but this will disable any silly stencil features
4050 R_Shadow_RenderMode_End();
4052 // set up ortho view for rendering this pass
4053 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4054 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4055 //GL_ScissorTest(true);
4056 //R_Mesh_Matrix(&identitymatrix);
4057 //R_Mesh_ResetTextureState();
4058 R_ResetViewRendering2D();
4059 R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
4060 R_Mesh_ColorPointer(NULL, 0, 0);
4061 R_SetupGenericShader(false);
4063 // set up a darkening blend on shadowed areas
4064 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4065 //GL_DepthRange(0, 1);
4066 //GL_DepthTest(false);
4067 //GL_DepthMask(false);
4068 //GL_PolygonOffset(0, 0);CHECKGLERROR
4069 GL_Color(0, 0, 0, r_shadows_darken.value);
4070 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4071 //qglDepthFunc(GL_ALWAYS);CHECKGLERROR
4072 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
4073 qglStencilMask(~0);CHECKGLERROR
4074 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
4075 qglStencilFunc(GL_NOTEQUAL, 128, ~0);CHECKGLERROR
4077 // apply the blend to the shadowed areas
4078 R_Mesh_Draw(0, 4, 0, 2, NULL, polygonelements, 0, 0);
4080 // restore the viewport
4081 R_SetViewport(&r_refdef.view.viewport);
4083 // restore other state to normal
4084 //R_Shadow_RenderMode_End();
4087 void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4090 vec3_t centerorigin;
4091 // if it's too close, skip it
4092 if (VectorLength(rtlight->color) < (1.0f / 256.0f))
4094 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4097 if (usequery && r_numqueries + 2 <= r_maxqueries)
4099 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4100 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4101 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4104 // 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
4105 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
4106 qglDepthFunc(GL_ALWAYS);
4107 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);
4108 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4109 qglDepthFunc(GL_LEQUAL);
4110 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
4111 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);
4112 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4115 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4118 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4121 GLint allpixels = 0, visiblepixels = 0;
4122 // now we have to check the query result
4123 if (rtlight->corona_queryindex_visiblepixels)
4126 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
4127 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
4129 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
4130 if (visiblepixels < 1 || allpixels < 1)
4132 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
4133 cscale *= rtlight->corona_visibility;
4137 // FIXME: these traces should scan all render entities instead of cl.world
4138 if (CL_Move(r_refdef.view.origin, vec3_origin, vec3_origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
4141 VectorScale(rtlight->color, cscale, color);
4142 if (VectorLength(color) > (1.0f / 256.0f))
4143 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);
4146 void R_DrawCoronas(void)
4154 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4156 if (r_waterstate.renderingscene)
4158 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4159 R_Mesh_Matrix(&identitymatrix);
4161 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4163 // check occlusion of coronas
4164 // use GL_ARB_occlusion_query if available
4165 // otherwise use raytraces
4167 usequery = gl_support_arb_occlusion_query && r_coronas_occlusionquery.integer;
4170 GL_ColorMask(0,0,0,0);
4171 if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
4172 if (r_maxqueries < R_MAX_OCCLUSION_QUERIES)
4175 r_maxqueries = (range + r_refdef.scene.numlights) * 4;
4176 r_maxqueries = min(r_maxqueries, R_MAX_OCCLUSION_QUERIES);
4178 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
4182 for (lightindex = 0;lightindex < range;lightindex++)
4184 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4187 rtlight = &light->rtlight;
4188 rtlight->corona_visibility = 0;
4189 rtlight->corona_queryindex_visiblepixels = 0;
4190 rtlight->corona_queryindex_allpixels = 0;
4191 if (!(rtlight->flags & flag))
4193 if (rtlight->corona <= 0)
4195 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4197 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4199 for (i = 0;i < r_refdef.scene.numlights;i++)
4201 rtlight = r_refdef.scene.lights[i];
4202 rtlight->corona_visibility = 0;
4203 rtlight->corona_queryindex_visiblepixels = 0;
4204 rtlight->corona_queryindex_allpixels = 0;
4205 if (!(rtlight->flags & flag))
4207 if (rtlight->corona <= 0)
4209 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4212 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4214 // now draw the coronas using the query data for intensity info
4215 for (lightindex = 0;lightindex < range;lightindex++)
4217 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4220 rtlight = &light->rtlight;
4221 if (rtlight->corona_visibility <= 0)
4223 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4225 for (i = 0;i < r_refdef.scene.numlights;i++)
4227 rtlight = r_refdef.scene.lights[i];
4228 if (rtlight->corona_visibility <= 0)
4230 if (gl_flashblend.integer)
4231 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4233 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4239 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
4240 typedef struct suffixinfo_s
4243 qboolean flipx, flipy, flipdiagonal;
4246 static suffixinfo_t suffix[3][6] =
4249 {"px", false, false, false},
4250 {"nx", false, false, false},
4251 {"py", false, false, false},
4252 {"ny", false, false, false},
4253 {"pz", false, false, false},
4254 {"nz", false, false, false}
4257 {"posx", false, false, false},
4258 {"negx", false, false, false},
4259 {"posy", false, false, false},
4260 {"negy", false, false, false},
4261 {"posz", false, false, false},
4262 {"negz", false, false, false}
4265 {"rt", true, false, true},
4266 {"lf", false, true, true},
4267 {"ft", true, true, false},
4268 {"bk", false, false, false},
4269 {"up", true, false, true},
4270 {"dn", true, false, true}
4274 static int componentorder[4] = {0, 1, 2, 3};
4276 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
4278 int i, j, cubemapsize;
4279 unsigned char *cubemappixels, *image_buffer;
4280 rtexture_t *cubemaptexture;
4282 // must start 0 so the first loadimagepixels has no requested width/height
4284 cubemappixels = NULL;
4285 cubemaptexture = NULL;
4286 // keep trying different suffix groups (posx, px, rt) until one loads
4287 for (j = 0;j < 3 && !cubemappixels;j++)
4289 // load the 6 images in the suffix group
4290 for (i = 0;i < 6;i++)
4292 // generate an image name based on the base and and suffix
4293 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
4295 if ((image_buffer = loadimagepixelsbgra(name, false, false)))
4297 // an image loaded, make sure width and height are equal
4298 if (image_width == image_height && (!cubemappixels || image_width == cubemapsize))
4300 // if this is the first image to load successfully, allocate the cubemap memory
4301 if (!cubemappixels && image_width >= 1)
4303 cubemapsize = image_width;
4304 // note this clears to black, so unavailable sides are black
4305 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
4307 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
4309 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);
4312 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
4314 Mem_Free(image_buffer);
4318 // if a cubemap loaded, upload it
4321 if (developer_loading.integer)
4322 Con_Printf("loading cubemap \"%s\"\n", basename);
4324 if (!r_shadow_filters_texturepool)
4325 r_shadow_filters_texturepool = R_AllocTexturePool();
4326 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_BGRA, TEXF_PRECACHE | (gl_texturecompression_lightcubemaps.integer ? TEXF_COMPRESS : 0) | TEXF_FORCELINEAR, NULL);
4327 Mem_Free(cubemappixels);
4331 Con_DPrintf("failed to load cubemap \"%s\"\n", basename);
4332 if (developer_loading.integer)
4334 Con_Printf("(tried tried images ");
4335 for (j = 0;j < 3;j++)
4336 for (i = 0;i < 6;i++)
4337 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
4338 Con_Print(" and was unable to find any of them).\n");
4341 return cubemaptexture;
4344 rtexture_t *R_Shadow_Cubemap(const char *basename)
4347 for (i = 0;i < numcubemaps;i++)
4348 if (!strcasecmp(cubemaps[i].basename, basename))
4349 return cubemaps[i].texture ? cubemaps[i].texture : r_texture_whitecube;
4350 if (i >= MAX_CUBEMAPS)
4351 return r_texture_whitecube;
4353 strlcpy(cubemaps[i].basename, basename, sizeof(cubemaps[i].basename));
4354 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
4355 return cubemaps[i].texture;
4358 void R_Shadow_FreeCubemaps(void)
4361 for (i = 0;i < numcubemaps;i++)
4363 if (developer_loading.integer)
4364 Con_Printf("unloading cubemap \"%s\"\n", cubemaps[i].basename);
4365 if (cubemaps[i].texture)
4366 R_FreeTexture(cubemaps[i].texture);
4370 R_FreeTexturePool(&r_shadow_filters_texturepool);
4373 dlight_t *R_Shadow_NewWorldLight(void)
4375 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4378 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)
4381 // validate parameters
4382 if (style < 0 || style >= MAX_LIGHTSTYLES)
4384 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
4390 // copy to light properties
4391 VectorCopy(origin, light->origin);
4392 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4393 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4394 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4395 light->color[0] = max(color[0], 0);
4396 light->color[1] = max(color[1], 0);
4397 light->color[2] = max(color[2], 0);
4398 light->radius = max(radius, 0);
4399 light->style = style;
4400 light->shadow = shadowenable;
4401 light->corona = corona;
4402 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4403 light->coronasizescale = coronasizescale;
4404 light->ambientscale = ambientscale;
4405 light->diffusescale = diffusescale;
4406 light->specularscale = specularscale;
4407 light->flags = flags;
4409 // update renderable light data
4410 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4411 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);
4414 void R_Shadow_FreeWorldLight(dlight_t *light)
4416 if (r_shadow_selectedlight == light)
4417 r_shadow_selectedlight = NULL;
4418 R_RTLight_Uncompile(&light->rtlight);
4419 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4422 void R_Shadow_ClearWorldLights(void)
4426 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4427 for (lightindex = 0;lightindex < range;lightindex++)
4429 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4431 R_Shadow_FreeWorldLight(light);
4433 r_shadow_selectedlight = NULL;
4434 R_Shadow_FreeCubemaps();
4437 void R_Shadow_SelectLight(dlight_t *light)
4439 if (r_shadow_selectedlight)
4440 r_shadow_selectedlight->selected = false;
4441 r_shadow_selectedlight = light;
4442 if (r_shadow_selectedlight)
4443 r_shadow_selectedlight->selected = true;
4446 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4448 // this is never batched (there can be only one)
4449 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);
4452 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4459 // this is never batched (due to the ent parameter changing every time)
4460 // so numsurfaces == 1 and surfacelist[0] == lightnumber
4461 const dlight_t *light = (dlight_t *)ent;
4464 VectorScale(light->color, intensity, spritecolor);
4465 if (VectorLength(spritecolor) < 0.1732f)
4466 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
4467 if (VectorLength(spritecolor) > 1.0f)
4468 VectorNormalize(spritecolor);
4470 // draw light sprite
4471 if (light->cubemapname[0] && !light->shadow)
4472 pic = r_editlights_sprcubemapnoshadowlight;
4473 else if (light->cubemapname[0])
4474 pic = r_editlights_sprcubemaplight;
4475 else if (!light->shadow)
4476 pic = r_editlights_sprnoshadowlight;
4478 pic = r_editlights_sprlight;
4479 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);
4480 // draw selection sprite if light is selected
4481 if (light->selected)
4482 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);
4483 // VorteX todo: add normalmode/realtime mode light overlay sprites?
4486 void R_Shadow_DrawLightSprites(void)
4490 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4491 for (lightindex = 0;lightindex < range;lightindex++)
4493 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4495 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
4497 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
4500 void R_Shadow_SelectLightInView(void)
4502 float bestrating, rating, temp[3];
4506 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4509 for (lightindex = 0;lightindex < range;lightindex++)
4511 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4514 VectorSubtract(light->origin, r_refdef.view.origin, temp);
4515 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
4518 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
4519 if (bestrating < rating && CL_Move(light->origin, vec3_origin, vec3_origin, r_refdef.view.origin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1.0f)
4521 bestrating = rating;
4526 R_Shadow_SelectLight(best);
4529 void R_Shadow_LoadWorldLights(void)
4531 int n, a, style, shadow, flags;
4532 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
4533 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
4534 if (cl.worldmodel == NULL)
4536 Con_Print("No map loaded.\n");
4539 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4540 strlcat (name, ".rtlights", sizeof (name));
4541 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4551 for (;COM_Parse(t, true) && strcmp(
4552 if (COM_Parse(t, true))
4554 if (com_token[0] == '!')
4557 origin[0] = atof(com_token+1);
4560 origin[0] = atof(com_token);
4565 while (*s && *s != '\n' && *s != '\r')
4571 // check for modifier flags
4578 #if _MSC_VER >= 1400
4579 #define sscanf sscanf_s
4581 cubemapname[sizeof(cubemapname)-1] = 0;
4582 #if MAX_QPATH != 128
4583 #error update this code if MAX_QPATH changes
4585 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
4586 #if _MSC_VER >= 1400
4587 , sizeof(cubemapname)
4589 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
4592 flags = LIGHTFLAG_REALTIMEMODE;
4600 coronasizescale = 0.25f;
4602 VectorClear(angles);
4605 if (a < 9 || !strcmp(cubemapname, "\"\""))
4607 // remove quotes on cubemapname
4608 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
4611 namelen = strlen(cubemapname) - 2;
4612 memmove(cubemapname, cubemapname + 1, namelen);
4613 cubemapname[namelen] = '\0';
4617 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);
4620 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4628 Con_Printf("invalid rtlights file \"%s\"\n", name);
4629 Mem_Free(lightsstring);
4633 void R_Shadow_SaveWorldLights(void)
4637 size_t bufchars, bufmaxchars;
4639 char name[MAX_QPATH];
4640 char line[MAX_INPUTLINE];
4641 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
4642 // I hate lines which are 3 times my screen size :( --blub
4645 if (cl.worldmodel == NULL)
4647 Con_Print("No map loaded.\n");
4650 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4651 strlcat (name, ".rtlights", sizeof (name));
4652 bufchars = bufmaxchars = 0;
4654 for (lightindex = 0;lightindex < range;lightindex++)
4656 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4659 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
4660 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);
4661 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
4662 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]);
4664 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);
4665 if (bufchars + strlen(line) > bufmaxchars)
4667 bufmaxchars = bufchars + strlen(line) + 2048;
4669 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
4673 memcpy(buf, oldbuf, bufchars);
4679 memcpy(buf + bufchars, line, strlen(line));
4680 bufchars += strlen(line);
4684 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
4689 void R_Shadow_LoadLightsFile(void)
4692 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
4693 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
4694 if (cl.worldmodel == NULL)
4696 Con_Print("No map loaded.\n");
4699 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4700 strlcat (name, ".lights", sizeof (name));
4701 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4709 while (*s && *s != '\n' && *s != '\r')
4715 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);
4719 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);
4722 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
4723 radius = bound(15, radius, 4096);
4724 VectorScale(color, (2.0f / (8388608.0f)), color);
4725 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
4733 Con_Printf("invalid lights file \"%s\"\n", name);
4734 Mem_Free(lightsstring);
4738 // tyrlite/hmap2 light types in the delay field
4739 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
4741 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
4743 int entnum, style, islight, skin, pflags, effects, type, n;
4746 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
4747 char key[256], value[MAX_INPUTLINE];
4749 if (cl.worldmodel == NULL)
4751 Con_Print("No map loaded.\n");
4754 // try to load a .ent file first
4755 FS_StripExtension (cl.worldmodel->name, key, sizeof (key));
4756 strlcat (key, ".ent", sizeof (key));
4757 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
4758 // and if that is not found, fall back to the bsp file entity string
4760 data = cl.worldmodel->brush.entities;
4763 for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
4765 type = LIGHTTYPE_MINUSX;
4766 origin[0] = origin[1] = origin[2] = 0;
4767 originhack[0] = originhack[1] = originhack[2] = 0;
4768 angles[0] = angles[1] = angles[2] = 0;
4769 color[0] = color[1] = color[2] = 1;
4770 light[0] = light[1] = light[2] = 1;light[3] = 300;
4771 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
4781 if (!COM_ParseToken_Simple(&data, false, false))
4783 if (com_token[0] == '}')
4784 break; // end of entity
4785 if (com_token[0] == '_')
4786 strlcpy(key, com_token + 1, sizeof(key));
4788 strlcpy(key, com_token, sizeof(key));
4789 while (key[strlen(key)-1] == ' ') // remove trailing spaces
4790 key[strlen(key)-1] = 0;
4791 if (!COM_ParseToken_Simple(&data, false, false))
4793 strlcpy(value, com_token, sizeof(value));
4795 // now that we have the key pair worked out...
4796 if (!strcmp("light", key))
4798 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
4802 light[0] = vec[0] * (1.0f / 256.0f);
4803 light[1] = vec[0] * (1.0f / 256.0f);
4804 light[2] = vec[0] * (1.0f / 256.0f);
4810 light[0] = vec[0] * (1.0f / 255.0f);
4811 light[1] = vec[1] * (1.0f / 255.0f);
4812 light[2] = vec[2] * (1.0f / 255.0f);
4816 else if (!strcmp("delay", key))
4818 else if (!strcmp("origin", key))
4819 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
4820 else if (!strcmp("angle", key))
4821 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
4822 else if (!strcmp("angles", key))
4823 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
4824 else if (!strcmp("color", key))
4825 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
4826 else if (!strcmp("wait", key))
4827 fadescale = atof(value);
4828 else if (!strcmp("classname", key))
4830 if (!strncmp(value, "light", 5))
4833 if (!strcmp(value, "light_fluoro"))
4838 overridecolor[0] = 1;
4839 overridecolor[1] = 1;
4840 overridecolor[2] = 1;
4842 if (!strcmp(value, "light_fluorospark"))
4847 overridecolor[0] = 1;
4848 overridecolor[1] = 1;
4849 overridecolor[2] = 1;
4851 if (!strcmp(value, "light_globe"))
4856 overridecolor[0] = 1;
4857 overridecolor[1] = 0.8;
4858 overridecolor[2] = 0.4;
4860 if (!strcmp(value, "light_flame_large_yellow"))
4865 overridecolor[0] = 1;
4866 overridecolor[1] = 0.5;
4867 overridecolor[2] = 0.1;
4869 if (!strcmp(value, "light_flame_small_yellow"))
4874 overridecolor[0] = 1;
4875 overridecolor[1] = 0.5;
4876 overridecolor[2] = 0.1;
4878 if (!strcmp(value, "light_torch_small_white"))
4883 overridecolor[0] = 1;
4884 overridecolor[1] = 0.5;
4885 overridecolor[2] = 0.1;
4887 if (!strcmp(value, "light_torch_small_walltorch"))
4892 overridecolor[0] = 1;
4893 overridecolor[1] = 0.5;
4894 overridecolor[2] = 0.1;
4898 else if (!strcmp("style", key))
4899 style = atoi(value);
4900 else if (!strcmp("skin", key))
4901 skin = (int)atof(value);
4902 else if (!strcmp("pflags", key))
4903 pflags = (int)atof(value);
4904 else if (!strcmp("effects", key))
4905 effects = (int)atof(value);
4906 else if (cl.worldmodel->type == mod_brushq3)
4908 if (!strcmp("scale", key))
4909 lightscale = atof(value);
4910 if (!strcmp("fade", key))
4911 fadescale = atof(value);
4916 if (lightscale <= 0)
4920 if (color[0] == color[1] && color[0] == color[2])
4922 color[0] *= overridecolor[0];
4923 color[1] *= overridecolor[1];
4924 color[2] *= overridecolor[2];
4926 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
4927 color[0] = color[0] * light[0];
4928 color[1] = color[1] * light[1];
4929 color[2] = color[2] * light[2];
4932 case LIGHTTYPE_MINUSX:
4934 case LIGHTTYPE_RECIPX:
4936 VectorScale(color, (1.0f / 16.0f), color);
4938 case LIGHTTYPE_RECIPXX:
4940 VectorScale(color, (1.0f / 16.0f), color);
4943 case LIGHTTYPE_NONE:
4947 case LIGHTTYPE_MINUSXX:
4950 VectorAdd(origin, originhack, origin);
4952 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);
4955 Mem_Free(entfiledata);
4959 void R_Shadow_SetCursorLocationForView(void)
4962 vec3_t dest, endpos;
4964 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
4965 trace = CL_Move(r_refdef.view.origin, vec3_origin, vec3_origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
4966 if (trace.fraction < 1)
4968 dist = trace.fraction * r_editlights_cursordistance.value;
4969 push = r_editlights_cursorpushback.value;
4973 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
4974 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
4978 VectorClear( endpos );
4980 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
4981 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
4982 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
4985 void R_Shadow_UpdateWorldLightSelection(void)
4987 if (r_editlights.integer)
4989 R_Shadow_SetCursorLocationForView();
4990 R_Shadow_SelectLightInView();
4993 R_Shadow_SelectLight(NULL);
4996 void R_Shadow_EditLights_Clear_f(void)
4998 R_Shadow_ClearWorldLights();
5001 void R_Shadow_EditLights_Reload_f(void)
5005 strlcpy(r_shadow_mapname, cl.worldmodel->name, sizeof(r_shadow_mapname));
5006 R_Shadow_ClearWorldLights();
5007 R_Shadow_LoadWorldLights();
5008 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5010 R_Shadow_LoadLightsFile();
5011 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5012 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5016 void R_Shadow_EditLights_Save_f(void)
5020 R_Shadow_SaveWorldLights();
5023 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
5025 R_Shadow_ClearWorldLights();
5026 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5029 void R_Shadow_EditLights_ImportLightsFile_f(void)
5031 R_Shadow_ClearWorldLights();
5032 R_Shadow_LoadLightsFile();
5035 void R_Shadow_EditLights_Spawn_f(void)
5038 if (!r_editlights.integer)
5040 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5043 if (Cmd_Argc() != 1)
5045 Con_Print("r_editlights_spawn does not take parameters\n");
5048 color[0] = color[1] = color[2] = 1;
5049 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5052 void R_Shadow_EditLights_Edit_f(void)
5054 vec3_t origin, angles, color;
5055 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5056 int style, shadows, flags, normalmode, realtimemode;
5057 char cubemapname[MAX_INPUTLINE];
5058 if (!r_editlights.integer)
5060 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5063 if (!r_shadow_selectedlight)
5065 Con_Print("No selected light.\n");
5068 VectorCopy(r_shadow_selectedlight->origin, origin);
5069 VectorCopy(r_shadow_selectedlight->angles, angles);
5070 VectorCopy(r_shadow_selectedlight->color, color);
5071 radius = r_shadow_selectedlight->radius;
5072 style = r_shadow_selectedlight->style;
5073 if (r_shadow_selectedlight->cubemapname)
5074 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5077 shadows = r_shadow_selectedlight->shadow;
5078 corona = r_shadow_selectedlight->corona;
5079 coronasizescale = r_shadow_selectedlight->coronasizescale;
5080 ambientscale = r_shadow_selectedlight->ambientscale;
5081 diffusescale = r_shadow_selectedlight->diffusescale;
5082 specularscale = r_shadow_selectedlight->specularscale;
5083 flags = r_shadow_selectedlight->flags;
5084 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5085 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5086 if (!strcmp(Cmd_Argv(1), "origin"))
5088 if (Cmd_Argc() != 5)
5090 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5093 origin[0] = atof(Cmd_Argv(2));
5094 origin[1] = atof(Cmd_Argv(3));
5095 origin[2] = atof(Cmd_Argv(4));
5097 else if (!strcmp(Cmd_Argv(1), "originx"))
5099 if (Cmd_Argc() != 3)
5101 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5104 origin[0] = atof(Cmd_Argv(2));
5106 else if (!strcmp(Cmd_Argv(1), "originy"))
5108 if (Cmd_Argc() != 3)
5110 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5113 origin[1] = atof(Cmd_Argv(2));
5115 else if (!strcmp(Cmd_Argv(1), "originz"))
5117 if (Cmd_Argc() != 3)
5119 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5122 origin[2] = atof(Cmd_Argv(2));
5124 else if (!strcmp(Cmd_Argv(1), "move"))
5126 if (Cmd_Argc() != 5)
5128 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5131 origin[0] += atof(Cmd_Argv(2));
5132 origin[1] += atof(Cmd_Argv(3));
5133 origin[2] += atof(Cmd_Argv(4));
5135 else if (!strcmp(Cmd_Argv(1), "movex"))
5137 if (Cmd_Argc() != 3)
5139 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5142 origin[0] += atof(Cmd_Argv(2));
5144 else if (!strcmp(Cmd_Argv(1), "movey"))
5146 if (Cmd_Argc() != 3)
5148 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5151 origin[1] += atof(Cmd_Argv(2));
5153 else if (!strcmp(Cmd_Argv(1), "movez"))
5155 if (Cmd_Argc() != 3)
5157 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5160 origin[2] += atof(Cmd_Argv(2));
5162 else if (!strcmp(Cmd_Argv(1), "angles"))
5164 if (Cmd_Argc() != 5)
5166 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5169 angles[0] = atof(Cmd_Argv(2));
5170 angles[1] = atof(Cmd_Argv(3));
5171 angles[2] = atof(Cmd_Argv(4));
5173 else if (!strcmp(Cmd_Argv(1), "anglesx"))
5175 if (Cmd_Argc() != 3)
5177 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5180 angles[0] = atof(Cmd_Argv(2));
5182 else if (!strcmp(Cmd_Argv(1), "anglesy"))
5184 if (Cmd_Argc() != 3)
5186 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5189 angles[1] = atof(Cmd_Argv(2));
5191 else if (!strcmp(Cmd_Argv(1), "anglesz"))
5193 if (Cmd_Argc() != 3)
5195 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5198 angles[2] = atof(Cmd_Argv(2));
5200 else if (!strcmp(Cmd_Argv(1), "color"))
5202 if (Cmd_Argc() != 5)
5204 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
5207 color[0] = atof(Cmd_Argv(2));
5208 color[1] = atof(Cmd_Argv(3));
5209 color[2] = atof(Cmd_Argv(4));
5211 else if (!strcmp(Cmd_Argv(1), "radius"))
5213 if (Cmd_Argc() != 3)
5215 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5218 radius = atof(Cmd_Argv(2));
5220 else if (!strcmp(Cmd_Argv(1), "colorscale"))
5222 if (Cmd_Argc() == 3)
5224 double scale = atof(Cmd_Argv(2));
5231 if (Cmd_Argc() != 5)
5233 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
5236 color[0] *= atof(Cmd_Argv(2));
5237 color[1] *= atof(Cmd_Argv(3));
5238 color[2] *= atof(Cmd_Argv(4));
5241 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
5243 if (Cmd_Argc() != 3)
5245 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5248 radius *= atof(Cmd_Argv(2));
5250 else if (!strcmp(Cmd_Argv(1), "style"))
5252 if (Cmd_Argc() != 3)
5254 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5257 style = atoi(Cmd_Argv(2));
5259 else if (!strcmp(Cmd_Argv(1), "cubemap"))
5263 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5266 if (Cmd_Argc() == 3)
5267 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
5271 else if (!strcmp(Cmd_Argv(1), "shadows"))
5273 if (Cmd_Argc() != 3)
5275 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5278 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5280 else if (!strcmp(Cmd_Argv(1), "corona"))
5282 if (Cmd_Argc() != 3)
5284 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5287 corona = atof(Cmd_Argv(2));
5289 else if (!strcmp(Cmd_Argv(1), "coronasize"))
5291 if (Cmd_Argc() != 3)
5293 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5296 coronasizescale = atof(Cmd_Argv(2));
5298 else if (!strcmp(Cmd_Argv(1), "ambient"))
5300 if (Cmd_Argc() != 3)
5302 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5305 ambientscale = atof(Cmd_Argv(2));
5307 else if (!strcmp(Cmd_Argv(1), "diffuse"))
5309 if (Cmd_Argc() != 3)
5311 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5314 diffusescale = atof(Cmd_Argv(2));
5316 else if (!strcmp(Cmd_Argv(1), "specular"))
5318 if (Cmd_Argc() != 3)
5320 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5323 specularscale = atof(Cmd_Argv(2));
5325 else if (!strcmp(Cmd_Argv(1), "normalmode"))
5327 if (Cmd_Argc() != 3)
5329 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5332 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5334 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
5336 if (Cmd_Argc() != 3)
5338 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5341 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5345 Con_Print("usage: r_editlights_edit [property] [value]\n");
5346 Con_Print("Selected light's properties:\n");
5347 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5348 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5349 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5350 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
5351 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
5352 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
5353 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5354 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
5355 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
5356 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
5357 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
5358 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
5359 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5360 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5363 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5364 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5367 void R_Shadow_EditLights_EditAll_f(void)
5373 if (!r_editlights.integer)
5375 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5379 // EditLights doesn't seem to have a "remove" command or something so:
5380 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5381 for (lightindex = 0;lightindex < range;lightindex++)
5383 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5386 R_Shadow_SelectLight(light);
5387 R_Shadow_EditLights_Edit_f();
5391 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
5393 int lightnumber, lightcount;
5394 size_t lightindex, range;
5398 if (!r_editlights.integer)
5400 x = vid_conwidth.value - 240;
5402 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
5405 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5406 for (lightindex = 0;lightindex < range;lightindex++)
5408 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5411 if (light == r_shadow_selectedlight)
5412 lightnumber = lightindex;
5415 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;
5416 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;
5418 if (r_shadow_selectedlight == NULL)
5420 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;
5421 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;
5422 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;
5423 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;
5424 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;
5425 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;
5426 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;
5427 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;
5428 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;
5429 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;
5430 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;
5431 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;
5432 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;
5433 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;
5434 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;
5437 void R_Shadow_EditLights_ToggleShadow_f(void)
5439 if (!r_editlights.integer)
5441 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5444 if (!r_shadow_selectedlight)
5446 Con_Print("No selected light.\n");
5449 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);
5452 void R_Shadow_EditLights_ToggleCorona_f(void)
5454 if (!r_editlights.integer)
5456 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5459 if (!r_shadow_selectedlight)
5461 Con_Print("No selected light.\n");
5464 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);
5467 void R_Shadow_EditLights_Remove_f(void)
5469 if (!r_editlights.integer)
5471 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
5474 if (!r_shadow_selectedlight)
5476 Con_Print("No selected light.\n");
5479 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
5480 r_shadow_selectedlight = NULL;
5483 void R_Shadow_EditLights_Help_f(void)
5486 "Documentation on r_editlights system:\n"
5488 "r_editlights : enable/disable editing mode\n"
5489 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
5490 "r_editlights_cursorpushback : push back cursor this far from surface\n"
5491 "r_editlights_cursorpushoff : push cursor off surface this far\n"
5492 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
5493 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
5495 "r_editlights_help : this help\n"
5496 "r_editlights_clear : remove all lights\n"
5497 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
5498 "r_editlights_save : save to .rtlights file\n"
5499 "r_editlights_spawn : create a light with default settings\n"
5500 "r_editlights_edit command : edit selected light - more documentation below\n"
5501 "r_editlights_remove : remove selected light\n"
5502 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
5503 "r_editlights_importlightentitiesfrommap : reload light entities\n"
5504 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
5506 "origin x y z : set light location\n"
5507 "originx x: set x component of light location\n"
5508 "originy y: set y component of light location\n"
5509 "originz z: set z component of light location\n"
5510 "move x y z : adjust light location\n"
5511 "movex x: adjust x component of light location\n"
5512 "movey y: adjust y component of light location\n"
5513 "movez z: adjust z component of light location\n"
5514 "angles x y z : set light angles\n"
5515 "anglesx x: set x component of light angles\n"
5516 "anglesy y: set y component of light angles\n"
5517 "anglesz z: set z component of light angles\n"
5518 "color r g b : set color of light (can be brighter than 1 1 1)\n"
5519 "radius radius : set radius (size) of light\n"
5520 "colorscale grey : multiply color of light (1 does nothing)\n"
5521 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
5522 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
5523 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
5524 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
5525 "cubemap basename : set filter cubemap of light (not yet supported)\n"
5526 "shadows 1/0 : turn on/off shadows\n"
5527 "corona n : set corona intensity\n"
5528 "coronasize n : set corona size (0-1)\n"
5529 "ambient n : set ambient intensity (0-1)\n"
5530 "diffuse n : set diffuse intensity (0-1)\n"
5531 "specular n : set specular intensity (0-1)\n"
5532 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
5533 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
5534 "<nothing> : print light properties to console\n"
5538 void R_Shadow_EditLights_CopyInfo_f(void)
5540 if (!r_editlights.integer)
5542 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
5545 if (!r_shadow_selectedlight)
5547 Con_Print("No selected light.\n");
5550 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
5551 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
5552 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
5553 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
5554 if (r_shadow_selectedlight->cubemapname)
5555 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
5557 r_shadow_bufferlight.cubemapname[0] = 0;
5558 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
5559 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
5560 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
5561 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
5562 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
5563 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
5564 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
5567 void R_Shadow_EditLights_PasteInfo_f(void)
5569 if (!r_editlights.integer)
5571 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
5574 if (!r_shadow_selectedlight)
5576 Con_Print("No selected light.\n");
5579 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);
5582 void R_Shadow_EditLights_Init(void)
5584 Cvar_RegisterVariable(&r_editlights);
5585 Cvar_RegisterVariable(&r_editlights_cursordistance);
5586 Cvar_RegisterVariable(&r_editlights_cursorpushback);
5587 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
5588 Cvar_RegisterVariable(&r_editlights_cursorgrid);
5589 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
5590 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
5591 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
5592 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)");
5593 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
5594 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
5595 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
5596 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)");
5597 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
5598 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
5599 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
5600 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
5601 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
5602 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
5603 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)");
5609 =============================================================================
5613 =============================================================================
5616 void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, int dynamic)
5618 VectorClear(diffusecolor);
5619 VectorClear(diffusenormal);
5621 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
5623 ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_refdef.scene.ambient * (2.0f / 128.0f);
5624 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
5627 VectorSet(ambientcolor, 1, 1, 1);
5634 for (i = 0;i < r_refdef.scene.numlights;i++)
5636 light = r_refdef.scene.lights[i];
5637 Matrix4x4_Transform(&light->matrix_worldtolight, p, v);
5638 f = 1 - VectorLength2(v);
5639 if (f > 0 && CL_Move(p, vec3_origin, vec3_origin, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
5640 VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);