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_shadowmapmaxsize;
185 qboolean r_shadow_shadowmapvsdct;
186 qboolean r_shadow_shadowmapsampler;
187 int r_shadow_shadowmappcf;
188 int r_shadow_shadowmapborder;
189 int r_shadow_lightscissor[4];
191 int maxshadowtriangles;
194 int maxshadowvertices;
195 float *shadowvertex3f;
208 int r_shadow_buffer_numleafpvsbytes;
209 unsigned char *r_shadow_buffer_visitingleafpvs;
210 unsigned char *r_shadow_buffer_leafpvs;
211 int *r_shadow_buffer_leaflist;
213 int r_shadow_buffer_numsurfacepvsbytes;
214 unsigned char *r_shadow_buffer_surfacepvs;
215 int *r_shadow_buffer_surfacelist;
217 int r_shadow_buffer_numshadowtrispvsbytes;
218 unsigned char *r_shadow_buffer_shadowtrispvs;
219 int r_shadow_buffer_numlighttrispvsbytes;
220 unsigned char *r_shadow_buffer_lighttrispvs;
222 rtexturepool_t *r_shadow_texturepool;
223 rtexture_t *r_shadow_attenuationgradienttexture;
224 rtexture_t *r_shadow_attenuation2dtexture;
225 rtexture_t *r_shadow_attenuation3dtexture;
226 rtexture_t *r_shadow_lightcorona;
227 rtexture_t *r_shadow_shadowmaprectangletexture;
228 rtexture_t *r_shadow_shadowmap2dtexture;
229 rtexture_t *r_shadow_shadowmapcubetexture[R_SHADOW_SHADOWMAP_NUMCUBEMAPS];
230 rtexture_t *r_shadow_shadowmapvsdcttexture;
231 int r_shadow_shadowmapsize; // changes for each light based on distance
232 int r_shadow_shadowmaplod; // changes for each light based on distance
234 // lights are reloaded when this changes
235 char r_shadow_mapname[MAX_QPATH];
237 // used only for light filters (cubemaps)
238 rtexturepool_t *r_shadow_filters_texturepool;
240 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"};
241 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"};
242 cvar_t r_shadow_debuglight = {0, "r_shadow_debuglight", "-1", "renders only one light, for level design purposes or debugging"};
243 cvar_t r_shadow_usenormalmap = {CVAR_SAVE, "r_shadow_usenormalmap", "1", "enables use of directional shading on lights"};
244 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)"};
245 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"};
246 cvar_t r_shadow_glossintensity = {0, "r_shadow_glossintensity", "1", "how bright textured glossmaps should look if r_shadow_gloss is 1 or 2"};
247 cvar_t r_shadow_glossexponent = {0, "r_shadow_glossexponent", "32", "how 'sharp' the gloss should appear (specular power)"};
248 cvar_t r_shadow_glossexact = {0, "r_shadow_glossexact", "0", "use exact reflection math for gloss (slightly slower, but should look a tad better)"};
249 cvar_t r_shadow_lightattenuationdividebias = {0, "r_shadow_lightattenuationdividebias", "1", "changes attenuation texture generation"};
250 cvar_t r_shadow_lightattenuationlinearscale = {0, "r_shadow_lightattenuationlinearscale", "2", "changes attenuation texture generation"};
251 cvar_t r_shadow_lightintensityscale = {0, "r_shadow_lightintensityscale", "1", "renders all world lights brighter or darker"};
252 cvar_t r_shadow_lightradiusscale = {0, "r_shadow_lightradiusscale", "1", "renders all world lights larger or smaller"};
253 cvar_t r_shadow_portallight = {0, "r_shadow_portallight", "1", "use portal culling to exactly determine lit triangles when compiling world lights"};
254 cvar_t r_shadow_projectdistance = {0, "r_shadow_projectdistance", "1000000", "how far to cast shadows"};
255 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)"};
256 cvar_t r_shadow_realtime_dlight = {CVAR_SAVE, "r_shadow_realtime_dlight", "1", "enables rendering of dynamic lights such as explosions and rocket light"};
257 cvar_t r_shadow_realtime_dlight_shadows = {CVAR_SAVE, "r_shadow_realtime_dlight_shadows", "1", "enables rendering of shadows from dynamic lights"};
258 cvar_t r_shadow_realtime_dlight_svbspculling = {0, "r_shadow_realtime_dlight_svbspculling", "0", "enables svbsp optimization on dynamic lights (very slow!)"};
259 cvar_t r_shadow_realtime_dlight_portalculling = {0, "r_shadow_realtime_dlight_portalculling", "0", "enables portal optimization on dynamic lights (slow!)"};
260 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)"};
261 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"};
262 cvar_t r_shadow_realtime_world_shadows = {CVAR_SAVE, "r_shadow_realtime_world_shadows", "1", "enables rendering of shadows from world lights"};
263 cvar_t r_shadow_realtime_world_compile = {0, "r_shadow_realtime_world_compile", "1", "enables compilation of world lights for higher performance rendering"};
264 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"};
265 cvar_t r_shadow_realtime_world_compilesvbsp = {0, "r_shadow_realtime_world_compilesvbsp", "1", "enables svbsp optimization during compilation"};
266 cvar_t r_shadow_realtime_world_compileportalculling = {0, "r_shadow_realtime_world_compileportalculling", "1", "enables portal-based culling optimization during compilation"};
267 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)"};
268 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"};
269 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"};
270 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)"};
271 cvar_t r_shadow_shadowmapping_vsdct = {CVAR_SAVE, "r_shadow_shadowmapping_vsdct", "1", "enables use of virtual shadow depth cube texture"};
272 cvar_t r_shadow_shadowmapping_minsize = {CVAR_SAVE, "r_shadow_shadowmapping_minsize", "32", "shadowmap size limit"};
273 cvar_t r_shadow_shadowmapping_maxsize = {CVAR_SAVE, "r_shadow_shadowmapping_maxsize", "512", "shadowmap size limit"};
274 cvar_t r_shadow_shadowmapping_lod_bias = {CVAR_SAVE, "r_shadow_shadowmapping_lod_bias", "16", "shadowmap size bias"};
275 cvar_t r_shadow_shadowmapping_lod_scale = {CVAR_SAVE, "r_shadow_shadowmapping_lod_scale", "128", "shadowmap size scaling parameter"};
276 cvar_t r_shadow_shadowmapping_bordersize = {CVAR_SAVE, "r_shadow_shadowmapping_bordersize", "4", "shadowmap size bias for filtering"};
277 cvar_t r_shadow_shadowmapping_nearclip = {CVAR_SAVE, "r_shadow_shadowmapping_nearclip", "1", "shadowmap nearclip in world units"};
278 cvar_t r_shadow_shadowmapping_bias = {CVAR_SAVE, "r_shadow_shadowmapping_bias", "0.03", "shadowmap bias parameter (this is multiplied by nearclip * 1024 / lodsize)"};
279 cvar_t r_shadow_culltriangles = {0, "r_shadow_culltriangles", "1", "performs more expensive tests to remove unnecessary triangles of lit surfaces"};
280 cvar_t r_shadow_polygonfactor = {0, "r_shadow_polygonfactor", "0", "how much to enlarge shadow volume polygons when rendering (should be 0!)"};
281 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)"};
282 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)"};
283 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "1", "brightness of corona flare effects around certain lights, 0 disables corona effects"};
284 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"};
285 cvar_t r_coronas_occlusionquery = {CVAR_SAVE, "r_coronas_occlusionquery", "1", "use GL_ARB_occlusion_query extension if supported (fades coronas according to visibility)"};
286 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "0", "render bright coronas for dynamic lights instead of actual lighting, fast but ugly"};
287 cvar_t gl_ext_separatestencil = {0, "gl_ext_separatestencil", "1", "make use of OpenGL 2.0 glStencilOpSeparate or GL_ATI_separate_stencil extension"};
288 cvar_t gl_ext_stenciltwoside = {0, "gl_ext_stenciltwoside", "1", "make use of GL_EXT_stenciltwoside extension (NVIDIA only)"};
289 cvar_t r_editlights = {0, "r_editlights", "0", "enables .rtlights file editing mode"};
290 cvar_t r_editlights_cursordistance = {0, "r_editlights_cursordistance", "1024", "maximum distance of cursor from eye"};
291 cvar_t r_editlights_cursorpushback = {0, "r_editlights_cursorpushback", "0", "how far to pull the cursor back toward the eye"};
292 cvar_t r_editlights_cursorpushoff = {0, "r_editlights_cursorpushoff", "4", "how far to push the cursor off the impacted surface"};
293 cvar_t r_editlights_cursorgrid = {0, "r_editlights_cursorgrid", "4", "snaps cursor to this grid size"};
294 cvar_t r_editlights_quakelightsizescale = {CVAR_SAVE, "r_editlights_quakelightsizescale", "1", "changes size of light entities loaded from a map"};
296 // note the table actually includes one more value, just to avoid the need to clamp the distance index due to minor math error
297 #define ATTENTABLESIZE 256
298 // 1D gradient, 2D circle and 3D sphere attenuation textures
299 #define ATTEN1DSIZE 32
300 #define ATTEN2DSIZE 64
301 #define ATTEN3DSIZE 32
303 static float r_shadow_attendividebias; // r_shadow_lightattenuationdividebias
304 static float r_shadow_attenlinearscale; // r_shadow_lightattenuationlinearscale
305 static float r_shadow_attentable[ATTENTABLESIZE+1];
307 rtlight_t *r_shadow_compilingrtlight;
308 static memexpandablearray_t r_shadow_worldlightsarray;
309 dlight_t *r_shadow_selectedlight;
310 dlight_t r_shadow_bufferlight;
311 vec3_t r_editlights_cursorlocation;
313 extern int con_vislines;
315 typedef struct cubemapinfo_s
322 #define MAX_CUBEMAPS 256
323 static int numcubemaps;
324 static cubemapinfo_t cubemaps[MAX_CUBEMAPS];
326 void R_Shadow_UncompileWorldLights(void);
327 void R_Shadow_ClearWorldLights(void);
328 void R_Shadow_SaveWorldLights(void);
329 void R_Shadow_LoadWorldLights(void);
330 void R_Shadow_LoadLightsFile(void);
331 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void);
332 void R_Shadow_EditLights_Reload_f(void);
333 void R_Shadow_ValidateCvars(void);
334 static void R_Shadow_MakeTextures(void);
336 // VorteX: custom editor light sprites
337 #define EDLIGHTSPRSIZE 8
338 cachepic_t *r_editlights_sprcursor;
339 cachepic_t *r_editlights_sprlight;
340 cachepic_t *r_editlights_sprnoshadowlight;
341 cachepic_t *r_editlights_sprcubemaplight;
342 cachepic_t *r_editlights_sprcubemapnoshadowlight;
343 cachepic_t *r_editlights_sprselection;
345 void R_Shadow_SetShadowMode(void)
347 r_shadow_shadowmapmaxsize = bound(1, r_shadow_shadowmapping_maxsize.integer, 2048);
348 r_shadow_shadowmapvsdct = r_shadow_shadowmapping_vsdct.integer != 0;
349 r_shadow_shadowmapfilterquality = r_shadow_shadowmapping_filterquality.integer;
350 r_shadow_shadowmaptexturetype = r_shadow_shadowmapping_texturetype.integer;
351 r_shadow_shadowmapborder = bound(0, r_shadow_shadowmapping_bordersize.integer, 16);
352 r_shadow_shadowmaplod = -1;
353 r_shadow_shadowmapsampler = false;
354 r_shadow_shadowmappcf = 0;
355 r_shadow_shadowmode = 0;
356 if(r_shadow_shadowmapping.integer)
358 if(r_shadow_shadowmapfilterquality < 0)
360 if(strstr(gl_vendor, "NVIDIA"))
362 r_shadow_shadowmapsampler = gl_support_arb_shadow;
363 r_shadow_shadowmappcf = 1;
365 else if(gl_support_amd_texture_texture4 || gl_support_arb_texture_gather)
366 r_shadow_shadowmappcf = 1;
367 else if(strstr(gl_vendor, "ATI"))
368 r_shadow_shadowmappcf = 1;
370 r_shadow_shadowmapsampler = gl_support_arb_shadow;
374 switch (r_shadow_shadowmapfilterquality)
377 r_shadow_shadowmapsampler = gl_support_arb_shadow;
380 r_shadow_shadowmapsampler = gl_support_arb_shadow;
381 r_shadow_shadowmappcf = 1;
384 r_shadow_shadowmappcf = 1;
387 r_shadow_shadowmappcf = 2;
391 r_shadow_shadowmode = r_shadow_shadowmaptexturetype;
392 if(r_shadow_shadowmode <= 0)
394 if((gl_support_amd_texture_texture4 || gl_support_arb_texture_gather) && r_shadow_shadowmappcf && !r_shadow_shadowmapsampler)
395 r_shadow_shadowmode = 1;
396 else if(gl_texturerectangle)
397 r_shadow_shadowmode = 2;
399 r_shadow_shadowmode = 1;
404 void R_Shadow_FreeShadowMaps(void)
408 R_Shadow_SetShadowMode();
410 if (r_shadow_fborectangle)
411 qglDeleteFramebuffersEXT(1, &r_shadow_fborectangle);
412 r_shadow_fborectangle = 0;
416 qglDeleteFramebuffersEXT(1, &r_shadow_fbo2d);
419 for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
420 if (r_shadow_fbocubeside[i][0])
421 qglDeleteFramebuffersEXT(6, r_shadow_fbocubeside[i]);
422 memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
425 if (r_shadow_shadowmaprectangletexture)
426 R_FreeTexture(r_shadow_shadowmaprectangletexture);
427 r_shadow_shadowmaprectangletexture = NULL;
429 if (r_shadow_shadowmap2dtexture)
430 R_FreeTexture(r_shadow_shadowmap2dtexture);
431 r_shadow_shadowmap2dtexture = NULL;
433 for (i = 0;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
434 if (r_shadow_shadowmapcubetexture[i])
435 R_FreeTexture(r_shadow_shadowmapcubetexture[i]);
436 memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
438 if (r_shadow_shadowmapvsdcttexture)
439 R_FreeTexture(r_shadow_shadowmapvsdcttexture);
440 r_shadow_shadowmapvsdcttexture = NULL;
445 void r_shadow_start(void)
447 // allocate vertex processing arrays
449 r_shadow_attenuationgradienttexture = NULL;
450 r_shadow_attenuation2dtexture = NULL;
451 r_shadow_attenuation3dtexture = NULL;
452 r_shadow_shadowmode = 0;
453 r_shadow_shadowmaprectangletexture = NULL;
454 r_shadow_shadowmap2dtexture = NULL;
455 memset(r_shadow_shadowmapcubetexture, 0, sizeof(r_shadow_shadowmapcubetexture));
456 r_shadow_shadowmapvsdcttexture = NULL;
457 r_shadow_shadowmapmaxsize = 0;
458 r_shadow_shadowmapsize = 0;
459 r_shadow_shadowmaplod = 0;
460 r_shadow_shadowmapfilterquality = 0;
461 r_shadow_shadowmaptexturetype = 0;
462 r_shadow_shadowmapvsdct = false;
463 r_shadow_shadowmapsampler = false;
464 r_shadow_shadowmappcf = 0;
465 r_shadow_fborectangle = 0;
467 memset(r_shadow_fbocubeside, 0, sizeof(r_shadow_fbocubeside));
469 R_Shadow_FreeShadowMaps();
471 r_shadow_texturepool = NULL;
472 r_shadow_filters_texturepool = NULL;
473 R_Shadow_ValidateCvars();
474 R_Shadow_MakeTextures();
475 maxshadowtriangles = 0;
476 shadowelements = NULL;
477 maxshadowvertices = 0;
478 shadowvertex3f = NULL;
486 shadowmarklist = NULL;
488 r_shadow_buffer_numleafpvsbytes = 0;
489 r_shadow_buffer_visitingleafpvs = NULL;
490 r_shadow_buffer_leafpvs = NULL;
491 r_shadow_buffer_leaflist = NULL;
492 r_shadow_buffer_numsurfacepvsbytes = 0;
493 r_shadow_buffer_surfacepvs = NULL;
494 r_shadow_buffer_surfacelist = NULL;
495 r_shadow_buffer_numshadowtrispvsbytes = 0;
496 r_shadow_buffer_shadowtrispvs = NULL;
497 r_shadow_buffer_numlighttrispvsbytes = 0;
498 r_shadow_buffer_lighttrispvs = NULL;
501 void r_shadow_shutdown(void)
504 R_Shadow_UncompileWorldLights();
506 R_Shadow_FreeShadowMaps();
510 r_shadow_attenuationgradienttexture = NULL;
511 r_shadow_attenuation2dtexture = NULL;
512 r_shadow_attenuation3dtexture = NULL;
513 R_FreeTexturePool(&r_shadow_texturepool);
514 R_FreeTexturePool(&r_shadow_filters_texturepool);
515 maxshadowtriangles = 0;
517 Mem_Free(shadowelements);
518 shadowelements = NULL;
520 Mem_Free(shadowvertex3f);
521 shadowvertex3f = NULL;
524 Mem_Free(vertexupdate);
527 Mem_Free(vertexremap);
533 Mem_Free(shadowmark);
536 Mem_Free(shadowmarklist);
537 shadowmarklist = NULL;
539 r_shadow_buffer_numleafpvsbytes = 0;
540 if (r_shadow_buffer_visitingleafpvs)
541 Mem_Free(r_shadow_buffer_visitingleafpvs);
542 r_shadow_buffer_visitingleafpvs = NULL;
543 if (r_shadow_buffer_leafpvs)
544 Mem_Free(r_shadow_buffer_leafpvs);
545 r_shadow_buffer_leafpvs = NULL;
546 if (r_shadow_buffer_leaflist)
547 Mem_Free(r_shadow_buffer_leaflist);
548 r_shadow_buffer_leaflist = NULL;
549 r_shadow_buffer_numsurfacepvsbytes = 0;
550 if (r_shadow_buffer_surfacepvs)
551 Mem_Free(r_shadow_buffer_surfacepvs);
552 r_shadow_buffer_surfacepvs = NULL;
553 if (r_shadow_buffer_surfacelist)
554 Mem_Free(r_shadow_buffer_surfacelist);
555 r_shadow_buffer_surfacelist = NULL;
556 r_shadow_buffer_numshadowtrispvsbytes = 0;
557 if (r_shadow_buffer_shadowtrispvs)
558 Mem_Free(r_shadow_buffer_shadowtrispvs);
559 r_shadow_buffer_numlighttrispvsbytes = 0;
560 if (r_shadow_buffer_lighttrispvs)
561 Mem_Free(r_shadow_buffer_lighttrispvs);
564 void r_shadow_newmap(void)
566 if (cl.worldmodel && strncmp(cl.worldmodel->name, r_shadow_mapname, sizeof(r_shadow_mapname)))
567 R_Shadow_EditLights_Reload_f();
570 void R_Shadow_Help_f(void)
573 "Documentation on r_shadow system:\n"
575 "r_shadow_bumpscale_basetexture : base texture as bumpmap with this scale\n"
576 "r_shadow_bumpscale_bumpmap : depth scale for bumpmap conversion\n"
577 "r_shadow_debuglight : render only this light number (-1 = all)\n"
578 "r_shadow_gloss 0/1/2 : no gloss, gloss textures only, force gloss\n"
579 "r_shadow_gloss2intensity : brightness of forced gloss\n"
580 "r_shadow_glossintensity : brightness of textured gloss\n"
581 "r_shadow_lightattenuationlinearscale : used to generate attenuation texture\n"
582 "r_shadow_lightattenuationdividebias : used to generate attenuation texture\n"
583 "r_shadow_lightintensityscale : scale rendering brightness of all lights\n"
584 "r_shadow_lightradiusscale : scale rendering radius of all lights\n"
585 "r_shadow_portallight : use portal visibility for static light precomputation\n"
586 "r_shadow_projectdistance : shadow volume projection distance\n"
587 "r_shadow_realtime_dlight : use high quality dynamic lights in normal mode\n"
588 "r_shadow_realtime_dlight_shadows : cast shadows from dlights\n"
589 "r_shadow_realtime_world : use high quality world lighting mode\n"
590 "r_shadow_realtime_world_lightmaps : use lightmaps in addition to lights\n"
591 "r_shadow_realtime_world_shadows : cast shadows from world lights\n"
592 "r_shadow_realtime_world_compile : compile surface/visibility information\n"
593 "r_shadow_realtime_world_compileshadow : compile shadow geometry\n"
594 "r_shadow_scissor : use scissor optimization\n"
595 "r_shadow_polygonfactor : nudge shadow volumes closer/further\n"
596 "r_shadow_polygonoffset : nudge shadow volumes closer/further\n"
597 "r_shadow_texture3d : use 3d attenuation texture (if hardware supports)\n"
598 "r_showlighting : useful for performance testing; bright = slow!\n"
599 "r_showshadowvolumes : useful for performance testing; bright = slow!\n"
601 "r_shadow_help : this help\n"
605 void R_Shadow_Init(void)
607 Cvar_RegisterVariable(&r_shadow_bumpscale_basetexture);
608 Cvar_RegisterVariable(&r_shadow_bumpscale_bumpmap);
609 Cvar_RegisterVariable(&r_shadow_usenormalmap);
610 Cvar_RegisterVariable(&r_shadow_debuglight);
611 Cvar_RegisterVariable(&r_shadow_gloss);
612 Cvar_RegisterVariable(&r_shadow_gloss2intensity);
613 Cvar_RegisterVariable(&r_shadow_glossintensity);
614 Cvar_RegisterVariable(&r_shadow_glossexponent);
615 Cvar_RegisterVariable(&r_shadow_glossexact);
616 Cvar_RegisterVariable(&r_shadow_lightattenuationdividebias);
617 Cvar_RegisterVariable(&r_shadow_lightattenuationlinearscale);
618 Cvar_RegisterVariable(&r_shadow_lightintensityscale);
619 Cvar_RegisterVariable(&r_shadow_lightradiusscale);
620 Cvar_RegisterVariable(&r_shadow_portallight);
621 Cvar_RegisterVariable(&r_shadow_projectdistance);
622 Cvar_RegisterVariable(&r_shadow_frontsidecasting);
623 Cvar_RegisterVariable(&r_shadow_realtime_dlight);
624 Cvar_RegisterVariable(&r_shadow_realtime_dlight_shadows);
625 Cvar_RegisterVariable(&r_shadow_realtime_dlight_svbspculling);
626 Cvar_RegisterVariable(&r_shadow_realtime_dlight_portalculling);
627 Cvar_RegisterVariable(&r_shadow_realtime_world);
628 Cvar_RegisterVariable(&r_shadow_realtime_world_lightmaps);
629 Cvar_RegisterVariable(&r_shadow_realtime_world_shadows);
630 Cvar_RegisterVariable(&r_shadow_realtime_world_compile);
631 Cvar_RegisterVariable(&r_shadow_realtime_world_compileshadow);
632 Cvar_RegisterVariable(&r_shadow_realtime_world_compilesvbsp);
633 Cvar_RegisterVariable(&r_shadow_realtime_world_compileportalculling);
634 Cvar_RegisterVariable(&r_shadow_scissor);
635 Cvar_RegisterVariable(&r_shadow_shadowmapping);
636 Cvar_RegisterVariable(&r_shadow_shadowmapping_vsdct);
637 Cvar_RegisterVariable(&r_shadow_shadowmapping_texturetype);
638 Cvar_RegisterVariable(&r_shadow_shadowmapping_filterquality);
639 Cvar_RegisterVariable(&r_shadow_shadowmapping_maxsize);
640 Cvar_RegisterVariable(&r_shadow_shadowmapping_minsize);
641 Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_bias);
642 Cvar_RegisterVariable(&r_shadow_shadowmapping_lod_scale);
643 Cvar_RegisterVariable(&r_shadow_shadowmapping_bordersize);
644 Cvar_RegisterVariable(&r_shadow_shadowmapping_nearclip);
645 Cvar_RegisterVariable(&r_shadow_shadowmapping_bias);
646 Cvar_RegisterVariable(&r_shadow_culltriangles);
647 Cvar_RegisterVariable(&r_shadow_polygonfactor);
648 Cvar_RegisterVariable(&r_shadow_polygonoffset);
649 Cvar_RegisterVariable(&r_shadow_texture3d);
650 Cvar_RegisterVariable(&r_coronas);
651 Cvar_RegisterVariable(&r_coronas_occlusionsizescale);
652 Cvar_RegisterVariable(&r_coronas_occlusionquery);
653 Cvar_RegisterVariable(&gl_flashblend);
654 Cvar_RegisterVariable(&gl_ext_separatestencil);
655 Cvar_RegisterVariable(&gl_ext_stenciltwoside);
656 if (gamemode == GAME_TENEBRAE)
658 Cvar_SetValue("r_shadow_gloss", 2);
659 Cvar_SetValue("r_shadow_bumpscale_basetexture", 4);
661 Cmd_AddCommand("r_shadow_help", R_Shadow_Help_f, "prints documentation on console commands and variables used by realtime lighting and shadowing system");
662 R_Shadow_EditLights_Init();
663 Mem_ExpandableArray_NewArray(&r_shadow_worldlightsarray, r_main_mempool, sizeof(dlight_t), 128);
664 maxshadowtriangles = 0;
665 shadowelements = NULL;
666 maxshadowvertices = 0;
667 shadowvertex3f = NULL;
675 shadowmarklist = NULL;
677 r_shadow_buffer_numleafpvsbytes = 0;
678 r_shadow_buffer_visitingleafpvs = NULL;
679 r_shadow_buffer_leafpvs = NULL;
680 r_shadow_buffer_leaflist = NULL;
681 r_shadow_buffer_numsurfacepvsbytes = 0;
682 r_shadow_buffer_surfacepvs = NULL;
683 r_shadow_buffer_surfacelist = NULL;
684 r_shadow_buffer_shadowtrispvs = NULL;
685 r_shadow_buffer_lighttrispvs = NULL;
686 R_RegisterModule("R_Shadow", r_shadow_start, r_shadow_shutdown, r_shadow_newmap);
689 matrix4x4_t matrix_attenuationxyz =
692 {0.5, 0.0, 0.0, 0.5},
693 {0.0, 0.5, 0.0, 0.5},
694 {0.0, 0.0, 0.5, 0.5},
699 matrix4x4_t matrix_attenuationz =
702 {0.0, 0.0, 0.5, 0.5},
703 {0.0, 0.0, 0.0, 0.5},
704 {0.0, 0.0, 0.0, 0.5},
709 void R_Shadow_ResizeShadowArrays(int numvertices, int numtriangles)
711 // make sure shadowelements is big enough for this volume
712 if (maxshadowtriangles < numtriangles)
714 maxshadowtriangles = numtriangles;
716 Mem_Free(shadowelements);
717 shadowelements = (int *)Mem_Alloc(r_main_mempool, maxshadowtriangles * sizeof(int[24]));
719 // make sure shadowvertex3f is big enough for this volume
720 if (maxshadowvertices < numvertices)
722 maxshadowvertices = numvertices;
724 Mem_Free(shadowvertex3f);
725 shadowvertex3f = (float *)Mem_Alloc(r_main_mempool, maxshadowvertices * sizeof(float[6]));
729 static void R_Shadow_EnlargeLeafSurfaceTrisBuffer(int numleafs, int numsurfaces, int numshadowtriangles, int numlighttriangles)
731 int numleafpvsbytes = (((numleafs + 7) >> 3) + 255) & ~255;
732 int numsurfacepvsbytes = (((numsurfaces + 7) >> 3) + 255) & ~255;
733 int numshadowtrispvsbytes = (((numshadowtriangles + 7) >> 3) + 255) & ~255;
734 int numlighttrispvsbytes = (((numlighttriangles + 7) >> 3) + 255) & ~255;
735 if (r_shadow_buffer_numleafpvsbytes < numleafpvsbytes)
737 if (r_shadow_buffer_visitingleafpvs)
738 Mem_Free(r_shadow_buffer_visitingleafpvs);
739 if (r_shadow_buffer_leafpvs)
740 Mem_Free(r_shadow_buffer_leafpvs);
741 if (r_shadow_buffer_leaflist)
742 Mem_Free(r_shadow_buffer_leaflist);
743 r_shadow_buffer_numleafpvsbytes = numleafpvsbytes;
744 r_shadow_buffer_visitingleafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
745 r_shadow_buffer_leafpvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes);
746 r_shadow_buffer_leaflist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numleafpvsbytes * 8 * sizeof(*r_shadow_buffer_leaflist));
748 if (r_shadow_buffer_numsurfacepvsbytes < numsurfacepvsbytes)
750 if (r_shadow_buffer_surfacepvs)
751 Mem_Free(r_shadow_buffer_surfacepvs);
752 if (r_shadow_buffer_surfacelist)
753 Mem_Free(r_shadow_buffer_surfacelist);
754 r_shadow_buffer_numsurfacepvsbytes = numsurfacepvsbytes;
755 r_shadow_buffer_surfacepvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes);
756 r_shadow_buffer_surfacelist = (int *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numsurfacepvsbytes * 8 * sizeof(*r_shadow_buffer_surfacelist));
758 if (r_shadow_buffer_numshadowtrispvsbytes < numshadowtrispvsbytes)
760 if (r_shadow_buffer_shadowtrispvs)
761 Mem_Free(r_shadow_buffer_shadowtrispvs);
762 r_shadow_buffer_numshadowtrispvsbytes = numshadowtrispvsbytes;
763 r_shadow_buffer_shadowtrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numshadowtrispvsbytes);
765 if (r_shadow_buffer_numlighttrispvsbytes < numlighttrispvsbytes)
767 if (r_shadow_buffer_lighttrispvs)
768 Mem_Free(r_shadow_buffer_lighttrispvs);
769 r_shadow_buffer_numlighttrispvsbytes = numlighttrispvsbytes;
770 r_shadow_buffer_lighttrispvs = (unsigned char *)Mem_Alloc(r_main_mempool, r_shadow_buffer_numlighttrispvsbytes);
774 void R_Shadow_PrepareShadowMark(int numtris)
776 // make sure shadowmark is big enough for this volume
777 if (maxshadowmark < numtris)
779 maxshadowmark = numtris;
781 Mem_Free(shadowmark);
783 Mem_Free(shadowmarklist);
784 shadowmark = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmark));
785 shadowmarklist = (int *)Mem_Alloc(r_main_mempool, maxshadowmark * sizeof(*shadowmarklist));
789 // if shadowmarkcount wrapped we clear the array and adjust accordingly
790 if (shadowmarkcount == 0)
793 memset(shadowmark, 0, maxshadowmark * sizeof(*shadowmark));
798 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)
801 int outtriangles = 0, outvertices = 0;
804 float ratio, direction[3], projectvector[3];
806 if (projectdirection)
807 VectorScale(projectdirection, projectdistance, projectvector);
809 VectorClear(projectvector);
811 // create the vertices
812 if (projectdirection)
814 for (i = 0;i < numshadowmarktris;i++)
816 element = inelement3i + shadowmarktris[i] * 3;
817 for (j = 0;j < 3;j++)
819 if (vertexupdate[element[j]] != vertexupdatenum)
821 vertexupdate[element[j]] = vertexupdatenum;
822 vertexremap[element[j]] = outvertices;
823 vertex = invertex3f + element[j] * 3;
824 // project one copy of the vertex according to projectvector
825 VectorCopy(vertex, outvertex3f);
826 VectorAdd(vertex, projectvector, (outvertex3f + 3));
835 for (i = 0;i < numshadowmarktris;i++)
837 element = inelement3i + shadowmarktris[i] * 3;
838 for (j = 0;j < 3;j++)
840 if (vertexupdate[element[j]] != vertexupdatenum)
842 vertexupdate[element[j]] = vertexupdatenum;
843 vertexremap[element[j]] = outvertices;
844 vertex = invertex3f + element[j] * 3;
845 // project one copy of the vertex to the sphere radius of the light
846 // (FIXME: would projecting it to the light box be better?)
847 VectorSubtract(vertex, projectorigin, direction);
848 ratio = projectdistance / VectorLength(direction);
849 VectorCopy(vertex, outvertex3f);
850 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
858 if (r_shadow_frontsidecasting.integer)
860 for (i = 0;i < numshadowmarktris;i++)
862 int remappedelement[3];
864 const int *neighbortriangle;
866 markindex = shadowmarktris[i] * 3;
867 element = inelement3i + markindex;
868 neighbortriangle = inneighbor3i + markindex;
869 // output the front and back triangles
870 outelement3i[0] = vertexremap[element[0]];
871 outelement3i[1] = vertexremap[element[1]];
872 outelement3i[2] = vertexremap[element[2]];
873 outelement3i[3] = vertexremap[element[2]] + 1;
874 outelement3i[4] = vertexremap[element[1]] + 1;
875 outelement3i[5] = vertexremap[element[0]] + 1;
879 // output the sides (facing outward from this triangle)
880 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
882 remappedelement[0] = vertexremap[element[0]];
883 remappedelement[1] = vertexremap[element[1]];
884 outelement3i[0] = remappedelement[1];
885 outelement3i[1] = remappedelement[0];
886 outelement3i[2] = remappedelement[0] + 1;
887 outelement3i[3] = remappedelement[1];
888 outelement3i[4] = remappedelement[0] + 1;
889 outelement3i[5] = remappedelement[1] + 1;
894 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
896 remappedelement[1] = vertexremap[element[1]];
897 remappedelement[2] = vertexremap[element[2]];
898 outelement3i[0] = remappedelement[2];
899 outelement3i[1] = remappedelement[1];
900 outelement3i[2] = remappedelement[1] + 1;
901 outelement3i[3] = remappedelement[2];
902 outelement3i[4] = remappedelement[1] + 1;
903 outelement3i[5] = remappedelement[2] + 1;
908 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
910 remappedelement[0] = vertexremap[element[0]];
911 remappedelement[2] = vertexremap[element[2]];
912 outelement3i[0] = remappedelement[0];
913 outelement3i[1] = remappedelement[2];
914 outelement3i[2] = remappedelement[2] + 1;
915 outelement3i[3] = remappedelement[0];
916 outelement3i[4] = remappedelement[2] + 1;
917 outelement3i[5] = remappedelement[0] + 1;
926 for (i = 0;i < numshadowmarktris;i++)
928 int remappedelement[3];
930 const int *neighbortriangle;
932 markindex = shadowmarktris[i] * 3;
933 element = inelement3i + markindex;
934 neighbortriangle = inneighbor3i + markindex;
935 // output the front and back triangles
936 outelement3i[0] = vertexremap[element[2]];
937 outelement3i[1] = vertexremap[element[1]];
938 outelement3i[2] = vertexremap[element[0]];
939 outelement3i[3] = vertexremap[element[0]] + 1;
940 outelement3i[4] = vertexremap[element[1]] + 1;
941 outelement3i[5] = vertexremap[element[2]] + 1;
945 // output the sides (facing outward from this triangle)
946 if (shadowmark[neighbortriangle[0]] != shadowmarkcount)
948 remappedelement[0] = vertexremap[element[0]];
949 remappedelement[1] = vertexremap[element[1]];
950 outelement3i[0] = remappedelement[0];
951 outelement3i[1] = remappedelement[1];
952 outelement3i[2] = remappedelement[1] + 1;
953 outelement3i[3] = remappedelement[0];
954 outelement3i[4] = remappedelement[1] + 1;
955 outelement3i[5] = remappedelement[0] + 1;
960 if (shadowmark[neighbortriangle[1]] != shadowmarkcount)
962 remappedelement[1] = vertexremap[element[1]];
963 remappedelement[2] = vertexremap[element[2]];
964 outelement3i[0] = remappedelement[1];
965 outelement3i[1] = remappedelement[2];
966 outelement3i[2] = remappedelement[2] + 1;
967 outelement3i[3] = remappedelement[1];
968 outelement3i[4] = remappedelement[2] + 1;
969 outelement3i[5] = remappedelement[1] + 1;
974 if (shadowmark[neighbortriangle[2]] != shadowmarkcount)
976 remappedelement[0] = vertexremap[element[0]];
977 remappedelement[2] = vertexremap[element[2]];
978 outelement3i[0] = remappedelement[2];
979 outelement3i[1] = remappedelement[0];
980 outelement3i[2] = remappedelement[0] + 1;
981 outelement3i[3] = remappedelement[2];
982 outelement3i[4] = remappedelement[0] + 1;
983 outelement3i[5] = remappedelement[2] + 1;
991 *outnumvertices = outvertices;
995 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)
998 int outtriangles = 0, outvertices = 0;
1000 const float *vertex;
1001 float ratio, direction[3], projectvector[3];
1004 if (projectdirection)
1005 VectorScale(projectdirection, projectdistance, projectvector);
1007 VectorClear(projectvector);
1009 for (i = 0;i < numshadowmarktris;i++)
1011 int remappedelement[3];
1013 const int *neighbortriangle;
1015 markindex = shadowmarktris[i] * 3;
1016 neighbortriangle = inneighbor3i + markindex;
1017 side[0] = shadowmark[neighbortriangle[0]] == shadowmarkcount;
1018 side[1] = shadowmark[neighbortriangle[1]] == shadowmarkcount;
1019 side[2] = shadowmark[neighbortriangle[2]] == shadowmarkcount;
1020 if (side[0] + side[1] + side[2] == 0)
1024 element = inelement3i + markindex;
1026 // create the vertices
1027 for (j = 0;j < 3;j++)
1029 if (side[j] + side[j+1] == 0)
1032 if (vertexupdate[k] != vertexupdatenum)
1034 vertexupdate[k] = vertexupdatenum;
1035 vertexremap[k] = outvertices;
1036 vertex = invertex3f + k * 3;
1037 VectorCopy(vertex, outvertex3f);
1038 if (projectdirection)
1040 // project one copy of the vertex according to projectvector
1041 VectorAdd(vertex, projectvector, (outvertex3f + 3));
1045 // project one copy of the vertex to the sphere radius of the light
1046 // (FIXME: would projecting it to the light box be better?)
1047 VectorSubtract(vertex, projectorigin, direction);
1048 ratio = projectdistance / VectorLength(direction);
1049 VectorMA(projectorigin, ratio, direction, (outvertex3f + 3));
1056 // output the sides (facing outward from this triangle)
1059 remappedelement[0] = vertexremap[element[0]];
1060 remappedelement[1] = vertexremap[element[1]];
1061 outelement3i[0] = remappedelement[1];
1062 outelement3i[1] = remappedelement[0];
1063 outelement3i[2] = remappedelement[0] + 1;
1064 outelement3i[3] = remappedelement[1];
1065 outelement3i[4] = remappedelement[0] + 1;
1066 outelement3i[5] = remappedelement[1] + 1;
1073 remappedelement[1] = vertexremap[element[1]];
1074 remappedelement[2] = vertexremap[element[2]];
1075 outelement3i[0] = remappedelement[2];
1076 outelement3i[1] = remappedelement[1];
1077 outelement3i[2] = remappedelement[1] + 1;
1078 outelement3i[3] = remappedelement[2];
1079 outelement3i[4] = remappedelement[1] + 1;
1080 outelement3i[5] = remappedelement[2] + 1;
1087 remappedelement[0] = vertexremap[element[0]];
1088 remappedelement[2] = vertexremap[element[2]];
1089 outelement3i[0] = remappedelement[0];
1090 outelement3i[1] = remappedelement[2];
1091 outelement3i[2] = remappedelement[2] + 1;
1092 outelement3i[3] = remappedelement[0];
1093 outelement3i[4] = remappedelement[2] + 1;
1094 outelement3i[5] = remappedelement[0] + 1;
1101 *outnumvertices = outvertices;
1102 return outtriangles;
1105 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)
1111 if (!BoxesOverlap(lightmins, lightmaxs, surfacemins, surfacemaxs))
1113 tend = firsttriangle + numtris;
1114 if (BoxInsideBox(surfacemins, surfacemaxs, lightmins, lightmaxs))
1116 // surface box entirely inside light box, no box cull
1117 if (projectdirection)
1119 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1121 TriangleNormal(invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3, normal);
1122 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0))
1123 shadowmarklist[numshadowmark++] = t;
1128 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1129 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, invertex3f + e[0] * 3, invertex3f + e[1] * 3, invertex3f + e[2] * 3))
1130 shadowmarklist[numshadowmark++] = t;
1135 // surface box not entirely inside light box, cull each triangle
1136 if (projectdirection)
1138 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1140 v[0] = invertex3f + e[0] * 3;
1141 v[1] = invertex3f + e[1] * 3;
1142 v[2] = invertex3f + e[2] * 3;
1143 TriangleNormal(v[0], v[1], v[2], normal);
1144 if (r_shadow_frontsidecasting.integer == (DotProduct(normal, projectdirection) < 0)
1145 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1146 shadowmarklist[numshadowmark++] = t;
1151 for (t = firsttriangle, e = elements + t * 3;t < tend;t++, e += 3)
1153 v[0] = invertex3f + e[0] * 3;
1154 v[1] = invertex3f + e[1] * 3;
1155 v[2] = invertex3f + e[2] * 3;
1156 if (r_shadow_frontsidecasting.integer == PointInfrontOfTriangle(projectorigin, v[0], v[1], v[2])
1157 && TriangleOverlapsBox(v[0], v[1], v[2], lightmins, lightmaxs))
1158 shadowmarklist[numshadowmark++] = t;
1164 qboolean R_Shadow_UseZPass(vec3_t mins, vec3_t maxs)
1169 if (r_shadow_compilingrtlight || !r_shadow_frontsidecasting.integer || !r_shadow_usezpassifpossible.integer)
1171 // check if the shadow volume intersects the near plane
1173 // a ray between the eye and light origin may intersect the caster,
1174 // indicating that the shadow may touch the eye location, however we must
1175 // test the near plane (a polygon), not merely the eye location, so it is
1176 // easiest to enlarge the caster bounding shape slightly for this.
1182 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)
1184 int i, tris, outverts;
1185 if (projectdistance < 0.1)
1187 Con_Printf("R_Shadow_Volume: projectdistance %f\n", projectdistance);
1190 if (!numverts || !nummarktris)
1192 // make sure shadowelements is big enough for this volume
1193 if (maxshadowtriangles < nummarktris || maxshadowvertices < numverts)
1194 R_Shadow_ResizeShadowArrays((numverts + 255) & ~255, (nummarktris + 255) & ~255);
1196 if (maxvertexupdate < numverts)
1198 maxvertexupdate = numverts;
1200 Mem_Free(vertexupdate);
1202 Mem_Free(vertexremap);
1203 vertexupdate = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1204 vertexremap = (int *)Mem_Alloc(r_main_mempool, maxvertexupdate * sizeof(int));
1205 vertexupdatenum = 0;
1208 if (vertexupdatenum == 0)
1210 vertexupdatenum = 1;
1211 memset(vertexupdate, 0, maxvertexupdate * sizeof(int));
1212 memset(vertexremap, 0, maxvertexupdate * sizeof(int));
1215 for (i = 0;i < nummarktris;i++)
1216 shadowmark[marktris[i]] = shadowmarkcount;
1218 if (r_shadow_compilingrtlight)
1220 // if we're compiling an rtlight, capture the mesh
1221 //tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1222 //Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zpass, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1223 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1224 Mod_ShadowMesh_AddMesh(r_main_mempool, r_shadow_compilingrtlight->static_meshchain_shadow_zfail, NULL, NULL, NULL, shadowvertex3f, NULL, NULL, NULL, NULL, tris, shadowelements);
1228 // decide which type of shadow to generate and set stencil mode
1229 R_Shadow_RenderMode_StencilShadowVolumes(R_Shadow_UseZPass(trismins, trismaxs));
1230 // generate the sides or a solid volume, depending on type
1231 if (r_shadow_rendermode >= R_SHADOW_RENDERMODE_ZPASS_STENCIL && r_shadow_rendermode <= R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE)
1232 tris = R_Shadow_ConstructShadowVolume_ZPass(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1234 tris = R_Shadow_ConstructShadowVolume_ZFail(numverts, numtris, elements, neighbors, invertex3f, &outverts, shadowelements, shadowvertex3f, projectorigin, projectdirection, projectdistance, nummarktris, marktris);
1235 r_refdef.stats.lights_dynamicshadowtriangles += tris;
1236 r_refdef.stats.lights_shadowtriangles += tris;
1238 R_Mesh_VertexPointer(shadowvertex3f, 0, 0);
1239 GL_LockArrays(0, outverts);
1240 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
1242 // increment stencil if frontface is infront of depthbuffer
1243 GL_CullFace(r_refdef.view.cullface_front);
1244 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1245 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1246 // decrement stencil if backface is infront of depthbuffer
1247 GL_CullFace(r_refdef.view.cullface_back);
1248 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1250 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
1252 // decrement stencil if backface is behind depthbuffer
1253 GL_CullFace(r_refdef.view.cullface_front);
1254 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1255 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1256 // increment stencil if frontface is behind depthbuffer
1257 GL_CullFace(r_refdef.view.cullface_back);
1258 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1260 R_Mesh_Draw(0, outverts, 0, tris, shadowelements, NULL, 0, 0);
1261 GL_LockArrays(0, 0);
1266 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)
1268 int i, tris = nummarktris;
1271 if (!numverts || !nummarktris)
1273 // make sure shadowelements is big enough for this mesh
1274 if (maxshadowtriangles < nummarktris || maxshadowvertices < numverts)
1275 R_Shadow_ResizeShadowArrays((numverts + 255) & ~255, (nummarktris + 255) & ~255);
1277 // gather up the (sparse) triangles into one array
1278 outelement3i = shadowelements;
1279 for (i = 0;i < nummarktris;i++)
1281 element = elements + marktris[i] * 3;
1282 outelement3i[0] = element[0];
1283 outelement3i[1] = element[1];
1284 outelement3i[2] = element[2];
1288 r_refdef.stats.lights_dynamicshadowtriangles += tris;
1289 r_refdef.stats.lights_shadowtriangles += tris;
1290 R_Mesh_VertexPointer(vertex3f, vertex3f_bufferobject, vertex3f_bufferoffset);
1291 R_Mesh_Draw(0, numverts, 0, tris, shadowelements, NULL, 0, 0);
1294 static void R_Shadow_MakeTextures_MakeCorona(void)
1298 unsigned char pixels[32][32][4];
1299 for (y = 0;y < 32;y++)
1301 dy = (y - 15.5f) * (1.0f / 16.0f);
1302 for (x = 0;x < 32;x++)
1304 dx = (x - 15.5f) * (1.0f / 16.0f);
1305 a = (int)(((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2)));
1306 a = bound(0, a, 255);
1307 pixels[y][x][0] = a;
1308 pixels[y][x][1] = a;
1309 pixels[y][x][2] = a;
1310 pixels[y][x][3] = 255;
1313 r_shadow_lightcorona = R_LoadTexture2D(r_shadow_texturepool, "lightcorona", 32, 32, &pixels[0][0][0], TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_FORCELINEAR, NULL);
1316 static unsigned int R_Shadow_MakeTextures_SamplePoint(float x, float y, float z)
1318 float dist = sqrt(x*x+y*y+z*z);
1319 float intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1320 // note this code could suffer byte order issues except that it is multiplying by an integer that reads the same both ways
1321 return (unsigned char)bound(0, intensity * 256.0f, 255) * 0x01010101;
1324 static void R_Shadow_MakeTextures(void)
1327 float intensity, dist;
1329 R_FreeTexturePool(&r_shadow_texturepool);
1330 r_shadow_texturepool = R_AllocTexturePool();
1331 r_shadow_attenlinearscale = r_shadow_lightattenuationlinearscale.value;
1332 r_shadow_attendividebias = r_shadow_lightattenuationdividebias.value;
1333 data = (unsigned int *)Mem_Alloc(tempmempool, max(max(ATTEN3DSIZE*ATTEN3DSIZE*ATTEN3DSIZE, ATTEN2DSIZE*ATTEN2DSIZE), ATTEN1DSIZE) * 4);
1334 // the table includes one additional value to avoid the need to clamp indexing due to minor math errors
1335 for (x = 0;x <= ATTENTABLESIZE;x++)
1337 dist = (x + 0.5f) * (1.0f / ATTENTABLESIZE) * (1.0f / 0.9375);
1338 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
1339 r_shadow_attentable[x] = bound(0, intensity, 1);
1341 // 1D gradient texture
1342 for (x = 0;x < ATTEN1DSIZE;x++)
1343 data[x] = R_Shadow_MakeTextures_SamplePoint((x + 0.5f) * (1.0f / ATTEN1DSIZE) * (1.0f / 0.9375), 0, 0);
1344 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);
1345 // 2D circle texture
1346 for (y = 0;y < ATTEN2DSIZE;y++)
1347 for (x = 0;x < ATTEN2DSIZE;x++)
1348 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);
1349 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);
1350 // 3D sphere texture
1351 if (r_shadow_texture3d.integer && gl_texture3d)
1353 for (z = 0;z < ATTEN3DSIZE;z++)
1354 for (y = 0;y < ATTEN3DSIZE;y++)
1355 for (x = 0;x < ATTEN3DSIZE;x++)
1356 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));
1357 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);
1360 r_shadow_attenuation3dtexture = NULL;
1363 R_Shadow_MakeTextures_MakeCorona();
1365 // Editor light sprites
1366 r_editlights_sprcursor = Draw_CachePic ("gfx/editlights/cursor");
1367 r_editlights_sprlight = Draw_CachePic ("gfx/editlights/light");
1368 r_editlights_sprnoshadowlight = Draw_CachePic ("gfx/editlights/noshadow");
1369 r_editlights_sprcubemaplight = Draw_CachePic ("gfx/editlights/cubemaplight");
1370 r_editlights_sprcubemapnoshadowlight = Draw_CachePic ("gfx/editlights/cubemapnoshadowlight");
1371 r_editlights_sprselection = Draw_CachePic ("gfx/editlights/selection");
1374 void R_Shadow_ValidateCvars(void)
1376 if (r_shadow_texture3d.integer && !gl_texture3d)
1377 Cvar_SetValueQuick(&r_shadow_texture3d, 0);
1378 if (gl_ext_separatestencil.integer && !gl_support_separatestencil)
1379 Cvar_SetValueQuick(&gl_ext_separatestencil, 0);
1380 if (gl_ext_stenciltwoside.integer && !gl_support_stenciltwoside)
1381 Cvar_SetValueQuick(&gl_ext_stenciltwoside, 0);
1384 void R_Shadow_RenderMode_Begin(void)
1388 R_Shadow_ValidateCvars();
1390 if (!r_shadow_attenuation2dtexture
1391 || (!r_shadow_attenuation3dtexture && r_shadow_texture3d.integer)
1392 || r_shadow_lightattenuationdividebias.value != r_shadow_attendividebias
1393 || r_shadow_lightattenuationlinearscale.value != r_shadow_attenlinearscale)
1394 R_Shadow_MakeTextures();
1397 R_Mesh_ColorPointer(NULL, 0, 0);
1398 R_Mesh_ResetTextureState();
1399 GL_BlendFunc(GL_ONE, GL_ZERO);
1400 GL_DepthRange(0, 1);
1401 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
1403 GL_DepthMask(false);
1404 GL_Color(0, 0, 0, 1);
1405 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1407 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1409 if (gl_ext_separatestencil.integer)
1411 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL;
1412 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL;
1414 else if (gl_ext_stenciltwoside.integer)
1416 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE;
1417 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE;
1421 r_shadow_shadowingrendermode_zpass = R_SHADOW_RENDERMODE_ZPASS_STENCIL;
1422 r_shadow_shadowingrendermode_zfail = R_SHADOW_RENDERMODE_ZFAIL_STENCIL;
1425 if (r_glsl.integer && gl_support_fragment_shader)
1426 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_GLSL;
1427 else if (gl_dot3arb && gl_texturecubemap && r_textureunits.integer >= 2 && gl_combine.integer && gl_stencil)
1428 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_DOT3;
1430 r_shadow_lightingrendermode = R_SHADOW_RENDERMODE_LIGHT_VERTEX;
1433 qglGetIntegerv(GL_DRAW_BUFFER, &drawbuffer);CHECKGLERROR
1434 qglGetIntegerv(GL_READ_BUFFER, &readbuffer);CHECKGLERROR
1435 r_shadow_drawbuffer = drawbuffer;
1436 r_shadow_readbuffer = readbuffer;
1439 void R_Shadow_RenderMode_ActiveLight(const rtlight_t *rtlight)
1441 rsurface.rtlight = rtlight;
1444 void R_Shadow_RenderMode_Reset(void)
1447 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE)
1449 qglDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1451 if (gl_support_ext_framebuffer_object)
1453 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);CHECKGLERROR
1455 qglDrawBuffer(r_shadow_drawbuffer);CHECKGLERROR
1456 qglReadBuffer(r_shadow_readbuffer);CHECKGLERROR
1457 R_SetViewport(&r_refdef.view.viewport);
1458 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
1459 R_Mesh_ColorPointer(NULL, 0, 0);
1460 R_Mesh_ResetTextureState();
1461 GL_DepthRange(0, 1);
1463 GL_DepthMask(false);
1464 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1465 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1466 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
1467 qglStencilMask(~0);CHECKGLERROR
1468 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
1469 qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
1470 GL_CullFace(r_refdef.view.cullface_back);
1471 GL_Color(1, 1, 1, 1);
1472 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
1473 GL_BlendFunc(GL_ONE, GL_ZERO);
1474 R_SetupGenericShader(false);
1475 r_shadow_usingshadowmaprect = false;
1476 r_shadow_usingshadowmapcube = false;
1477 r_shadow_usingshadowmap2d = false;
1481 void R_Shadow_ClearStencil(void)
1484 GL_Clear(GL_STENCIL_BUFFER_BIT);
1485 r_refdef.stats.lights_clears++;
1488 void R_Shadow_RenderMode_StencilShadowVolumes(qboolean zpass)
1490 r_shadow_rendermode_t mode = zpass ? r_shadow_shadowingrendermode_zpass : r_shadow_shadowingrendermode_zfail;
1491 if (r_shadow_rendermode == mode)
1494 R_Shadow_RenderMode_Reset();
1495 GL_ColorMask(0, 0, 0, 0);
1496 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1497 R_SetupDepthOrShadowShader();
1498 qglDepthFunc(GL_LESS);CHECKGLERROR
1499 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1500 r_shadow_rendermode = mode;
1505 case R_SHADOW_RENDERMODE_ZPASS_SEPARATESTENCIL:
1506 GL_CullFace(GL_NONE);
1507 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1508 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1510 case R_SHADOW_RENDERMODE_ZFAIL_SEPARATESTENCIL:
1511 GL_CullFace(GL_NONE);
1512 qglStencilOpSeparate(r_refdef.view.cullface_front, GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1513 qglStencilOpSeparate(r_refdef.view.cullface_back, GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1515 case R_SHADOW_RENDERMODE_ZPASS_STENCILTWOSIDE:
1516 GL_CullFace(GL_NONE);
1517 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1518 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
1519 qglStencilMask(~0);CHECKGLERROR
1520 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
1521 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
1522 qglStencilMask(~0);CHECKGLERROR
1523 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
1525 case R_SHADOW_RENDERMODE_ZFAIL_STENCILTWOSIDE:
1526 GL_CullFace(GL_NONE);
1527 qglEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);CHECKGLERROR
1528 qglActiveStencilFaceEXT(r_refdef.view.cullface_front);CHECKGLERROR
1529 qglStencilMask(~0);CHECKGLERROR
1530 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
1531 qglActiveStencilFaceEXT(r_refdef.view.cullface_back);CHECKGLERROR
1532 qglStencilMask(~0);CHECKGLERROR
1533 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
1538 static void R_Shadow_MakeVSDCT(void)
1540 // maps to a 2x3 texture rectangle with normalized coordinates
1545 // stores abs(dir.xy), offset.xy/2.5
1546 unsigned char data[4*6] =
1548 255, 0, 0x33, 0x33, // +X: <1, 0>, <0.5, 0.5>
1549 255, 0, 0x99, 0x33, // -X: <1, 0>, <1.5, 0.5>
1550 0, 255, 0x33, 0x99, // +Y: <0, 1>, <0.5, 1.5>
1551 0, 255, 0x99, 0x99, // -Y: <0, 1>, <1.5, 1.5>
1552 0, 0, 0x33, 0xFF, // +Z: <0, 0>, <0.5, 2.5>
1553 0, 0, 0x99, 0xFF, // -Z: <0, 0>, <1.5, 2.5>
1555 r_shadow_shadowmapvsdcttexture = R_LoadTextureCubeMap(r_shadow_texturepool, "shadowmapvsdct", 1, data, TEXTYPE_RGBA, TEXF_ALWAYSPRECACHE | TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALPHA, NULL);
1558 void R_Shadow_RenderMode_ShadowMap(int side, qboolean clear, int size)
1563 float nearclip, farclip, bias;
1564 r_viewport_t viewport;
1566 maxsize = r_shadow_shadowmapmaxsize;
1567 nearclip = r_shadow_shadowmapping_nearclip.value / rsurface.rtlight->radius;
1569 bias = r_shadow_shadowmapping_bias.value * nearclip * (1024.0f / size);// * rsurface.rtlight->radius;
1570 r_shadow_shadowmap_parameters[2] = 0.5f + 0.5f * (farclip + nearclip) / (farclip - nearclip);
1571 r_shadow_shadowmap_parameters[3] = -nearclip * farclip / (farclip - nearclip) - 0.5f * bias;
1572 if (r_shadow_shadowmode == 1)
1574 // complex unrolled cube approach (more flexible)
1575 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
1576 R_Shadow_MakeVSDCT();
1577 if (!r_shadow_shadowmap2dtexture)
1580 int w = maxsize*2, h = gl_support_arb_texture_non_power_of_two ? maxsize*3 : maxsize*4;
1581 r_shadow_shadowmap2dtexture = R_LoadTextureShadowMap2D(r_shadow_texturepool, "shadowmap", w, h, r_shadow_shadowmapsampler);
1582 qglGenFramebuffersEXT(1, &r_shadow_fbo2d);CHECKGLERROR
1583 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbo2d);CHECKGLERROR
1584 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, R_GetTexture(r_shadow_shadowmap2dtexture), 0);CHECKGLERROR
1588 R_Shadow_RenderMode_Reset();
1589 if (r_shadow_shadowmap2dtexture)
1591 // render depth into the fbo, do not render color at all
1592 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbo2d);CHECKGLERROR
1593 qglDrawBuffer(GL_NONE);CHECKGLERROR
1594 qglReadBuffer(GL_NONE);CHECKGLERROR
1595 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
1596 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
1598 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
1599 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
1601 R_SetupDepthOrShadowShader();
1605 R_SetupShowDepthShader();
1606 qglClearColor(1,1,1,1);CHECKGLERROR
1608 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
1609 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmap2dtexture);
1610 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureHeight(r_shadow_shadowmap2dtexture);
1611 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
1612 r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
1613 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAP2D;
1615 else if (r_shadow_shadowmode == 2)
1617 // complex unrolled cube approach (more flexible)
1618 if (r_shadow_shadowmapvsdct && !r_shadow_shadowmapvsdcttexture)
1619 R_Shadow_MakeVSDCT();
1620 if (!r_shadow_shadowmaprectangletexture)
1623 r_shadow_shadowmaprectangletexture = R_LoadTextureShadowMapRectangle(r_shadow_texturepool, "shadowmap", maxsize*2, maxsize*3, r_shadow_shadowmapsampler);
1624 qglGenFramebuffersEXT(1, &r_shadow_fborectangle);CHECKGLERROR
1625 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fborectangle);CHECKGLERROR
1626 qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_RECTANGLE_ARB, R_GetTexture(r_shadow_shadowmaprectangletexture), 0);CHECKGLERROR
1630 R_Shadow_RenderMode_Reset();
1631 if (r_shadow_shadowmaprectangletexture)
1633 // render depth into the fbo, do not render color at all
1634 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fborectangle);CHECKGLERROR
1635 qglDrawBuffer(GL_NONE);CHECKGLERROR
1636 qglReadBuffer(GL_NONE);CHECKGLERROR
1637 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
1638 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
1640 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
1641 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
1643 R_SetupDepthOrShadowShader();
1647 R_SetupShowDepthShader();
1648 qglClearColor(1,1,1,1);CHECKGLERROR
1650 R_Viewport_InitRectSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, r_shadow_shadowmapborder, nearclip, farclip, NULL);
1651 r_shadow_shadowmap_texturescale[0] = 1.0f;
1652 r_shadow_shadowmap_texturescale[1] = 1.0f;
1653 r_shadow_shadowmap_parameters[0] = 0.5f * (size - r_shadow_shadowmapborder);
1654 r_shadow_shadowmap_parameters[1] = r_shadow_shadowmapvsdct ? 2.5f*size : size;
1655 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE;
1657 else if (r_shadow_shadowmode == 3)
1659 // simple cube approach
1660 if (!r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod])
1663 r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod] = R_LoadTextureShadowMapCube(r_shadow_texturepool, "shadowmapcube", bound(1, maxsize >> r_shadow_shadowmaplod, 2048), r_shadow_shadowmapsampler);
1664 qglGenFramebuffersEXT(6, r_shadow_fbocubeside[r_shadow_shadowmaplod]);CHECKGLERROR
1665 for (i = 0;i < 6;i++)
1667 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbocubeside[r_shadow_shadowmaplod][i]);CHECKGLERROR
1668 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
1673 R_Shadow_RenderMode_Reset();
1674 if (r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod])
1676 // render depth into the fbo, do not render color at all
1677 qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, r_shadow_fbocubeside[r_shadow_shadowmaplod][side]);CHECKGLERROR
1678 qglDrawBuffer(GL_NONE);CHECKGLERROR
1679 qglReadBuffer(GL_NONE);CHECKGLERROR
1680 status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);CHECKGLERROR
1681 if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
1683 Con_Printf("R_Shadow_RenderMode_ShadowMap: glCheckFramebufferStatusEXT returned %i\n", status);
1684 Cvar_SetValueQuick(&r_shadow_shadowmapping, 0);
1686 R_SetupDepthOrShadowShader();
1690 R_SetupShowDepthShader();
1691 qglClearColor(1,1,1,1);CHECKGLERROR
1693 R_Viewport_InitCubeSideView(&viewport, &rsurface.rtlight->matrix_lighttoworld, side, size, nearclip, farclip, NULL);
1694 r_shadow_shadowmap_texturescale[0] = 1.0f / R_TextureWidth(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]);
1695 r_shadow_shadowmap_texturescale[1] = 1.0f / R_TextureWidth(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]);
1696 r_shadow_shadowmap_parameters[0] = 1.0f;
1697 r_shadow_shadowmap_parameters[1] = 1.0f;
1698 r_shadow_rendermode = R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE;
1701 R_SetViewport(&viewport);
1702 GL_PolygonOffset(0, 0);
1704 if(r_shadow_shadowmode >= 1 && r_shadow_shadowmode <= 2)
1706 static qboolean cullback[6] = { true, false, true, false, false, true };
1707 GL_CullFace(cullback[side] ? r_refdef.view.cullface_back : r_refdef.view.cullface_front);
1709 else if(r_shadow_shadowmode == 3)
1710 GL_CullFace(r_refdef.view.cullface_back);
1712 GL_CullFace(GL_NONE);
1714 GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
1717 qglClearDepth(1);CHECKGLERROR
1720 qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
1724 void R_Shadow_RenderMode_Lighting(qboolean stenciltest, qboolean transparent, qboolean shadowmapping)
1727 R_Shadow_RenderMode_Reset();
1728 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1731 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1735 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1736 // only draw light where this geometry was already rendered AND the
1737 // stencil is 128 (values other than this mean shadow)
1738 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
1740 r_shadow_rendermode = r_shadow_lightingrendermode;
1741 // do global setup needed for the chosen lighting mode
1742 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
1744 R_Mesh_TexBindCubeMap(GL20TU_CUBE, R_GetTexture(rsurface.rtlight->currentcubemap)); // light filter
1745 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
1749 if (r_shadow_shadowmode == 1)
1751 r_shadow_usingshadowmap2d = true;
1752 R_Mesh_TexBind(GL20TU_SHADOWMAP2D, R_GetTexture(r_shadow_shadowmap2dtexture));
1755 else if (r_shadow_shadowmode == 2)
1757 r_shadow_usingshadowmaprect = true;
1758 R_Mesh_TexBindRectangle(GL20TU_SHADOWMAPRECT, R_GetTexture(r_shadow_shadowmaprectangletexture));
1761 else if (r_shadow_shadowmode == 3)
1763 r_shadow_usingshadowmapcube = true;
1764 R_Mesh_TexBindCubeMap(GL20TU_SHADOWMAPCUBE, R_GetTexture(r_shadow_shadowmapcubetexture[r_shadow_shadowmaplod]));
1768 if (r_shadow_shadowmapvsdct && (r_shadow_usingshadowmap2d || r_shadow_usingshadowmaprect))
1770 R_Mesh_TexBindCubeMap(GL20TU_CUBEPROJECTION, R_GetTexture(r_shadow_shadowmapvsdcttexture));
1775 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_LIGHT_VERTEX)
1776 R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
1777 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1781 void R_Shadow_RenderMode_VisibleShadowVolumes(void)
1784 R_Shadow_RenderMode_Reset();
1785 GL_BlendFunc(GL_ONE, GL_ONE);
1786 GL_DepthRange(0, 1);
1787 GL_DepthTest(r_showshadowvolumes.integer < 2);
1788 GL_Color(0.0, 0.0125 * r_refdef.view.colorscale, 0.1 * r_refdef.view.colorscale, 1);
1789 GL_PolygonOffset(r_refdef.shadowpolygonfactor, r_refdef.shadowpolygonoffset);CHECKGLERROR
1790 GL_CullFace(GL_NONE);
1791 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLEVOLUMES;
1794 void R_Shadow_RenderMode_VisibleLighting(qboolean stenciltest, qboolean transparent)
1797 R_Shadow_RenderMode_Reset();
1798 GL_BlendFunc(GL_ONE, GL_ONE);
1799 GL_DepthRange(0, 1);
1800 GL_DepthTest(r_showlighting.integer < 2);
1801 GL_Color(0.1 * r_refdef.view.colorscale, 0.0125 * r_refdef.view.colorscale, 0, 1);
1804 qglDepthFunc(GL_EQUAL);CHECKGLERROR
1808 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
1809 qglStencilFunc(GL_EQUAL, 128, ~0);CHECKGLERROR
1811 r_shadow_rendermode = R_SHADOW_RENDERMODE_VISIBLELIGHTING;
1814 void R_Shadow_RenderMode_End(void)
1817 R_Shadow_RenderMode_Reset();
1818 R_Shadow_RenderMode_ActiveLight(NULL);
1820 GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
1821 r_shadow_rendermode = R_SHADOW_RENDERMODE_NONE;
1824 int bboxedges[12][2] =
1843 qboolean R_Shadow_ScissorForBBox(const float *mins, const float *maxs)
1845 int i, ix1, iy1, ix2, iy2;
1846 float x1, y1, x2, y2;
1848 float vertex[20][3];
1857 r_shadow_lightscissor[0] = r_refdef.view.viewport.x;
1858 r_shadow_lightscissor[1] = r_refdef.view.viewport.y;
1859 r_shadow_lightscissor[2] = r_refdef.view.viewport.width;
1860 r_shadow_lightscissor[3] = r_refdef.view.viewport.height;
1862 if (!r_shadow_scissor.integer)
1865 // if view is inside the light box, just say yes it's visible
1866 if (BoxesOverlap(r_refdef.view.origin, r_refdef.view.origin, mins, maxs))
1869 x1 = y1 = x2 = y2 = 0;
1871 // transform all corners that are infront of the nearclip plane
1872 VectorNegate(r_refdef.view.frustum[4].normal, plane4f);
1873 plane4f[3] = r_refdef.view.frustum[4].dist;
1875 for (i = 0;i < 8;i++)
1877 Vector4Set(corner[i], (i & 1) ? maxs[0] : mins[0], (i & 2) ? maxs[1] : mins[1], (i & 4) ? maxs[2] : mins[2], 1);
1878 dist[i] = DotProduct4(corner[i], plane4f);
1879 sign[i] = dist[i] > 0;
1882 VectorCopy(corner[i], vertex[numvertices]);
1886 // if some points are behind the nearclip, add clipped edge points to make
1887 // sure that the scissor boundary is complete
1888 if (numvertices > 0 && numvertices < 8)
1890 // add clipped edge points
1891 for (i = 0;i < 12;i++)
1893 j = bboxedges[i][0];
1894 k = bboxedges[i][1];
1895 if (sign[j] != sign[k])
1897 f = dist[j] / (dist[j] - dist[k]);
1898 VectorLerp(corner[j], f, corner[k], vertex[numvertices]);
1904 // if we have no points to check, the light is behind the view plane
1908 // if we have some points to transform, check what screen area is covered
1909 x1 = y1 = x2 = y2 = 0;
1911 //Con_Printf("%i vertices to transform...\n", numvertices);
1912 for (i = 0;i < numvertices;i++)
1914 VectorCopy(vertex[i], v);
1915 R_Viewport_TransformToScreen(&r_refdef.view.viewport, v, v2);
1916 //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]);
1919 if (x1 > v2[0]) x1 = v2[0];
1920 if (x2 < v2[0]) x2 = v2[0];
1921 if (y1 > v2[1]) y1 = v2[1];
1922 if (y2 < v2[1]) y2 = v2[1];
1931 // now convert the scissor rectangle to integer screen coordinates
1932 ix1 = (int)(x1 - 1.0f);
1933 iy1 = vid.height - (int)(y2 - 1.0f);
1934 ix2 = (int)(x2 + 1.0f);
1935 iy2 = vid.height - (int)(y1 + 1.0f);
1936 //Con_Printf("%f %f %f %f\n", x1, y1, x2, y2);
1938 // clamp it to the screen
1939 if (ix1 < r_refdef.view.viewport.x) ix1 = r_refdef.view.viewport.x;
1940 if (iy1 < r_refdef.view.viewport.y) iy1 = r_refdef.view.viewport.y;
1941 if (ix2 > r_refdef.view.viewport.x + r_refdef.view.viewport.width) ix2 = r_refdef.view.viewport.x + r_refdef.view.viewport.width;
1942 if (iy2 > r_refdef.view.viewport.y + r_refdef.view.viewport.height) iy2 = r_refdef.view.viewport.y + r_refdef.view.viewport.height;
1944 // if it is inside out, it's not visible
1945 if (ix2 <= ix1 || iy2 <= iy1)
1948 // the light area is visible, set up the scissor rectangle
1949 r_shadow_lightscissor[0] = ix1;
1950 r_shadow_lightscissor[1] = iy1;
1951 r_shadow_lightscissor[2] = ix2 - ix1;
1952 r_shadow_lightscissor[3] = iy2 - iy1;
1954 r_refdef.stats.lights_scissored++;
1958 static void R_Shadow_RenderLighting_Light_Vertex_Shading(int firstvertex, int numverts, int numtriangles, const int *element3i, const float *diffusecolor, const float *ambientcolor)
1960 float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
1961 float *normal3f = rsurface.normal3f + 3 * firstvertex;
1962 float *color4f = rsurface.array_color4f + 4 * firstvertex;
1963 float dist, dot, distintensity, shadeintensity, v[3], n[3];
1964 if (r_textureunits.integer >= 3)
1966 if (VectorLength2(diffusecolor) > 0)
1968 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
1970 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1971 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
1972 if ((dot = DotProduct(n, v)) < 0)
1974 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
1975 VectorMA(ambientcolor, shadeintensity, diffusecolor, color4f);
1978 VectorCopy(ambientcolor, color4f);
1979 if (r_refdef.fogenabled)
1982 f = FogPoint_Model(vertex3f);
1983 VectorScale(color4f, f, color4f);
1990 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
1992 VectorCopy(ambientcolor, color4f);
1993 if (r_refdef.fogenabled)
1996 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
1997 f = FogPoint_Model(vertex3f);
1998 VectorScale(color4f, f, color4f);
2004 else if (r_textureunits.integer >= 2)
2006 if (VectorLength2(diffusecolor) > 0)
2008 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2010 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2011 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2013 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2014 if ((dot = DotProduct(n, v)) < 0)
2016 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2017 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2018 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2019 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2023 color4f[0] = ambientcolor[0] * distintensity;
2024 color4f[1] = ambientcolor[1] * distintensity;
2025 color4f[2] = ambientcolor[2] * distintensity;
2027 if (r_refdef.fogenabled)
2030 f = FogPoint_Model(vertex3f);
2031 VectorScale(color4f, f, color4f);
2035 VectorClear(color4f);
2041 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2043 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2044 if ((dist = fabs(v[2])) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2046 color4f[0] = ambientcolor[0] * distintensity;
2047 color4f[1] = ambientcolor[1] * distintensity;
2048 color4f[2] = ambientcolor[2] * distintensity;
2049 if (r_refdef.fogenabled)
2052 f = FogPoint_Model(vertex3f);
2053 VectorScale(color4f, f, color4f);
2057 VectorClear(color4f);
2064 if (VectorLength2(diffusecolor) > 0)
2066 for (;numverts > 0;numverts--, vertex3f += 3, normal3f += 3, color4f += 4)
2068 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2069 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2071 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2072 Matrix4x4_Transform3x3(&rsurface.entitytolight, normal3f, n);
2073 if ((dot = DotProduct(n, v)) < 0)
2075 shadeintensity = -dot / sqrt(VectorLength2(v) * VectorLength2(n));
2076 color4f[0] = (ambientcolor[0] + shadeintensity * diffusecolor[0]) * distintensity;
2077 color4f[1] = (ambientcolor[1] + shadeintensity * diffusecolor[1]) * distintensity;
2078 color4f[2] = (ambientcolor[2] + shadeintensity * diffusecolor[2]) * distintensity;
2082 color4f[0] = ambientcolor[0] * distintensity;
2083 color4f[1] = ambientcolor[1] * distintensity;
2084 color4f[2] = ambientcolor[2] * distintensity;
2086 if (r_refdef.fogenabled)
2089 f = FogPoint_Model(vertex3f);
2090 VectorScale(color4f, f, color4f);
2094 VectorClear(color4f);
2100 for (;numverts > 0;numverts--, vertex3f += 3, color4f += 4)
2102 Matrix4x4_Transform(&rsurface.entitytolight, vertex3f, v);
2103 if ((dist = VectorLength(v)) < 1 && (distintensity = r_shadow_attentable[(int)(dist * ATTENTABLESIZE)]))
2105 distintensity = (1 - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
2106 color4f[0] = ambientcolor[0] * distintensity;
2107 color4f[1] = ambientcolor[1] * distintensity;
2108 color4f[2] = ambientcolor[2] * distintensity;
2109 if (r_refdef.fogenabled)
2112 f = FogPoint_Model(vertex3f);
2113 VectorScale(color4f, f, color4f);
2117 VectorClear(color4f);
2124 // TODO: use glTexGen instead of feeding vertices to texcoordpointer?
2126 static void R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
2129 float *out3f = rsurface.array_texcoord3f + 3 * firstvertex;
2130 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
2131 const float *svector3f = rsurface.svector3f + 3 * firstvertex;
2132 const float *tvector3f = rsurface.tvector3f + 3 * firstvertex;
2133 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
2135 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
2137 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
2138 // the cubemap normalizes this for us
2139 out3f[0] = DotProduct(svector3f, lightdir);
2140 out3f[1] = DotProduct(tvector3f, lightdir);
2141 out3f[2] = DotProduct(normal3f, lightdir);
2145 static void R_Shadow_GenTexCoords_Specular_NormalCubeMap(int firstvertex, int numvertices, int numtriangles, const int *element3i)
2148 float *out3f = rsurface.array_texcoord3f + 3 * firstvertex;
2149 const float *vertex3f = rsurface.vertex3f + 3 * firstvertex;
2150 const float *svector3f = rsurface.svector3f + 3 * firstvertex;
2151 const float *tvector3f = rsurface.tvector3f + 3 * firstvertex;
2152 const float *normal3f = rsurface.normal3f + 3 * firstvertex;
2153 float lightdir[3], eyedir[3], halfdir[3];
2154 for (i = 0;i < numvertices;i++, vertex3f += 3, svector3f += 3, tvector3f += 3, normal3f += 3, out3f += 3)
2156 VectorSubtract(rsurface.entitylightorigin, vertex3f, lightdir);
2157 VectorNormalize(lightdir);
2158 VectorSubtract(rsurface.modelorg, vertex3f, eyedir);
2159 VectorNormalize(eyedir);
2160 VectorAdd(lightdir, eyedir, halfdir);
2161 // the cubemap normalizes this for us
2162 out3f[0] = DotProduct(svector3f, halfdir);
2163 out3f[1] = DotProduct(tvector3f, halfdir);
2164 out3f[2] = DotProduct(normal3f, halfdir);
2168 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)
2170 // used to display how many times a surface is lit for level design purposes
2171 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2174 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)
2176 // ARB2 GLSL shader path (GFFX5200, Radeon 9500)
2177 R_SetupSurfaceShader(lightcolorbase, false, ambientscale, diffusescale, specularscale, RSURFPASS_RTLIGHT);
2178 if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND))
2179 R_Mesh_ColorPointer(rsurface.modellightmapcolor4f, rsurface.modellightmapcolor4f_bufferobject, rsurface.modellightmapcolor4f_bufferoffset);
2181 R_Mesh_ColorPointer(NULL, 0, 0);
2182 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
2183 R_Mesh_TexMatrix(1, &rsurface.texture->currentbackgroundtexmatrix);
2184 R_Mesh_TexBind(GL20TU_NORMAL, R_GetTexture(rsurface.texture->currentskinframe->nmap));
2185 R_Mesh_TexBind(GL20TU_COLOR, R_GetTexture(rsurface.texture->basetexture));
2186 R_Mesh_TexBind(GL20TU_GLOSS, R_GetTexture(rsurface.texture->glosstexture));
2187 if (rsurface.texture->backgroundcurrentskinframe)
2189 R_Mesh_TexBind(GL20TU_SECONDARY_NORMAL, R_GetTexture(rsurface.texture->backgroundcurrentskinframe->nmap));
2190 R_Mesh_TexBind(GL20TU_SECONDARY_COLOR, R_GetTexture(rsurface.texture->backgroundbasetexture));
2191 R_Mesh_TexBind(GL20TU_SECONDARY_GLOSS, R_GetTexture(rsurface.texture->backgroundglosstexture));
2192 R_Mesh_TexBind(GL20TU_SECONDARY_GLOW, R_GetTexture(rsurface.texture->backgroundcurrentskinframe->glow));
2194 //R_Mesh_TexBindCubeMap(GL20TU_CUBE, R_GetTexture(rsurface.rtlight->currentcubemap));
2195 R_Mesh_TexBind(GL20TU_FOGMASK, R_GetTexture(r_texture_fogattenuation));
2196 if(rsurface.texture->colormapping)
2198 R_Mesh_TexBind(GL20TU_PANTS, R_GetTexture(rsurface.texture->currentskinframe->pants));
2199 R_Mesh_TexBind(GL20TU_SHIRT, R_GetTexture(rsurface.texture->currentskinframe->shirt));
2201 R_Mesh_TexBind(GL20TU_ATTENUATION, R_GetTexture(r_shadow_attenuationgradienttexture));
2202 R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
2203 R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset);
2204 R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset);
2205 R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset);
2206 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2208 qglDepthFunc(GL_EQUAL);CHECKGLERROR
2210 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2211 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
2213 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
2217 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)
2219 // shared final code for all the dot3 layers
2221 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 0);
2222 for (renders = 0;renders < 64 && (r > 0 || g > 0 || b > 0);renders++, r--, g--, b--)
2224 GL_Color(bound(0, r, 1), bound(0, g, 1), bound(0, b, 1), 1);
2225 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2229 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)
2232 // colorscale accounts for how much we multiply the brightness
2235 // mult is how many times the final pass of the lighting will be
2236 // performed to get more brightness than otherwise possible.
2238 // Limit mult to 64 for sanity sake.
2240 if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap != r_texture_whitecube && r_textureunits.integer >= 4)
2242 // 3 3D combine path (Geforce3, Radeon 8500)
2243 memset(&m, 0, sizeof(m));
2244 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2245 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2246 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2247 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2248 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2249 m.tex[1] = R_GetTexture(basetexture);
2250 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
2251 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
2252 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
2253 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
2254 m.texcubemap[2] = R_GetTexture(rsurface.rtlight->currentcubemap);
2255 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2256 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2257 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2258 m.texmatrix[2] = rsurface.entitytolight;
2259 GL_BlendFunc(GL_ONE, GL_ONE);
2261 else if (r_shadow_texture3d.integer && rsurface.rtlight->currentcubemap == r_texture_whitecube && r_textureunits.integer >= 2)
2263 // 2 3D combine path (Geforce3, original Radeon)
2264 memset(&m, 0, sizeof(m));
2265 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2266 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2267 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2268 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2269 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2270 m.tex[1] = R_GetTexture(basetexture);
2271 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
2272 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
2273 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
2274 m.texmatrix[1] = rsurface.texture->currenttexmatrix;
2275 GL_BlendFunc(GL_ONE, GL_ONE);
2277 else if (r_textureunits.integer >= 4 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2279 // 4 2D combine path (Geforce3, Radeon 8500)
2280 memset(&m, 0, sizeof(m));
2281 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2282 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2283 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2284 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2285 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2286 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2287 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2288 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2289 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2290 m.texmatrix[1] = rsurface.entitytoattenuationz;
2291 m.tex[2] = R_GetTexture(basetexture);
2292 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
2293 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
2294 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
2295 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
2296 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2298 m.texcubemap[3] = R_GetTexture(rsurface.rtlight->currentcubemap);
2299 m.pointer_texcoord3f[3] = rsurface.vertex3f;
2300 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
2301 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
2302 m.texmatrix[3] = rsurface.entitytolight;
2304 GL_BlendFunc(GL_ONE, GL_ONE);
2306 else if (r_textureunits.integer >= 3 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
2308 // 3 2D combine path (Geforce3, original Radeon)
2309 memset(&m, 0, sizeof(m));
2310 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2311 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2312 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2313 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2314 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2315 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2316 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2317 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2318 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2319 m.texmatrix[1] = rsurface.entitytoattenuationz;
2320 m.tex[2] = R_GetTexture(basetexture);
2321 m.pointer_texcoord[2] = rsurface.texcoordtexture2f;
2322 m.pointer_texcoord_bufferobject[2] = rsurface.texcoordtexture2f_bufferobject;
2323 m.pointer_texcoord_bufferoffset[2] = rsurface.texcoordtexture2f_bufferoffset;
2324 m.texmatrix[2] = rsurface.texture->currenttexmatrix;
2325 GL_BlendFunc(GL_ONE, GL_ONE);
2329 // 2/2/2 2D combine path (any dot3 card)
2330 memset(&m, 0, sizeof(m));
2331 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2332 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2333 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2334 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2335 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2336 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2337 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2338 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2339 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2340 m.texmatrix[1] = rsurface.entitytoattenuationz;
2341 R_Mesh_TextureState(&m);
2342 GL_ColorMask(0,0,0,1);
2343 GL_BlendFunc(GL_ONE, GL_ZERO);
2344 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2347 memset(&m, 0, sizeof(m));
2348 m.tex[0] = R_GetTexture(basetexture);
2349 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2350 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2351 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2352 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2353 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2355 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2356 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2357 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2358 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2359 m.texmatrix[1] = rsurface.entitytolight;
2361 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2363 // this final code is shared
2364 R_Mesh_TextureState(&m);
2365 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);
2368 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)
2371 // colorscale accounts for how much we multiply the brightness
2374 // mult is how many times the final pass of the lighting will be
2375 // performed to get more brightness than otherwise possible.
2377 // Limit mult to 64 for sanity sake.
2379 // generate normalization cubemap texcoords
2380 R_Shadow_GenTexCoords_Diffuse_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
2381 if (r_shadow_texture3d.integer && r_textureunits.integer >= 4)
2383 // 3/2 3D combine path (Geforce3, Radeon 8500)
2384 memset(&m, 0, sizeof(m));
2385 m.tex[0] = R_GetTexture(normalmaptexture);
2386 m.texcombinergb[0] = GL_REPLACE;
2387 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2388 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2389 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2390 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2391 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2392 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2393 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2394 m.pointer_texcoord_bufferobject[1] = 0;
2395 m.pointer_texcoord_bufferoffset[1] = 0;
2396 m.tex3d[2] = R_GetTexture(r_shadow_attenuation3dtexture);
2397 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2398 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2399 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2400 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
2401 R_Mesh_TextureState(&m);
2402 GL_ColorMask(0,0,0,1);
2403 GL_BlendFunc(GL_ONE, GL_ZERO);
2404 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2407 memset(&m, 0, sizeof(m));
2408 m.tex[0] = R_GetTexture(basetexture);
2409 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2410 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2411 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2412 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2413 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2415 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2416 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2417 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2418 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2419 m.texmatrix[1] = rsurface.entitytolight;
2421 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2423 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2425 // 1/2/2 3D combine path (original Radeon)
2426 memset(&m, 0, sizeof(m));
2427 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2428 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2429 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2430 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2431 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2432 R_Mesh_TextureState(&m);
2433 GL_ColorMask(0,0,0,1);
2434 GL_BlendFunc(GL_ONE, GL_ZERO);
2435 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2438 memset(&m, 0, sizeof(m));
2439 m.tex[0] = R_GetTexture(normalmaptexture);
2440 m.texcombinergb[0] = GL_REPLACE;
2441 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2442 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2443 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2444 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2445 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2446 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2447 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2448 m.pointer_texcoord_bufferobject[1] = 0;
2449 m.pointer_texcoord_bufferoffset[1] = 0;
2450 R_Mesh_TextureState(&m);
2451 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2452 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2455 memset(&m, 0, sizeof(m));
2456 m.tex[0] = R_GetTexture(basetexture);
2457 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2458 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2459 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2460 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2461 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2463 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2464 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2465 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2466 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2467 m.texmatrix[1] = rsurface.entitytolight;
2469 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2471 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube)
2473 // 2/2 3D combine path (original Radeon)
2474 memset(&m, 0, sizeof(m));
2475 m.tex[0] = R_GetTexture(normalmaptexture);
2476 m.texcombinergb[0] = GL_REPLACE;
2477 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2478 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2479 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2480 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2481 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2482 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2483 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2484 m.pointer_texcoord_bufferobject[1] = 0;
2485 m.pointer_texcoord_bufferoffset[1] = 0;
2486 R_Mesh_TextureState(&m);
2487 GL_ColorMask(0,0,0,1);
2488 GL_BlendFunc(GL_ONE, GL_ZERO);
2489 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2492 memset(&m, 0, sizeof(m));
2493 m.tex[0] = R_GetTexture(basetexture);
2494 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2495 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2496 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2497 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2498 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2499 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2500 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2501 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2502 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2503 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2505 else if (r_textureunits.integer >= 4)
2507 // 4/2 2D combine path (Geforce3, Radeon 8500)
2508 memset(&m, 0, sizeof(m));
2509 m.tex[0] = R_GetTexture(normalmaptexture);
2510 m.texcombinergb[0] = GL_REPLACE;
2511 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2512 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2513 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2514 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2515 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2516 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2517 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2518 m.pointer_texcoord_bufferobject[1] = 0;
2519 m.pointer_texcoord_bufferoffset[1] = 0;
2520 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2521 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2522 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2523 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2524 m.texmatrix[2] = rsurface.entitytoattenuationxyz;
2525 m.tex[3] = R_GetTexture(r_shadow_attenuation2dtexture);
2526 m.pointer_texcoord3f[3] = rsurface.vertex3f;
2527 m.pointer_texcoord_bufferobject[3] = rsurface.vertex3f_bufferobject;
2528 m.pointer_texcoord_bufferoffset[3] = rsurface.vertex3f_bufferoffset;
2529 m.texmatrix[3] = rsurface.entitytoattenuationz;
2530 R_Mesh_TextureState(&m);
2531 GL_ColorMask(0,0,0,1);
2532 GL_BlendFunc(GL_ONE, GL_ZERO);
2533 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2536 memset(&m, 0, sizeof(m));
2537 m.tex[0] = R_GetTexture(basetexture);
2538 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2539 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2540 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2541 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2542 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2544 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2545 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2546 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2547 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2548 m.texmatrix[1] = rsurface.entitytolight;
2550 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2554 // 2/2/2 2D combine path (any dot3 card)
2555 memset(&m, 0, sizeof(m));
2556 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2557 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2558 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2559 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2560 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2561 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2562 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2563 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2564 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2565 m.texmatrix[1] = rsurface.entitytoattenuationz;
2566 R_Mesh_TextureState(&m);
2567 GL_ColorMask(0,0,0,1);
2568 GL_BlendFunc(GL_ONE, GL_ZERO);
2569 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2572 memset(&m, 0, sizeof(m));
2573 m.tex[0] = R_GetTexture(normalmaptexture);
2574 m.texcombinergb[0] = GL_REPLACE;
2575 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2576 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2577 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2578 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2579 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2580 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2581 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2582 m.pointer_texcoord_bufferobject[1] = 0;
2583 m.pointer_texcoord_bufferoffset[1] = 0;
2584 R_Mesh_TextureState(&m);
2585 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2586 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2589 memset(&m, 0, sizeof(m));
2590 m.tex[0] = R_GetTexture(basetexture);
2591 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2592 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2593 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2594 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2595 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2597 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2598 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2599 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2600 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2601 m.texmatrix[1] = rsurface.entitytolight;
2603 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2605 // this final code is shared
2606 R_Mesh_TextureState(&m);
2607 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);
2610 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)
2612 float glossexponent;
2614 // FIXME: detect blendsquare!
2615 //if (!gl_support_blendsquare)
2618 // generate normalization cubemap texcoords
2619 R_Shadow_GenTexCoords_Specular_NormalCubeMap(firstvertex, numvertices, numtriangles, element3i);
2620 if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap != r_texture_whitecube)
2622 // 2/0/0/1/2 3D combine blendsquare path
2623 memset(&m, 0, sizeof(m));
2624 m.tex[0] = R_GetTexture(normalmaptexture);
2625 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2626 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2627 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2628 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2629 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2630 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2631 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2632 m.pointer_texcoord_bufferobject[1] = 0;
2633 m.pointer_texcoord_bufferoffset[1] = 0;
2634 R_Mesh_TextureState(&m);
2635 GL_ColorMask(0,0,0,1);
2636 // this squares the result
2637 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2638 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2640 // second and third pass
2641 R_Mesh_ResetTextureState();
2642 // square alpha in framebuffer a few times to make it shiny
2643 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2644 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2645 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2648 memset(&m, 0, sizeof(m));
2649 m.tex3d[0] = R_GetTexture(r_shadow_attenuation3dtexture);
2650 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2651 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2652 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2653 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2654 R_Mesh_TextureState(&m);
2655 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2656 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2659 memset(&m, 0, sizeof(m));
2660 m.tex[0] = R_GetTexture(glosstexture);
2661 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2662 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2663 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2664 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2665 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2667 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2668 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2669 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2670 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2671 m.texmatrix[1] = rsurface.entitytolight;
2673 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2675 else if (r_shadow_texture3d.integer && r_textureunits.integer >= 2 && rsurface.rtlight->currentcubemap == r_texture_whitecube /* && gl_support_blendsquare*/) // FIXME: detect blendsquare!
2677 // 2/0/0/2 3D combine blendsquare path
2678 memset(&m, 0, sizeof(m));
2679 m.tex[0] = R_GetTexture(normalmaptexture);
2680 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2681 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2682 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2683 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2684 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2685 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2686 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2687 m.pointer_texcoord_bufferobject[1] = 0;
2688 m.pointer_texcoord_bufferoffset[1] = 0;
2689 R_Mesh_TextureState(&m);
2690 GL_ColorMask(0,0,0,1);
2691 // this squares the result
2692 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2693 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2695 // second and third pass
2696 R_Mesh_ResetTextureState();
2697 // square alpha in framebuffer a few times to make it shiny
2698 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2699 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2700 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2703 memset(&m, 0, sizeof(m));
2704 m.tex[0] = R_GetTexture(glosstexture);
2705 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2706 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2707 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2708 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2709 m.tex3d[1] = R_GetTexture(r_shadow_attenuation3dtexture);
2710 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2711 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2712 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2713 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2714 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2718 // 2/0/0/2/2 2D combine blendsquare path
2719 memset(&m, 0, sizeof(m));
2720 m.tex[0] = R_GetTexture(normalmaptexture);
2721 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2722 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2723 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2724 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2725 m.texcubemap[1] = R_GetTexture(r_texture_normalizationcube);
2726 m.texcombinergb[1] = GL_DOT3_RGBA_ARB;
2727 m.pointer_texcoord3f[1] = rsurface.array_texcoord3f;
2728 m.pointer_texcoord_bufferobject[1] = 0;
2729 m.pointer_texcoord_bufferoffset[1] = 0;
2730 R_Mesh_TextureState(&m);
2731 GL_ColorMask(0,0,0,1);
2732 // this squares the result
2733 GL_BlendFunc(GL_SRC_ALPHA, GL_ZERO);
2734 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2736 // second and third pass
2737 R_Mesh_ResetTextureState();
2738 // square alpha in framebuffer a few times to make it shiny
2739 GL_BlendFunc(GL_ZERO, GL_DST_ALPHA);
2740 for (glossexponent = 2;glossexponent * 2 <= r_shadow_glossexponent.value;glossexponent *= 2)
2741 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2744 memset(&m, 0, sizeof(m));
2745 m.tex[0] = R_GetTexture(r_shadow_attenuation2dtexture);
2746 m.pointer_texcoord3f[0] = rsurface.vertex3f;
2747 m.pointer_texcoord_bufferobject[0] = rsurface.vertex3f_bufferobject;
2748 m.pointer_texcoord_bufferoffset[0] = rsurface.vertex3f_bufferoffset;
2749 m.texmatrix[0] = rsurface.entitytoattenuationxyz;
2750 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2751 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2752 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2753 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2754 m.texmatrix[1] = rsurface.entitytoattenuationz;
2755 R_Mesh_TextureState(&m);
2756 GL_BlendFunc(GL_DST_ALPHA, GL_ZERO);
2757 R_Mesh_Draw(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject);
2760 memset(&m, 0, sizeof(m));
2761 m.tex[0] = R_GetTexture(glosstexture);
2762 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2763 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2764 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2765 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2766 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
2768 m.texcubemap[1] = R_GetTexture(rsurface.rtlight->currentcubemap);
2769 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2770 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2771 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2772 m.texmatrix[1] = rsurface.entitytolight;
2774 GL_BlendFunc(GL_DST_ALPHA, GL_ONE);
2776 // this final code is shared
2777 R_Mesh_TextureState(&m);
2778 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);
2781 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)
2783 // ARB path (any Geforce, any Radeon)
2784 qboolean doambient = ambientscale > 0;
2785 qboolean dodiffuse = diffusescale > 0;
2786 qboolean dospecular = specularscale > 0;
2787 if (!doambient && !dodiffuse && !dospecular)
2789 R_Mesh_ColorPointer(NULL, 0, 0);
2791 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, basetexture, ambientscale * r_refdef.view.colorscale);
2793 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, basetexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
2797 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorpants, pantstexture, ambientscale * r_refdef.view.colorscale);
2799 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorpants, pantstexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
2804 R_Shadow_RenderLighting_Light_Dot3_AmbientPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorshirt, shirttexture, ambientscale * r_refdef.view.colorscale);
2806 R_Shadow_RenderLighting_Light_Dot3_DiffusePass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorshirt, shirttexture, normalmaptexture, diffusescale * r_refdef.view.colorscale);
2809 R_Shadow_RenderLighting_Light_Dot3_SpecularPass(firstvertex, numvertices, firsttriangle, numtriangles, element3i, element3s, element3i_bufferobject, element3s_bufferobject, lightcolorbase, glosstexture, normalmaptexture, specularscale * r_refdef.view.colorscale);
2812 static void R_Shadow_RenderLighting_Light_Vertex_Pass(int firstvertex, int numvertices, int numtriangles, const int *element3i, vec3_t diffusecolor2, vec3_t ambientcolor2)
2819 int newnumtriangles;
2823 int maxtriangles = 4096;
2824 int newelements[4096*3];
2825 R_Shadow_RenderLighting_Light_Vertex_Shading(firstvertex, numvertices, numtriangles, element3i, diffusecolor2, ambientcolor2);
2826 for (renders = 0;renders < 64;renders++)
2831 newnumtriangles = 0;
2833 // due to low fillrate on the cards this vertex lighting path is
2834 // designed for, we manually cull all triangles that do not
2835 // contain a lit vertex
2836 // this builds batches of triangles from multiple surfaces and
2837 // renders them at once
2838 for (i = 0, e = element3i;i < numtriangles;i++, e += 3)
2840 if (VectorLength2(rsurface.array_color4f + e[0] * 4) + VectorLength2(rsurface.array_color4f + e[1] * 4) + VectorLength2(rsurface.array_color4f + e[2] * 4) >= 0.01)
2842 if (newnumtriangles)
2844 newfirstvertex = min(newfirstvertex, e[0]);
2845 newlastvertex = max(newlastvertex, e[0]);
2849 newfirstvertex = e[0];
2850 newlastvertex = e[0];
2852 newfirstvertex = min(newfirstvertex, e[1]);
2853 newlastvertex = max(newlastvertex, e[1]);
2854 newfirstvertex = min(newfirstvertex, e[2]);
2855 newlastvertex = max(newlastvertex, e[2]);
2861 if (newnumtriangles >= maxtriangles)
2863 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
2864 newnumtriangles = 0;
2870 if (newnumtriangles >= 1)
2872 R_Mesh_Draw(newfirstvertex, newlastvertex - newfirstvertex + 1, 0, newnumtriangles, newelements, NULL, 0, 0);
2875 // if we couldn't find any lit triangles, exit early
2878 // now reduce the intensity for the next overbright pass
2879 // we have to clamp to 0 here incase the drivers have improper
2880 // handling of negative colors
2881 // (some old drivers even have improper handling of >1 color)
2883 for (i = 0, c = rsurface.array_color4f + 4 * firstvertex;i < numvertices;i++, c += 4)
2885 if (c[0] > 1 || c[1] > 1 || c[2] > 1)
2887 c[0] = max(0, c[0] - 1);
2888 c[1] = max(0, c[1] - 1);
2889 c[2] = max(0, c[2] - 1);
2901 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)
2903 // OpenGL 1.1 path (anything)
2904 float ambientcolorbase[3], diffusecolorbase[3];
2905 float ambientcolorpants[3], diffusecolorpants[3];
2906 float ambientcolorshirt[3], diffusecolorshirt[3];
2908 VectorScale(lightcolorbase, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorbase);
2909 VectorScale(lightcolorbase, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorbase);
2910 VectorScale(lightcolorpants, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorpants);
2911 VectorScale(lightcolorpants, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorpants);
2912 VectorScale(lightcolorshirt, ambientscale * 2 * r_refdef.view.colorscale, ambientcolorshirt);
2913 VectorScale(lightcolorshirt, diffusescale * 2 * r_refdef.view.colorscale, diffusecolorshirt);
2914 memset(&m, 0, sizeof(m));
2915 m.tex[0] = R_GetTexture(basetexture);
2916 m.texmatrix[0] = rsurface.texture->currenttexmatrix;
2917 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
2918 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
2919 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
2920 if (r_textureunits.integer >= 2)
2923 m.tex[1] = R_GetTexture(r_shadow_attenuation2dtexture);
2924 m.texmatrix[1] = rsurface.entitytoattenuationxyz;
2925 m.pointer_texcoord3f[1] = rsurface.vertex3f;
2926 m.pointer_texcoord_bufferobject[1] = rsurface.vertex3f_bufferobject;
2927 m.pointer_texcoord_bufferoffset[1] = rsurface.vertex3f_bufferoffset;
2928 if (r_textureunits.integer >= 3)
2930 // Voodoo4 or Kyro (or Geforce3/Radeon with gl_combine off)
2931 m.tex[2] = R_GetTexture(r_shadow_attenuation2dtexture);
2932 m.texmatrix[2] = rsurface.entitytoattenuationz;
2933 m.pointer_texcoord3f[2] = rsurface.vertex3f;
2934 m.pointer_texcoord_bufferobject[2] = rsurface.vertex3f_bufferobject;
2935 m.pointer_texcoord_bufferoffset[2] = rsurface.vertex3f_bufferoffset;
2938 R_Mesh_TextureState(&m);
2939 //R_Mesh_TexBind(0, R_GetTexture(basetexture));
2940 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorbase, ambientcolorbase);
2943 R_Mesh_TexBind(0, R_GetTexture(pantstexture));
2944 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorpants, ambientcolorpants);
2948 R_Mesh_TexBind(0, R_GetTexture(shirttexture));
2949 R_Shadow_RenderLighting_Light_Vertex_Pass(firstvertex, numvertices, numtriangles, element3i, diffusecolorshirt, ambientcolorshirt);
2953 extern cvar_t gl_lightmaps;
2954 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)
2956 float ambientscale, diffusescale, specularscale;
2957 vec3_t lightcolorbase, lightcolorpants, lightcolorshirt;
2959 // calculate colors to render this texture with
2960 lightcolorbase[0] = rsurface.rtlight->currentcolor[0] * rsurface.texture->dlightcolor[0];
2961 lightcolorbase[1] = rsurface.rtlight->currentcolor[1] * rsurface.texture->dlightcolor[1];
2962 lightcolorbase[2] = rsurface.rtlight->currentcolor[2] * rsurface.texture->dlightcolor[2];
2963 ambientscale = rsurface.rtlight->ambientscale;
2964 diffusescale = rsurface.rtlight->diffusescale;
2965 specularscale = rsurface.rtlight->specularscale * rsurface.texture->specularscale;
2966 if (!r_shadow_usenormalmap.integer)
2968 ambientscale += 1.0f * diffusescale;
2972 if ((ambientscale + diffusescale) * VectorLength2(lightcolorbase) + specularscale * VectorLength2(lightcolorbase) < (1.0f / 1048576.0f))
2974 RSurf_SetupDepthAndCulling();
2975 nmap = rsurface.texture->currentskinframe->nmap;
2976 if (gl_lightmaps.integer)
2977 nmap = r_texture_blanknormalmap;
2978 if (rsurface.texture->colormapping && !gl_lightmaps.integer)
2980 qboolean dopants = rsurface.texture->currentskinframe->pants != NULL && VectorLength2(rsurface.colormap_pantscolor) >= (1.0f / 1048576.0f);
2981 qboolean doshirt = rsurface.texture->currentskinframe->shirt != NULL && VectorLength2(rsurface.colormap_shirtcolor) >= (1.0f / 1048576.0f);
2984 lightcolorpants[0] = lightcolorbase[0] * rsurface.colormap_pantscolor[0];
2985 lightcolorpants[1] = lightcolorbase[1] * rsurface.colormap_pantscolor[1];
2986 lightcolorpants[2] = lightcolorbase[2] * rsurface.colormap_pantscolor[2];
2989 VectorClear(lightcolorpants);
2992 lightcolorshirt[0] = lightcolorbase[0] * rsurface.colormap_shirtcolor[0];
2993 lightcolorshirt[1] = lightcolorbase[1] * rsurface.colormap_shirtcolor[1];
2994 lightcolorshirt[2] = lightcolorbase[2] * rsurface.colormap_shirtcolor[2];
2997 VectorClear(lightcolorshirt);
2998 switch (r_shadow_rendermode)
3000 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
3001 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
3002 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);
3004 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
3005 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);
3007 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
3008 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);
3010 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3011 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);
3014 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
3020 switch (r_shadow_rendermode)
3022 case R_SHADOW_RENDERMODE_VISIBLELIGHTING:
3023 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) && !r_showdisabledepthtest.integer);
3024 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);
3026 case R_SHADOW_RENDERMODE_LIGHT_GLSL:
3027 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);
3029 case R_SHADOW_RENDERMODE_LIGHT_DOT3:
3030 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);
3032 case R_SHADOW_RENDERMODE_LIGHT_VERTEX:
3033 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);
3036 Con_Printf("R_Shadow_RenderLighting: unknown r_shadow_rendermode %i\n", r_shadow_rendermode);
3042 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)
3044 matrix4x4_t tempmatrix = *matrix;
3045 Matrix4x4_Scale(&tempmatrix, r_shadow_lightradiusscale.value, 1);
3047 // if this light has been compiled before, free the associated data
3048 R_RTLight_Uncompile(rtlight);
3050 // clear it completely to avoid any lingering data
3051 memset(rtlight, 0, sizeof(*rtlight));
3053 // copy the properties
3054 rtlight->matrix_lighttoworld = tempmatrix;
3055 Matrix4x4_Invert_Simple(&rtlight->matrix_worldtolight, &tempmatrix);
3056 Matrix4x4_OriginFromMatrix(&tempmatrix, rtlight->shadoworigin);
3057 rtlight->radius = Matrix4x4_ScaleFromMatrix(&tempmatrix);
3058 VectorCopy(color, rtlight->color);
3059 rtlight->cubemapname[0] = 0;
3060 if (cubemapname && cubemapname[0])
3061 strlcpy(rtlight->cubemapname, cubemapname, sizeof(rtlight->cubemapname));
3062 rtlight->shadow = shadow;
3063 rtlight->corona = corona;
3064 rtlight->style = style;
3065 rtlight->isstatic = isstatic;
3066 rtlight->coronasizescale = coronasizescale;
3067 rtlight->ambientscale = ambientscale;
3068 rtlight->diffusescale = diffusescale;
3069 rtlight->specularscale = specularscale;
3070 rtlight->flags = flags;
3072 // compute derived data
3073 //rtlight->cullradius = rtlight->radius;
3074 //rtlight->cullradius2 = rtlight->radius * rtlight->radius;
3075 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3076 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3077 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3078 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3079 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3080 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3083 // compiles rtlight geometry
3084 // (undone by R_FreeCompiledRTLight, which R_UpdateLight calls)
3085 void R_RTLight_Compile(rtlight_t *rtlight)
3088 int numsurfaces, numleafs, numleafpvsbytes, numshadowtrispvsbytes, numlighttrispvsbytes;
3089 int lighttris, shadowtris, shadowzpasstris, shadowzfailtris;
3090 entity_render_t *ent = r_refdef.scene.worldentity;
3091 dp_model_t *model = r_refdef.scene.worldmodel;
3092 unsigned char *data;
3095 // compile the light
3096 rtlight->compiled = true;
3097 rtlight->static_numleafs = 0;
3098 rtlight->static_numleafpvsbytes = 0;
3099 rtlight->static_leaflist = NULL;
3100 rtlight->static_leafpvs = NULL;
3101 rtlight->static_numsurfaces = 0;
3102 rtlight->static_surfacelist = NULL;
3103 rtlight->cullmins[0] = rtlight->shadoworigin[0] - rtlight->radius;
3104 rtlight->cullmins[1] = rtlight->shadoworigin[1] - rtlight->radius;
3105 rtlight->cullmins[2] = rtlight->shadoworigin[2] - rtlight->radius;
3106 rtlight->cullmaxs[0] = rtlight->shadoworigin[0] + rtlight->radius;
3107 rtlight->cullmaxs[1] = rtlight->shadoworigin[1] + rtlight->radius;
3108 rtlight->cullmaxs[2] = rtlight->shadoworigin[2] + rtlight->radius;
3110 if (model && model->GetLightInfo)
3112 // this variable must be set for the CompileShadowVolume code
3113 r_shadow_compilingrtlight = rtlight;
3114 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);
3115 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);
3116 numleafpvsbytes = (model->brush.num_leafs + 7) >> 3;
3117 numshadowtrispvsbytes = ((model->brush.shadowmesh ? model->brush.shadowmesh->numtriangles : model->surfmesh.num_triangles) + 7) >> 3;
3118 numlighttrispvsbytes = (model->surfmesh.num_triangles + 7) >> 3;
3119 data = (unsigned char *)Mem_Alloc(r_main_mempool, sizeof(int) * numsurfaces + sizeof(int) * numleafs + numleafpvsbytes + numshadowtrispvsbytes + numlighttrispvsbytes);
3120 rtlight->static_numsurfaces = numsurfaces;
3121 rtlight->static_surfacelist = (int *)data;data += sizeof(int) * numsurfaces;
3122 rtlight->static_numleafs = numleafs;
3123 rtlight->static_leaflist = (int *)data;data += sizeof(int) * numleafs;
3124 rtlight->static_numleafpvsbytes = numleafpvsbytes;
3125 rtlight->static_leafpvs = (unsigned char *)data;data += numleafpvsbytes;
3126 rtlight->static_numshadowtrispvsbytes = numshadowtrispvsbytes;
3127 rtlight->static_shadowtrispvs = (unsigned char *)data;data += numshadowtrispvsbytes;
3128 rtlight->static_numlighttrispvsbytes = numlighttrispvsbytes;
3129 rtlight->static_lighttrispvs = (unsigned char *)data;data += numlighttrispvsbytes;
3130 if (rtlight->static_numsurfaces)
3131 memcpy(rtlight->static_surfacelist, r_shadow_buffer_surfacelist, rtlight->static_numsurfaces * sizeof(*rtlight->static_surfacelist));
3132 if (rtlight->static_numleafs)
3133 memcpy(rtlight->static_leaflist, r_shadow_buffer_leaflist, rtlight->static_numleafs * sizeof(*rtlight->static_leaflist));
3134 if (rtlight->static_numleafpvsbytes)
3135 memcpy(rtlight->static_leafpvs, r_shadow_buffer_leafpvs, rtlight->static_numleafpvsbytes);
3136 if (rtlight->static_numshadowtrispvsbytes)
3137 memcpy(rtlight->static_shadowtrispvs, r_shadow_buffer_shadowtrispvs, rtlight->static_numshadowtrispvsbytes);
3138 if (rtlight->static_numlighttrispvsbytes)
3139 memcpy(rtlight->static_lighttrispvs, r_shadow_buffer_lighttrispvs, rtlight->static_numlighttrispvsbytes);
3140 if (model->CompileShadowVolume && rtlight->shadow)
3141 model->CompileShadowVolume(ent, rtlight->shadoworigin, NULL, rtlight->radius, numsurfaces, r_shadow_buffer_surfacelist);
3142 // now we're done compiling the rtlight
3143 r_shadow_compilingrtlight = NULL;
3147 // use smallest available cullradius - box radius or light radius
3148 //rtlight->cullradius = RadiusFromBoundsAndOrigin(rtlight->cullmins, rtlight->cullmaxs, rtlight->shadoworigin);
3149 //rtlight->cullradius = min(rtlight->cullradius, rtlight->radius);
3151 shadowzpasstris = 0;
3152 if (rtlight->static_meshchain_shadow_zpass)
3153 for (mesh = rtlight->static_meshchain_shadow_zpass;mesh;mesh = mesh->next)
3154 shadowzpasstris += mesh->numtriangles;
3156 shadowzfailtris = 0;
3157 if (rtlight->static_meshchain_shadow_zfail)
3158 for (mesh = rtlight->static_meshchain_shadow_zfail;mesh;mesh = mesh->next)
3159 shadowzfailtris += mesh->numtriangles;
3162 if (rtlight->static_numlighttrispvsbytes)
3163 for (i = 0;i < rtlight->static_numlighttrispvsbytes*8;i++)
3164 if (CHECKPVSBIT(rtlight->static_lighttrispvs, i))
3168 if (rtlight->static_numlighttrispvsbytes)
3169 for (i = 0;i < rtlight->static_numshadowtrispvsbytes*8;i++)
3170 if (CHECKPVSBIT(rtlight->static_shadowtrispvs, i))
3173 if (developer.integer >= 10)
3174 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);
3177 void R_RTLight_Uncompile(rtlight_t *rtlight)
3179 if (rtlight->compiled)
3181 if (rtlight->static_meshchain_shadow_zpass)
3182 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zpass);
3183 rtlight->static_meshchain_shadow_zpass = NULL;
3184 if (rtlight->static_meshchain_shadow_zfail)
3185 Mod_ShadowMesh_Free(rtlight->static_meshchain_shadow_zfail);
3186 rtlight->static_meshchain_shadow_zfail = NULL;
3187 // these allocations are grouped
3188 if (rtlight->static_surfacelist)
3189 Mem_Free(rtlight->static_surfacelist);
3190 rtlight->static_numleafs = 0;
3191 rtlight->static_numleafpvsbytes = 0;
3192 rtlight->static_leaflist = NULL;
3193 rtlight->static_leafpvs = NULL;
3194 rtlight->static_numsurfaces = 0;
3195 rtlight->static_surfacelist = NULL;
3196 rtlight->static_numshadowtrispvsbytes = 0;
3197 rtlight->static_shadowtrispvs = NULL;
3198 rtlight->static_numlighttrispvsbytes = 0;
3199 rtlight->static_lighttrispvs = NULL;
3200 rtlight->compiled = false;
3204 void R_Shadow_UncompileWorldLights(void)
3208 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3209 for (lightindex = 0;lightindex < range;lightindex++)
3211 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3214 R_RTLight_Uncompile(&light->rtlight);
3218 void R_Shadow_ComputeShadowCasterCullingPlanes(rtlight_t *rtlight)
3222 // reset the count of frustum planes
3223 // see rsurface.rtlight_frustumplanes definition for how much this array
3225 rsurface.rtlight_numfrustumplanes = 0;
3227 // haven't implemented a culling path for ortho rendering
3228 if (!r_refdef.view.useperspective)
3230 // check if the light is on screen and copy the 4 planes if it is
3231 for (i = 0;i < 4;i++)
3232 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3235 for (i = 0;i < 4;i++)
3236 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_refdef.view.frustum[i];
3241 // generate a deformed frustum that includes the light origin, this is
3242 // used to cull shadow casting surfaces that can not possibly cast a
3243 // shadow onto the visible light-receiving surfaces, which can be a
3246 // if the light origin is onscreen the result will be 4 planes exactly
3247 // if the light origin is offscreen on only one axis the result will
3248 // be exactly 5 planes (split-side case)
3249 // if the light origin is offscreen on two axes the result will be
3250 // exactly 4 planes (stretched corner case)
3251 for (i = 0;i < 4;i++)
3253 // quickly reject standard frustum planes that put the light
3254 // origin outside the frustum
3255 if (PlaneDiff(rtlight->shadoworigin, &r_refdef.view.frustum[i]) < -0.03125)
3258 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = r_refdef.view.frustum[i];
3260 // if all the standard frustum planes were accepted, the light is onscreen
3261 // otherwise we need to generate some more planes below...
3262 if (rsurface.rtlight_numfrustumplanes < 4)
3264 // at least one of the stock frustum planes failed, so we need to
3265 // create one or two custom planes to enclose the light origin
3266 for (i = 0;i < 4;i++)
3268 // create a plane using the view origin and light origin, and a
3269 // single point from the frustum corner set
3270 TriangleNormal(r_refdef.view.origin, r_refdef.view.frustumcorner[i], rtlight->shadoworigin, plane.normal);
3271 VectorNormalize(plane.normal);
3272 plane.dist = DotProduct(r_refdef.view.origin, plane.normal);
3273 // see if this plane is backwards and flip it if so
3274 for (j = 0;j < 4;j++)
3275 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3279 VectorNegate(plane.normal, plane.normal);
3281 // flipped plane, test again to see if it is now valid
3282 for (j = 0;j < 4;j++)
3283 if (j != i && DotProduct(r_refdef.view.frustumcorner[j], plane.normal) - plane.dist < -0.03125)
3285 // if the plane is still not valid, then it is dividing the
3286 // frustum and has to be rejected
3290 // we have created a valid plane, compute extra info
3291 PlaneClassify(&plane);
3293 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3295 // if we've found 5 frustum planes then we have constructed a
3296 // proper split-side case and do not need to keep searching for
3297 // planes to enclose the light origin
3298 if (rsurface.rtlight_numfrustumplanes == 5)
3306 for (i = 0;i < rsurface.rtlight_numfrustumplanes;i++)
3308 plane = rsurface.rtlight_frustumplanes[i];
3309 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));
3314 // now add the light-space box planes if the light box is rotated, as any
3315 // caster outside the oriented light box is irrelevant (even if it passed
3316 // the worldspace light box, which is axial)
3317 if (rtlight->matrix_lighttoworld.m[0][0] != 1 || rtlight->matrix_lighttoworld.m[1][1] != 1 || rtlight->matrix_lighttoworld.m[2][2] != 1)
3319 for (i = 0;i < 6;i++)
3323 v[i >> 1] = (i & 1) ? -1 : 1;
3324 Matrix4x4_Transform(&rtlight->matrix_lighttoworld, v, plane.normal);
3325 VectorSubtract(plane.normal, rtlight->shadoworigin, plane.normal);
3326 plane.dist = VectorNormalizeLength(plane.normal);
3327 plane.dist += DotProduct(plane.normal, rtlight->shadoworigin);
3328 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3334 // add the world-space reduced box planes
3335 for (i = 0;i < 6;i++)
3337 VectorClear(plane.normal);
3338 plane.normal[i >> 1] = (i & 1) ? -1 : 1;
3339 plane.dist = (i & 1) ? -rsurface.rtlight_cullmaxs[i >> 1] : rsurface.rtlight_cullmins[i >> 1];
3340 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = plane;
3349 // reduce all plane distances to tightly fit the rtlight cull box, which
3351 VectorSet(points[0], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
3352 VectorSet(points[1], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmins[2]);
3353 VectorSet(points[2], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
3354 VectorSet(points[3], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmins[2]);
3355 VectorSet(points[4], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
3356 VectorSet(points[5], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmins[1], rsurface.rtlight_cullmaxs[2]);
3357 VectorSet(points[6], rsurface.rtlight_cullmins[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
3358 VectorSet(points[7], rsurface.rtlight_cullmaxs[0], rsurface.rtlight_cullmaxs[1], rsurface.rtlight_cullmaxs[2]);
3359 oldnum = rsurface.rtlight_numfrustumplanes;
3360 rsurface.rtlight_numfrustumplanes = 0;
3361 for (j = 0;j < oldnum;j++)
3363 // find the nearest point on the box to this plane
3364 bestdist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[0]);
3365 for (i = 1;i < 8;i++)
3367 dist = DotProduct(rsurface.rtlight_frustumplanes[j].normal, points[i]);
3368 if (bestdist > dist)
3371 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);
3372 // if the nearest point is near or behind the plane, we want this
3373 // plane, otherwise the plane is useless as it won't cull anything
3374 if (rsurface.rtlight_frustumplanes[j].dist < bestdist + 0.03125)
3376 PlaneClassify(&rsurface.rtlight_frustumplanes[j]);
3377 rsurface.rtlight_frustumplanes[rsurface.rtlight_numfrustumplanes++] = rsurface.rtlight_frustumplanes[j];
3384 void R_Shadow_DrawWorldShadow(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3389 int surfacelistindex;
3390 msurface_t *surface;
3392 RSurf_ActiveWorldEntity();
3393 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D)
3395 if (r_refdef.scene.worldentity->model)
3396 r_refdef.scene.worldmodel->DrawShadowMap(r_refdef.scene.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs);
3397 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3401 if (rsurface.rtlight->compiled && r_shadow_realtime_world_compile.integer && r_shadow_realtime_world_compileshadow.integer)
3404 zpass = R_Shadow_UseZPass(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
3405 R_Shadow_RenderMode_StencilShadowVolumes(zpass);
3406 mesh = zpass ? rsurface.rtlight->static_meshchain_shadow_zpass : rsurface.rtlight->static_meshchain_shadow_zfail;
3407 for (;mesh;mesh = mesh->next)
3409 r_refdef.stats.lights_shadowtriangles += mesh->numtriangles;
3410 R_Mesh_VertexPointer(mesh->vertex3f, mesh->vbo, mesh->vbooffset_vertex3f);
3411 GL_LockArrays(0, mesh->numverts);
3412 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZPASS_STENCIL)
3414 // increment stencil if frontface is infront of depthbuffer
3415 GL_CullFace(r_refdef.view.cullface_back);
3416 qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);CHECKGLERROR
3417 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3418 // decrement stencil if backface is infront of depthbuffer
3419 GL_CullFace(r_refdef.view.cullface_front);
3420 qglStencilOp(GL_KEEP, GL_KEEP, GL_DECR);CHECKGLERROR
3422 else if (r_shadow_rendermode == R_SHADOW_RENDERMODE_ZFAIL_STENCIL)
3424 // decrement stencil if backface is behind depthbuffer
3425 GL_CullFace(r_refdef.view.cullface_front);
3426 qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP);CHECKGLERROR
3427 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3428 // increment stencil if frontface is behind depthbuffer
3429 GL_CullFace(r_refdef.view.cullface_back);
3430 qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP);CHECKGLERROR
3432 R_Mesh_Draw(0, mesh->numverts, 0, mesh->numtriangles, mesh->element3i, mesh->element3s, mesh->ebo3i, mesh->ebo3s);
3433 GL_LockArrays(0, 0);
3437 else if (numsurfaces && r_refdef.scene.worldmodel->brush.shadowmesh && r_shadow_culltriangles.integer)
3439 R_Shadow_PrepareShadowMark(r_refdef.scene.worldmodel->brush.shadowmesh->numtriangles);
3440 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
3442 surface = r_refdef.scene.worldmodel->data_surfaces + surfacelist[surfacelistindex];
3443 for (t = surface->num_firstshadowmeshtriangle, tend = t + surface->num_triangles;t < tend;t++)
3444 if (CHECKPVSBIT(trispvs, t))
3445 shadowmarklist[numshadowmark++] = t;
3447 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);
3449 else if (numsurfaces)
3450 r_refdef.scene.worldmodel->DrawShadowVolume(r_refdef.scene.worldentity, rsurface.rtlight->shadoworigin, NULL, rsurface.rtlight->radius, numsurfaces, surfacelist, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs);
3452 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3455 void R_Shadow_DrawEntityShadow(entity_render_t *ent)
3457 vec3_t relativeshadoworigin, relativeshadowmins, relativeshadowmaxs;
3458 vec_t relativeshadowradius;
3459 RSurf_ActiveModelEntity(ent, false, false);
3460 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, relativeshadoworigin);
3461 relativeshadowradius = rsurface.rtlight->radius / ent->scale;
3462 relativeshadowmins[0] = relativeshadoworigin[0] - relativeshadowradius;
3463 relativeshadowmins[1] = relativeshadoworigin[1] - relativeshadowradius;
3464 relativeshadowmins[2] = relativeshadoworigin[2] - relativeshadowradius;
3465 relativeshadowmaxs[0] = relativeshadoworigin[0] + relativeshadowradius;
3466 relativeshadowmaxs[1] = relativeshadoworigin[1] + relativeshadowradius;
3467 relativeshadowmaxs[2] = relativeshadoworigin[2] + relativeshadowradius;
3468 if (r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPRECTANGLE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAPCUBESIDE || r_shadow_rendermode == R_SHADOW_RENDERMODE_SHADOWMAP2D)
3469 ent->model->DrawShadowMap(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3471 ent->model->DrawShadowVolume(ent, relativeshadoworigin, NULL, relativeshadowradius, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
3472 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3475 void R_Shadow_SetupEntityLight(const entity_render_t *ent)
3477 // set up properties for rendering light onto this entity
3478 RSurf_ActiveModelEntity(ent, true, true);
3479 GL_AlphaTest(false);
3480 Matrix4x4_Concat(&rsurface.entitytolight, &rsurface.rtlight->matrix_worldtolight, &ent->matrix);
3481 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3482 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3483 Matrix4x4_Transform(&ent->inversematrix, rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3484 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
3485 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
3488 void R_Shadow_DrawWorldLight(int numsurfaces, int *surfacelist, const unsigned char *trispvs)
3490 if (!r_refdef.scene.worldmodel->DrawLight)
3493 // set up properties for rendering light onto this entity
3494 RSurf_ActiveWorldEntity();
3495 GL_AlphaTest(false);
3496 rsurface.entitytolight = rsurface.rtlight->matrix_worldtolight;
3497 Matrix4x4_Concat(&rsurface.entitytoattenuationxyz, &matrix_attenuationxyz, &rsurface.entitytolight);
3498 Matrix4x4_Concat(&rsurface.entitytoattenuationz, &matrix_attenuationz, &rsurface.entitytolight);
3499 VectorCopy(rsurface.rtlight->shadoworigin, rsurface.entitylightorigin);
3500 if (r_shadow_lightingrendermode == R_SHADOW_RENDERMODE_LIGHT_GLSL)
3501 R_Mesh_TexMatrix(3, &rsurface.entitytolight);
3503 r_refdef.scene.worldmodel->DrawLight(r_refdef.scene.worldentity, numsurfaces, surfacelist, trispvs);
3505 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3508 void R_Shadow_DrawEntityLight(entity_render_t *ent)
3510 dp_model_t *model = ent->model;
3511 if (!model->DrawLight)
3514 R_Shadow_SetupEntityLight(ent);
3516 model->DrawLight(ent, model->nummodelsurfaces, model->sortedmodelsurfaces, NULL);
3518 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
3522 {{ 0, 0, 0}, "px", true, true, true},
3523 {{ 0, 90, 0}, "py", false, true, false},
3524 {{ 0, 180, 0}, "nx", false, false, true},
3525 {{ 0, 270, 0}, "ny", true, false, false},
3526 {{-90, 180, 0}, "pz", false, false, true},
3527 {{ 90, 180, 0}, "nz", false, false, true}
3530 static const double shadowviewmat16[6][4][4] =
3570 void R_DrawRTLight(rtlight_t *rtlight, qboolean visible)
3574 int numleafs, numsurfaces;
3575 int *leaflist, *surfacelist;
3576 unsigned char *leafpvs, *shadowtrispvs, *lighttrispvs;
3577 int numlightentities;
3578 int numlightentities_noselfshadow;
3579 int numshadowentities;
3580 int numshadowentities_noselfshadow;
3581 static entity_render_t *lightentities[MAX_EDICTS];
3582 static entity_render_t *lightentities_noselfshadow[MAX_EDICTS];
3583 static entity_render_t *shadowentities[MAX_EDICTS];
3584 static entity_render_t *shadowentities_noselfshadow[MAX_EDICTS];
3585 vec3_t nearestpoint;
3587 qboolean castshadows;
3590 // skip lights that don't light because of ambientscale+diffusescale+specularscale being 0 (corona only lights)
3591 // skip lights that are basically invisible (color 0 0 0)
3592 if (VectorLength2(rtlight->color) * (rtlight->ambientscale + rtlight->diffusescale + rtlight->specularscale) < (1.0f / 1048576.0f))
3595 // loading is done before visibility checks because loading should happen
3596 // all at once at the start of a level, not when it stalls gameplay.
3597 // (especially important to benchmarks)
3599 if (rtlight->isstatic && !rtlight->compiled && r_shadow_realtime_world_compile.integer)
3600 R_RTLight_Compile(rtlight);
3602 rtlight->currentcubemap = rtlight->cubemapname[0] ? R_Shadow_Cubemap(rtlight->cubemapname) : r_texture_whitecube;
3604 // look up the light style value at this time
3605 f = (rtlight->style >= 0 ? r_refdef.scene.rtlightstylevalue[rtlight->style] : 1) * r_shadow_lightintensityscale.value;
3606 VectorScale(rtlight->color, f, rtlight->currentcolor);
3608 if (rtlight->selected)
3610 f = 2 + sin(realtime * M_PI * 4.0);
3611 VectorScale(rtlight->currentcolor, f, rtlight->currentcolor);
3615 // if lightstyle is currently off, don't draw the light
3616 if (VectorLength2(rtlight->currentcolor) < (1.0f / 1048576.0f))
3619 // if the light box is offscreen, skip it
3620 if (R_CullBox(rtlight->cullmins, rtlight->cullmaxs))
3623 VectorCopy(rtlight->cullmins, rsurface.rtlight_cullmins);
3624 VectorCopy(rtlight->cullmaxs, rsurface.rtlight_cullmaxs);
3626 if (rtlight->compiled && r_shadow_realtime_world_compile.integer)
3628 // compiled light, world available and can receive realtime lighting
3629 // retrieve leaf information
3630 numleafs = rtlight->static_numleafs;
3631 leaflist = rtlight->static_leaflist;
3632 leafpvs = rtlight->static_leafpvs;
3633 numsurfaces = rtlight->static_numsurfaces;
3634 surfacelist = rtlight->static_surfacelist;
3635 shadowtrispvs = rtlight->static_shadowtrispvs;
3636 lighttrispvs = rtlight->static_lighttrispvs;
3638 else if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->GetLightInfo)
3640 // dynamic light, world available and can receive realtime lighting
3641 // calculate lit surfaces and leafs
3642 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);
3643 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);
3644 leaflist = r_shadow_buffer_leaflist;
3645 leafpvs = r_shadow_buffer_leafpvs;
3646 surfacelist = r_shadow_buffer_surfacelist;
3647 shadowtrispvs = r_shadow_buffer_shadowtrispvs;
3648 lighttrispvs = r_shadow_buffer_lighttrispvs;
3649 // if the reduced leaf bounds are offscreen, skip it
3650 if (R_CullBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
3661 shadowtrispvs = NULL;
3662 lighttrispvs = NULL;
3664 // check if light is illuminating any visible leafs
3667 for (i = 0;i < numleafs;i++)
3668 if (r_refdef.viewcache.world_leafvisible[leaflist[i]])
3673 // set up a scissor rectangle for this light
3674 if (R_Shadow_ScissorForBBox(rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
3677 R_Shadow_ComputeShadowCasterCullingPlanes(rtlight);
3679 // make a list of lit entities and shadow casting entities
3680 numlightentities = 0;
3681 numlightentities_noselfshadow = 0;
3682 numshadowentities = 0;
3683 numshadowentities_noselfshadow = 0;
3684 // add dynamic entities that are lit by the light
3685 if (r_drawentities.integer)
3687 for (i = 0;i < r_refdef.scene.numentities;i++)
3690 entity_render_t *ent = r_refdef.scene.entities[i];
3692 if (!BoxesOverlap(ent->mins, ent->maxs, rsurface.rtlight_cullmins, rsurface.rtlight_cullmaxs))
3694 // skip the object entirely if it is not within the valid
3695 // shadow-casting region (which includes the lit region)
3696 if (R_CullBoxCustomPlanes(ent->mins, ent->maxs, rsurface.rtlight_numfrustumplanes, rsurface.rtlight_frustumplanes))
3698 if (!(model = ent->model))
3700 if (r_refdef.viewcache.entityvisible[i] && model->DrawLight && (ent->flags & RENDER_LIGHT))
3702 // this entity wants to receive light, is visible, and is
3703 // inside the light box
3704 // TODO: check if the surfaces in the model can receive light
3705 // so now check if it's in a leaf seen by the light
3706 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))
3708 if (ent->flags & RENDER_NOSELFSHADOW)
3709 lightentities_noselfshadow[numlightentities_noselfshadow++] = ent;
3711 lightentities[numlightentities++] = ent;
3712 // since it is lit, it probably also casts a shadow...
3713 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3714 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3715 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3717 // note: exterior models without the RENDER_NOSELFSHADOW
3718 // flag still create a RENDER_NOSELFSHADOW shadow but
3719 // are lit normally, this means that they are
3720 // self-shadowing but do not shadow other
3721 // RENDER_NOSELFSHADOW entities such as the gun
3722 // (very weird, but keeps the player shadow off the gun)
3723 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3724 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3726 shadowentities[numshadowentities++] = ent;
3729 else if (ent->flags & RENDER_SHADOW)
3731 // this entity is not receiving light, but may still need to
3733 // TODO: check if the surfaces in the model can cast shadow
3734 // now check if it is in a leaf seen by the light
3735 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))
3737 // about the VectorDistance2 - light emitting entities should not cast their own shadow
3738 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3739 if ((ent->flags & RENDER_SHADOW) && model->DrawShadowVolume && VectorDistance2(org, rtlight->shadoworigin) > 0.1)
3741 if (ent->flags & (RENDER_NOSELFSHADOW | RENDER_EXTERIORMODEL))
3742 shadowentities_noselfshadow[numshadowentities_noselfshadow++] = ent;
3744 shadowentities[numshadowentities++] = ent;
3750 // return if there's nothing at all to light
3751 if (!numlightentities && !numsurfaces)
3754 // don't let sound skip if going slow
3755 if (r_refdef.scene.extraupdate)
3758 // make this the active rtlight for rendering purposes
3759 R_Shadow_RenderMode_ActiveLight(rtlight);
3760 // count this light in the r_speeds
3761 r_refdef.stats.lights++;
3763 if (r_showshadowvolumes.integer && r_refdef.view.showdebug && numsurfaces + numshadowentities + numshadowentities_noselfshadow && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows))
3765 // optionally draw visible shape of the shadow volumes
3766 // for performance analysis by level designers
3767 R_Shadow_RenderMode_VisibleShadowVolumes();
3769 R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
3770 for (i = 0;i < numshadowentities;i++)
3771 R_Shadow_DrawEntityShadow(shadowentities[i]);
3772 for (i = 0;i < numshadowentities_noselfshadow;i++)
3773 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3776 if (r_showlighting.integer && r_refdef.view.showdebug && numsurfaces + numlightentities + numlightentities_noselfshadow)
3778 // optionally draw the illuminated areas
3779 // for performance analysis by level designers
3780 R_Shadow_RenderMode_VisibleLighting(false, false);
3782 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3783 for (i = 0;i < numlightentities;i++)
3784 R_Shadow_DrawEntityLight(lightentities[i]);
3785 for (i = 0;i < numlightentities_noselfshadow;i++)
3786 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3789 castshadows = numsurfaces + numshadowentities + numshadowentities_noselfshadow > 0 && rtlight->shadow && (rtlight->isstatic ? r_refdef.scene.rtworldshadows : r_refdef.scene.rtdlightshadows);
3791 nearestpoint[0] = bound(rtlight->cullmins[0], r_refdef.view.origin[0], rtlight->cullmaxs[0]);
3792 nearestpoint[1] = bound(rtlight->cullmins[1], r_refdef.view.origin[1], rtlight->cullmaxs[1]);
3793 nearestpoint[2] = bound(rtlight->cullmins[2], r_refdef.view.origin[2], rtlight->cullmaxs[2]);
3794 distance = VectorDistance(nearestpoint, r_refdef.view.origin);
3795 lodlinear = (int)(r_shadow_shadowmapping_lod_bias.value + r_shadow_shadowmapping_lod_scale.value * rtlight->radius / max(1.0f, distance));
3796 lodlinear = bound(r_shadow_shadowmapping_minsize.integer, lodlinear, r_shadow_shadowmapping_maxsize.integer);
3798 if (castshadows && r_shadow_shadowmode >= 1 && r_shadow_shadowmode <= 3 && r_glsl.integer && gl_support_fragment_shader)
3803 r_shadow_shadowmaplod = 0;
3804 for (i = 1;i < R_SHADOW_SHADOWMAP_NUMCUBEMAPS;i++)
3805 if ((r_shadow_shadowmapping_maxsize.integer >> i) > lodlinear)
3806 r_shadow_shadowmaplod = i;
3808 size = r_shadow_shadowmode == 3 ? r_shadow_shadowmapping_maxsize.integer >> r_shadow_shadowmaplod : lodlinear;
3809 size = bound(1, size, 2048);
3811 //Con_Printf("distance %f lodlinear %i (lod %i) size %i\n", distance, lodlinear, r_shadow_shadowmaplod, size);
3813 // render shadow casters into 6 sided depth texture
3814 for (side = 0;side < 6;side++)
3816 R_Shadow_RenderMode_ShadowMap(side, true, size);
3818 R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
3819 for (i = 0;i < numshadowentities;i++)
3820 R_Shadow_DrawEntityShadow(shadowentities[i]);
3823 if (numlightentities_noselfshadow)
3825 // render lighting using the depth texture as shadowmap
3826 // draw lighting in the unmasked areas
3827 R_Shadow_RenderMode_Lighting(false, false, true);
3828 for (i = 0;i < numlightentities_noselfshadow;i++)
3829 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3832 // render shadow casters into 6 sided depth texture
3833 for (side = 0;side < 6;side++)
3835 R_Shadow_RenderMode_ShadowMap(side, false, size);
3836 for (i = 0;i < numshadowentities_noselfshadow;i++)
3837 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3840 // render lighting using the depth texture as shadowmap
3841 // draw lighting in the unmasked areas
3842 R_Shadow_RenderMode_Lighting(false, false, true);
3843 // draw lighting in the unmasked areas
3845 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3846 for (i = 0;i < numlightentities;i++)
3847 R_Shadow_DrawEntityLight(lightentities[i]);
3849 else if (castshadows && gl_stencil)
3851 // draw stencil shadow volumes to mask off pixels that are in shadow
3852 // so that they won't receive lighting
3853 GL_Scissor(r_shadow_lightscissor[0], r_shadow_lightscissor[1], r_shadow_lightscissor[2], r_shadow_lightscissor[3]);
3854 R_Shadow_ClearStencil();
3856 R_Shadow_DrawWorldShadow(numsurfaces, surfacelist, shadowtrispvs);
3857 for (i = 0;i < numshadowentities;i++)
3858 R_Shadow_DrawEntityShadow(shadowentities[i]);
3859 if (numlightentities_noselfshadow)
3861 // draw lighting in the unmasked areas
3862 R_Shadow_RenderMode_Lighting(true, false, false);
3863 for (i = 0;i < numlightentities_noselfshadow;i++)
3864 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3866 // optionally draw the illuminated areas
3867 // for performance analysis by level designers
3868 if (r_showlighting.integer && r_refdef.view.showdebug)
3870 R_Shadow_RenderMode_VisibleLighting(!r_showdisabledepthtest.integer, false);
3871 for (i = 0;i < numlightentities_noselfshadow;i++)
3872 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3875 for (i = 0;i < numshadowentities_noselfshadow;i++)
3876 R_Shadow_DrawEntityShadow(shadowentities_noselfshadow[i]);
3878 if (numsurfaces + numlightentities)
3880 // draw lighting in the unmasked areas
3881 R_Shadow_RenderMode_Lighting(true, false, false);
3883 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3884 for (i = 0;i < numlightentities;i++)
3885 R_Shadow_DrawEntityLight(lightentities[i]);
3890 if (numsurfaces + numlightentities)
3892 // draw lighting in the unmasked areas
3893 R_Shadow_RenderMode_Lighting(false, false, false);
3895 R_Shadow_DrawWorldLight(numsurfaces, surfacelist, lighttrispvs);
3896 for (i = 0;i < numlightentities;i++)
3897 R_Shadow_DrawEntityLight(lightentities[i]);
3898 for (i = 0;i < numlightentities_noselfshadow;i++)
3899 R_Shadow_DrawEntityLight(lightentities_noselfshadow[i]);
3904 void R_Shadow_DrawLightSprites(void);
3905 void R_ShadowVolumeLighting(qboolean visible)
3913 if (r_shadow_shadowmapmaxsize != bound(1, r_shadow_shadowmapping_maxsize.integer, 2048) ||
3914 (r_shadow_shadowmode != 0) != (r_shadow_shadowmapping.integer != 0) ||
3915 r_shadow_shadowmapvsdct != (r_shadow_shadowmapping_vsdct.integer != 0) ||
3916 r_shadow_shadowmaptexturetype != r_shadow_shadowmapping_texturetype.integer ||
3917 r_shadow_shadowmapfilterquality != r_shadow_shadowmapping_filterquality.integer ||
3918 r_shadow_shadowmapborder != bound(0, r_shadow_shadowmapping_bordersize.integer, 16))
3919 R_Shadow_FreeShadowMaps();
3921 if (r_editlights.integer)
3922 R_Shadow_DrawLightSprites();
3924 R_Shadow_RenderMode_Begin();
3926 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
3927 if (r_shadow_debuglight.integer >= 0)
3929 lightindex = r_shadow_debuglight.integer;
3930 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3931 if (light && (light->flags & flag))
3932 R_DrawRTLight(&light->rtlight, visible);
3936 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
3937 for (lightindex = 0;lightindex < range;lightindex++)
3939 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
3940 if (light && (light->flags & flag))
3941 R_DrawRTLight(&light->rtlight, visible);
3944 if (r_refdef.scene.rtdlight)
3945 for (lnum = 0;lnum < r_refdef.scene.numlights;lnum++)
3946 R_DrawRTLight(r_refdef.scene.lights[lnum], visible);
3948 R_Shadow_RenderMode_End();
3951 extern const float r_screenvertex3f[12];
3952 extern void R_SetupView(qboolean allowwaterclippingplane);
3953 extern void R_ResetViewRendering3D(void);
3954 extern void R_ResetViewRendering2D(void);
3955 extern cvar_t r_shadows;
3956 extern cvar_t r_shadows_darken;
3957 extern cvar_t r_shadows_drawafterrtlighting;
3958 extern cvar_t r_shadows_castfrombmodels;
3959 extern cvar_t r_shadows_throwdistance;
3960 extern cvar_t r_shadows_throwdirection;
3961 void R_DrawModelShadows(void)
3964 float relativethrowdistance;
3965 entity_render_t *ent;
3966 vec3_t relativelightorigin;
3967 vec3_t relativelightdirection;
3968 vec3_t relativeshadowmins, relativeshadowmaxs;
3969 vec3_t tmp, shadowdir;
3971 if (!r_drawentities.integer || !gl_stencil)
3975 R_ResetViewRendering3D();
3976 //GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
3977 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
3978 R_Shadow_RenderMode_Begin();
3979 R_Shadow_RenderMode_ActiveLight(NULL);
3980 r_shadow_lightscissor[0] = r_refdef.view.x;
3981 r_shadow_lightscissor[1] = vid.height - r_refdef.view.y - r_refdef.view.height;
3982 r_shadow_lightscissor[2] = r_refdef.view.width;
3983 r_shadow_lightscissor[3] = r_refdef.view.height;
3984 R_Shadow_RenderMode_StencilShadowVolumes(false);
3987 if (r_shadows.integer == 2)
3989 Math_atov(r_shadows_throwdirection.string, shadowdir);
3990 VectorNormalize(shadowdir);
3993 R_Shadow_ClearStencil();
3995 for (i = 0;i < r_refdef.scene.numentities;i++)
3997 ent = r_refdef.scene.entities[i];
3999 // cast shadows from anything of the map (submodels are optional)
4000 if (ent->model && ent->model->DrawShadowVolume != NULL && (!ent->model->brush.submodel || r_shadows_castfrombmodels.integer) && (ent->flags & RENDER_SHADOW))
4002 relativethrowdistance = r_shadows_throwdistance.value * Matrix4x4_ScaleFromMatrix(&ent->inversematrix);
4003 VectorSet(relativeshadowmins, -relativethrowdistance, -relativethrowdistance, -relativethrowdistance);
4004 VectorSet(relativeshadowmaxs, relativethrowdistance, relativethrowdistance, relativethrowdistance);
4005 if (r_shadows.integer == 2) // 2: simpler mode, throw shadows always in same direction
4006 Matrix4x4_Transform3x3(&ent->inversematrix, shadowdir, relativelightdirection);
4009 if(ent->entitynumber != 0)
4011 // networked entity - might be attached in some way (then we should use the parent's light direction, to not tear apart attached entities)
4012 int entnum, entnum2, recursion;
4013 entnum = entnum2 = ent->entitynumber;
4014 for(recursion = 32; recursion > 0; --recursion)
4016 entnum2 = cl.entities[entnum].state_current.tagentity;
4017 if(entnum2 >= 1 && entnum2 < cl.num_entities && cl.entities_active[entnum2])
4022 if(recursion && recursion != 32) // if we followed a valid non-empty attachment chain
4024 VectorNegate(cl.entities[entnum].render.modellight_lightdir, relativelightdirection);
4025 // transform into modelspace of OUR entity
4026 Matrix4x4_Transform3x3(&cl.entities[entnum].render.matrix, relativelightdirection, tmp);
4027 Matrix4x4_Transform3x3(&ent->inversematrix, tmp, relativelightdirection);
4030 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4033 VectorNegate(ent->modellight_lightdir, relativelightdirection);
4036 VectorScale(relativelightdirection, -relativethrowdistance, relativelightorigin);
4037 RSurf_ActiveModelEntity(ent, false, false);
4038 ent->model->DrawShadowVolume(ent, relativelightorigin, relativelightdirection, relativethrowdistance, ent->model->nummodelsurfaces, ent->model->sortedmodelsurfaces, relativeshadowmins, relativeshadowmaxs);
4039 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4043 // not really the right mode, but this will disable any silly stencil features
4044 R_Shadow_RenderMode_End();
4046 // set up ortho view for rendering this pass
4047 //GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.height - r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4048 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4049 //GL_ScissorTest(true);
4050 //R_Mesh_Matrix(&identitymatrix);
4051 //R_Mesh_ResetTextureState();
4052 R_ResetViewRendering2D();
4053 R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
4054 R_Mesh_ColorPointer(NULL, 0, 0);
4055 R_SetupGenericShader(false);
4057 // set up a darkening blend on shadowed areas
4058 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4059 //GL_DepthRange(0, 1);
4060 //GL_DepthTest(false);
4061 //GL_DepthMask(false);
4062 //GL_PolygonOffset(0, 0);CHECKGLERROR
4063 GL_Color(0, 0, 0, r_shadows_darken.value);
4064 //GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4065 //qglDepthFunc(GL_ALWAYS);CHECKGLERROR
4066 qglEnable(GL_STENCIL_TEST);CHECKGLERROR
4067 qglStencilMask(~0);CHECKGLERROR
4068 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
4069 qglStencilFunc(GL_NOTEQUAL, 128, ~0);CHECKGLERROR
4071 // apply the blend to the shadowed areas
4072 R_Mesh_Draw(0, 4, 0, 2, NULL, polygonelements, 0, 0);
4074 // restore the viewport
4075 R_SetViewport(&r_refdef.view.viewport);
4077 // restore other state to normal
4078 //R_Shadow_RenderMode_End();
4081 void R_BeginCoronaQuery(rtlight_t *rtlight, float scale, qboolean usequery)
4084 vec3_t centerorigin;
4085 // if it's too close, skip it
4086 if (VectorLength(rtlight->color) < (1.0f / 256.0f))
4088 zdist = (DotProduct(rtlight->shadoworigin, r_refdef.view.forward) - DotProduct(r_refdef.view.origin, r_refdef.view.forward));
4091 if (usequery && r_numqueries + 2 <= r_maxqueries)
4093 rtlight->corona_queryindex_allpixels = r_queries[r_numqueries++];
4094 rtlight->corona_queryindex_visiblepixels = r_queries[r_numqueries++];
4095 VectorMA(r_refdef.view.origin, zdist, r_refdef.view.forward, centerorigin);
4098 // 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
4099 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_allpixels);
4100 qglDepthFunc(GL_ALWAYS);
4101 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);
4102 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4103 qglDepthFunc(GL_LEQUAL);
4104 qglBeginQueryARB(GL_SAMPLES_PASSED_ARB, rtlight->corona_queryindex_visiblepixels);
4105 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);
4106 qglEndQueryARB(GL_SAMPLES_PASSED_ARB);
4109 rtlight->corona_visibility = bound(0, (zdist - 32) / 32, 1);
4112 void R_DrawCorona(rtlight_t *rtlight, float cscale, float scale)
4115 GLint allpixels = 0, visiblepixels = 0;
4116 // now we have to check the query result
4117 if (rtlight->corona_queryindex_visiblepixels)
4120 qglGetQueryObjectivARB(rtlight->corona_queryindex_visiblepixels, GL_QUERY_RESULT_ARB, &visiblepixels);
4121 qglGetQueryObjectivARB(rtlight->corona_queryindex_allpixels, GL_QUERY_RESULT_ARB, &allpixels);
4123 //Con_Printf("%i of %i pixels\n", (int)visiblepixels, (int)allpixels);
4124 if (visiblepixels < 1 || allpixels < 1)
4126 rtlight->corona_visibility *= bound(0, (float)visiblepixels / (float)allpixels, 1);
4127 cscale *= rtlight->corona_visibility;
4131 // FIXME: these traces should scan all render entities instead of cl.world
4132 if (CL_Move(r_refdef.view.origin, vec3_origin, vec3_origin, rtlight->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction < 1)
4135 VectorScale(rtlight->color, cscale, color);
4136 if (VectorLength(color) > (1.0f / 256.0f))
4137 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);
4140 void R_DrawCoronas(void)
4148 if (r_coronas.value < (1.0f / 256.0f) && !gl_flashblend.integer)
4150 if (r_waterstate.renderingscene)
4152 flag = r_refdef.scene.rtworld ? LIGHTFLAG_REALTIMEMODE : LIGHTFLAG_NORMALMODE;
4153 R_Mesh_Matrix(&identitymatrix);
4155 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4157 // check occlusion of coronas
4158 // use GL_ARB_occlusion_query if available
4159 // otherwise use raytraces
4161 usequery = gl_support_arb_occlusion_query && r_coronas_occlusionquery.integer;
4164 GL_ColorMask(0,0,0,0);
4165 if (r_maxqueries < (range + r_refdef.scene.numlights) * 2)
4166 if (r_maxqueries < R_MAX_OCCLUSION_QUERIES)
4169 r_maxqueries = (range + r_refdef.scene.numlights) * 4;
4170 r_maxqueries = min(r_maxqueries, R_MAX_OCCLUSION_QUERIES);
4172 qglGenQueriesARB(r_maxqueries - i, r_queries + i);
4176 for (lightindex = 0;lightindex < range;lightindex++)
4178 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4181 rtlight = &light->rtlight;
4182 rtlight->corona_visibility = 0;
4183 rtlight->corona_queryindex_visiblepixels = 0;
4184 rtlight->corona_queryindex_allpixels = 0;
4185 if (!(rtlight->flags & flag))
4187 if (rtlight->corona <= 0)
4189 if (r_shadow_debuglight.integer >= 0 && r_shadow_debuglight.integer != (int)lightindex)
4191 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4193 for (i = 0;i < r_refdef.scene.numlights;i++)
4195 rtlight = r_refdef.scene.lights[i];
4196 rtlight->corona_visibility = 0;
4197 rtlight->corona_queryindex_visiblepixels = 0;
4198 rtlight->corona_queryindex_allpixels = 0;
4199 if (!(rtlight->flags & flag))
4201 if (rtlight->corona <= 0)
4203 R_BeginCoronaQuery(rtlight, rtlight->radius * rtlight->coronasizescale * r_coronas_occlusionsizescale.value, usequery);
4206 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4208 // now draw the coronas using the query data for intensity info
4209 for (lightindex = 0;lightindex < range;lightindex++)
4211 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4214 rtlight = &light->rtlight;
4215 if (rtlight->corona_visibility <= 0)
4217 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4219 for (i = 0;i < r_refdef.scene.numlights;i++)
4221 rtlight = r_refdef.scene.lights[i];
4222 if (rtlight->corona_visibility <= 0)
4224 if (gl_flashblend.integer)
4225 R_DrawCorona(rtlight, rtlight->corona, rtlight->radius * rtlight->coronasizescale * 2.0f);
4227 R_DrawCorona(rtlight, rtlight->corona * r_coronas.value * 0.25f, rtlight->radius * rtlight->coronasizescale);
4233 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
4234 typedef struct suffixinfo_s
4237 qboolean flipx, flipy, flipdiagonal;
4240 static suffixinfo_t suffix[3][6] =
4243 {"px", false, false, false},
4244 {"nx", false, false, false},
4245 {"py", false, false, false},
4246 {"ny", false, false, false},
4247 {"pz", false, false, false},
4248 {"nz", false, false, false}
4251 {"posx", false, false, false},
4252 {"negx", false, false, false},
4253 {"posy", false, false, false},
4254 {"negy", false, false, false},
4255 {"posz", false, false, false},
4256 {"negz", false, false, false}
4259 {"rt", true, false, true},
4260 {"lf", false, true, true},
4261 {"ft", true, true, false},
4262 {"bk", false, false, false},
4263 {"up", true, false, true},
4264 {"dn", true, false, true}
4268 static int componentorder[4] = {0, 1, 2, 3};
4270 rtexture_t *R_Shadow_LoadCubemap(const char *basename)
4272 int i, j, cubemapsize;
4273 unsigned char *cubemappixels, *image_buffer;
4274 rtexture_t *cubemaptexture;
4276 // must start 0 so the first loadimagepixels has no requested width/height
4278 cubemappixels = NULL;
4279 cubemaptexture = NULL;
4280 // keep trying different suffix groups (posx, px, rt) until one loads
4281 for (j = 0;j < 3 && !cubemappixels;j++)
4283 // load the 6 images in the suffix group
4284 for (i = 0;i < 6;i++)
4286 // generate an image name based on the base and and suffix
4287 dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
4289 if ((image_buffer = loadimagepixelsbgra(name, false, false)))
4291 // an image loaded, make sure width and height are equal
4292 if (image_width == image_height && (!cubemappixels || image_width == cubemapsize))
4294 // if this is the first image to load successfully, allocate the cubemap memory
4295 if (!cubemappixels && image_width >= 1)
4297 cubemapsize = image_width;
4298 // note this clears to black, so unavailable sides are black
4299 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
4301 // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
4303 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);
4306 Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
4308 Mem_Free(image_buffer);
4312 // if a cubemap loaded, upload it
4315 if (developer_loading.integer)
4316 Con_Printf("loading cubemap \"%s\"\n", basename);
4318 if (!r_shadow_filters_texturepool)
4319 r_shadow_filters_texturepool = R_AllocTexturePool();
4320 cubemaptexture = R_LoadTextureCubeMap(r_shadow_filters_texturepool, basename, cubemapsize, cubemappixels, TEXTYPE_BGRA, TEXF_PRECACHE | (gl_texturecompression_lightcubemaps.integer ? TEXF_COMPRESS : 0) | TEXF_FORCELINEAR, NULL);
4321 Mem_Free(cubemappixels);
4325 Con_DPrintf("failed to load cubemap \"%s\"\n", basename);
4326 if (developer_loading.integer)
4328 Con_Printf("(tried tried images ");
4329 for (j = 0;j < 3;j++)
4330 for (i = 0;i < 6;i++)
4331 Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
4332 Con_Print(" and was unable to find any of them).\n");
4335 return cubemaptexture;
4338 rtexture_t *R_Shadow_Cubemap(const char *basename)
4341 for (i = 0;i < numcubemaps;i++)
4342 if (!strcasecmp(cubemaps[i].basename, basename))
4343 return cubemaps[i].texture ? cubemaps[i].texture : r_texture_whitecube;
4344 if (i >= MAX_CUBEMAPS)
4345 return r_texture_whitecube;
4347 strlcpy(cubemaps[i].basename, basename, sizeof(cubemaps[i].basename));
4348 cubemaps[i].texture = R_Shadow_LoadCubemap(cubemaps[i].basename);
4349 return cubemaps[i].texture;
4352 void R_Shadow_FreeCubemaps(void)
4355 for (i = 0;i < numcubemaps;i++)
4357 if (developer_loading.integer)
4358 Con_Printf("unloading cubemap \"%s\"\n", cubemaps[i].basename);
4359 if (cubemaps[i].texture)
4360 R_FreeTexture(cubemaps[i].texture);
4364 R_FreeTexturePool(&r_shadow_filters_texturepool);
4367 dlight_t *R_Shadow_NewWorldLight(void)
4369 return (dlight_t *)Mem_ExpandableArray_AllocRecord(&r_shadow_worldlightsarray);
4372 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)
4375 // validate parameters
4376 if (style < 0 || style >= MAX_LIGHTSTYLES)
4378 Con_Printf("R_Shadow_NewWorldLight: invalid light style number %i, must be >= 0 and < %i\n", light->style, MAX_LIGHTSTYLES);
4384 // copy to light properties
4385 VectorCopy(origin, light->origin);
4386 light->angles[0] = angles[0] - 360 * floor(angles[0] / 360);
4387 light->angles[1] = angles[1] - 360 * floor(angles[1] / 360);
4388 light->angles[2] = angles[2] - 360 * floor(angles[2] / 360);
4389 light->color[0] = max(color[0], 0);
4390 light->color[1] = max(color[1], 0);
4391 light->color[2] = max(color[2], 0);
4392 light->radius = max(radius, 0);
4393 light->style = style;
4394 light->shadow = shadowenable;
4395 light->corona = corona;
4396 strlcpy(light->cubemapname, cubemapname, sizeof(light->cubemapname));
4397 light->coronasizescale = coronasizescale;
4398 light->ambientscale = ambientscale;
4399 light->diffusescale = diffusescale;
4400 light->specularscale = specularscale;
4401 light->flags = flags;
4403 // update renderable light data
4404 Matrix4x4_CreateFromQuakeEntity(&matrix, light->origin[0], light->origin[1], light->origin[2], light->angles[0], light->angles[1], light->angles[2], light->radius);
4405 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);
4408 void R_Shadow_FreeWorldLight(dlight_t *light)
4410 if (r_shadow_selectedlight == light)
4411 r_shadow_selectedlight = NULL;
4412 R_RTLight_Uncompile(&light->rtlight);
4413 Mem_ExpandableArray_FreeRecord(&r_shadow_worldlightsarray, light);
4416 void R_Shadow_ClearWorldLights(void)
4420 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4421 for (lightindex = 0;lightindex < range;lightindex++)
4423 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4425 R_Shadow_FreeWorldLight(light);
4427 r_shadow_selectedlight = NULL;
4428 R_Shadow_FreeCubemaps();
4431 void R_Shadow_SelectLight(dlight_t *light)
4433 if (r_shadow_selectedlight)
4434 r_shadow_selectedlight->selected = false;
4435 r_shadow_selectedlight = light;
4436 if (r_shadow_selectedlight)
4437 r_shadow_selectedlight->selected = true;
4440 void R_Shadow_DrawCursor_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4442 // this is never batched (there can be only one)
4443 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);
4446 void R_Shadow_DrawLightSprite_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4453 // this is never batched (due to the ent parameter changing every time)
4454 // so numsurfaces == 1 and surfacelist[0] == lightnumber
4455 const dlight_t *light = (dlight_t *)ent;
4458 VectorScale(light->color, intensity, spritecolor);
4459 if (VectorLength(spritecolor) < 0.1732f)
4460 VectorSet(spritecolor, 0.1f, 0.1f, 0.1f);
4461 if (VectorLength(spritecolor) > 1.0f)
4462 VectorNormalize(spritecolor);
4464 // draw light sprite
4465 if (light->cubemapname[0] && !light->shadow)
4466 pic = r_editlights_sprcubemapnoshadowlight;
4467 else if (light->cubemapname[0])
4468 pic = r_editlights_sprcubemaplight;
4469 else if (!light->shadow)
4470 pic = r_editlights_sprnoshadowlight;
4472 pic = r_editlights_sprlight;
4473 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);
4474 // draw selection sprite if light is selected
4475 if (light->selected)
4476 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);
4477 // VorteX todo: add normalmode/realtime mode light overlay sprites?
4480 void R_Shadow_DrawLightSprites(void)
4484 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4485 for (lightindex = 0;lightindex < range;lightindex++)
4487 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4489 R_MeshQueue_AddTransparent(light->origin, R_Shadow_DrawLightSprite_TransparentCallback, (entity_render_t *)light, 5, &light->rtlight);
4491 R_MeshQueue_AddTransparent(r_editlights_cursorlocation, R_Shadow_DrawCursor_TransparentCallback, NULL, 0, NULL);
4494 void R_Shadow_SelectLightInView(void)
4496 float bestrating, rating, temp[3];
4500 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
4503 for (lightindex = 0;lightindex < range;lightindex++)
4505 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4508 VectorSubtract(light->origin, r_refdef.view.origin, temp);
4509 rating = (DotProduct(temp, r_refdef.view.forward) / sqrt(DotProduct(temp, temp)));
4512 rating /= (1 + 0.0625f * sqrt(DotProduct(temp, temp)));
4513 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)
4515 bestrating = rating;
4520 R_Shadow_SelectLight(best);
4523 void R_Shadow_LoadWorldLights(void)
4525 int n, a, style, shadow, flags;
4526 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH], cubemapname[MAX_QPATH];
4527 float origin[3], radius, color[3], angles[3], corona, coronasizescale, ambientscale, diffusescale, specularscale;
4528 if (cl.worldmodel == NULL)
4530 Con_Print("No map loaded.\n");
4533 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4534 strlcat (name, ".rtlights", sizeof (name));
4535 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4545 for (;COM_Parse(t, true) && strcmp(
4546 if (COM_Parse(t, true))
4548 if (com_token[0] == '!')
4551 origin[0] = atof(com_token+1);
4554 origin[0] = atof(com_token);
4559 while (*s && *s != '\n' && *s != '\r')
4565 // check for modifier flags
4572 #if _MSC_VER >= 1400
4573 #define sscanf sscanf_s
4575 cubemapname[sizeof(cubemapname)-1] = 0;
4576 #if MAX_QPATH != 128
4577 #error update this code if MAX_QPATH changes
4579 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
4580 #if _MSC_VER >= 1400
4581 , sizeof(cubemapname)
4583 , &corona, &angles[0], &angles[1], &angles[2], &coronasizescale, &ambientscale, &diffusescale, &specularscale, &flags);
4586 flags = LIGHTFLAG_REALTIMEMODE;
4594 coronasizescale = 0.25f;
4596 VectorClear(angles);
4599 if (a < 9 || !strcmp(cubemapname, "\"\""))
4601 // remove quotes on cubemapname
4602 if (cubemapname[0] == '"' && cubemapname[strlen(cubemapname) - 1] == '"')
4605 namelen = strlen(cubemapname) - 2;
4606 memmove(cubemapname, cubemapname + 1, namelen);
4607 cubemapname[namelen] = '\0';
4611 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);
4614 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, angles, color, radius, corona, style, shadow, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
4622 Con_Printf("invalid rtlights file \"%s\"\n", name);
4623 Mem_Free(lightsstring);
4627 void R_Shadow_SaveWorldLights(void)
4631 size_t bufchars, bufmaxchars;
4633 char name[MAX_QPATH];
4634 char line[MAX_INPUTLINE];
4635 size_t range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked, assuming the dpsnprintf mess doesn't screw it up...
4636 // I hate lines which are 3 times my screen size :( --blub
4639 if (cl.worldmodel == NULL)
4641 Con_Print("No map loaded.\n");
4644 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4645 strlcat (name, ".rtlights", sizeof (name));
4646 bufchars = bufmaxchars = 0;
4648 for (lightindex = 0;lightindex < range;lightindex++)
4650 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
4653 if (light->coronasizescale != 0.25f || light->ambientscale != 0 || light->diffusescale != 1 || light->specularscale != 1 || light->flags != LIGHTFLAG_REALTIMEMODE)
4654 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);
4655 else if (light->cubemapname[0] || light->corona || light->angles[0] || light->angles[1] || light->angles[2])
4656 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]);
4658 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);
4659 if (bufchars + strlen(line) > bufmaxchars)
4661 bufmaxchars = bufchars + strlen(line) + 2048;
4663 buf = (char *)Mem_Alloc(tempmempool, bufmaxchars);
4667 memcpy(buf, oldbuf, bufchars);
4673 memcpy(buf + bufchars, line, strlen(line));
4674 bufchars += strlen(line);
4678 FS_WriteFile(name, buf, (fs_offset_t)bufchars);
4683 void R_Shadow_LoadLightsFile(void)
4686 char tempchar, *lightsstring, *s, *t, name[MAX_QPATH];
4687 float origin[3], radius, color[3], subtract, spotdir[3], spotcone, falloff, distbias;
4688 if (cl.worldmodel == NULL)
4690 Con_Print("No map loaded.\n");
4693 FS_StripExtension (cl.worldmodel->name, name, sizeof (name));
4694 strlcat (name, ".lights", sizeof (name));
4695 lightsstring = (char *)FS_LoadFile(name, tempmempool, false, NULL);
4703 while (*s && *s != '\n' && *s != '\r')
4709 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);
4713 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);
4716 radius = sqrt(DotProduct(color, color) / (falloff * falloff * 8192.0f * 8192.0f));
4717 radius = bound(15, radius, 4096);
4718 VectorScale(color, (2.0f / (8388608.0f)), color);
4719 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), origin, vec3_origin, color, radius, 0, style, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
4727 Con_Printf("invalid lights file \"%s\"\n", name);
4728 Mem_Free(lightsstring);
4732 // tyrlite/hmap2 light types in the delay field
4733 typedef enum lighttype_e {LIGHTTYPE_MINUSX, LIGHTTYPE_RECIPX, LIGHTTYPE_RECIPXX, LIGHTTYPE_NONE, LIGHTTYPE_SUN, LIGHTTYPE_MINUSXX} lighttype_t;
4735 void R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite(void)
4737 int entnum, style, islight, skin, pflags, effects, type, n;
4740 float origin[3], angles[3], radius, color[3], light[4], fadescale, lightscale, originhack[3], overridecolor[3], vec[4];
4741 char key[256], value[MAX_INPUTLINE];
4743 if (cl.worldmodel == NULL)
4745 Con_Print("No map loaded.\n");
4748 // try to load a .ent file first
4749 FS_StripExtension (cl.worldmodel->name, key, sizeof (key));
4750 strlcat (key, ".ent", sizeof (key));
4751 data = entfiledata = (char *)FS_LoadFile(key, tempmempool, true, NULL);
4752 // and if that is not found, fall back to the bsp file entity string
4754 data = cl.worldmodel->brush.entities;
4757 for (entnum = 0;COM_ParseToken_Simple(&data, false, false) && com_token[0] == '{';entnum++)
4759 type = LIGHTTYPE_MINUSX;
4760 origin[0] = origin[1] = origin[2] = 0;
4761 originhack[0] = originhack[1] = originhack[2] = 0;
4762 angles[0] = angles[1] = angles[2] = 0;
4763 color[0] = color[1] = color[2] = 1;
4764 light[0] = light[1] = light[2] = 1;light[3] = 300;
4765 overridecolor[0] = overridecolor[1] = overridecolor[2] = 1;
4775 if (!COM_ParseToken_Simple(&data, false, false))
4777 if (com_token[0] == '}')
4778 break; // end of entity
4779 if (com_token[0] == '_')
4780 strlcpy(key, com_token + 1, sizeof(key));
4782 strlcpy(key, com_token, sizeof(key));
4783 while (key[strlen(key)-1] == ' ') // remove trailing spaces
4784 key[strlen(key)-1] = 0;
4785 if (!COM_ParseToken_Simple(&data, false, false))
4787 strlcpy(value, com_token, sizeof(value));
4789 // now that we have the key pair worked out...
4790 if (!strcmp("light", key))
4792 n = sscanf(value, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
4796 light[0] = vec[0] * (1.0f / 256.0f);
4797 light[1] = vec[0] * (1.0f / 256.0f);
4798 light[2] = vec[0] * (1.0f / 256.0f);
4804 light[0] = vec[0] * (1.0f / 255.0f);
4805 light[1] = vec[1] * (1.0f / 255.0f);
4806 light[2] = vec[2] * (1.0f / 255.0f);
4810 else if (!strcmp("delay", key))
4812 else if (!strcmp("origin", key))
4813 sscanf(value, "%f %f %f", &origin[0], &origin[1], &origin[2]);
4814 else if (!strcmp("angle", key))
4815 angles[0] = 0, angles[1] = atof(value), angles[2] = 0;
4816 else if (!strcmp("angles", key))
4817 sscanf(value, "%f %f %f", &angles[0], &angles[1], &angles[2]);
4818 else if (!strcmp("color", key))
4819 sscanf(value, "%f %f %f", &color[0], &color[1], &color[2]);
4820 else if (!strcmp("wait", key))
4821 fadescale = atof(value);
4822 else if (!strcmp("classname", key))
4824 if (!strncmp(value, "light", 5))
4827 if (!strcmp(value, "light_fluoro"))
4832 overridecolor[0] = 1;
4833 overridecolor[1] = 1;
4834 overridecolor[2] = 1;
4836 if (!strcmp(value, "light_fluorospark"))
4841 overridecolor[0] = 1;
4842 overridecolor[1] = 1;
4843 overridecolor[2] = 1;
4845 if (!strcmp(value, "light_globe"))
4850 overridecolor[0] = 1;
4851 overridecolor[1] = 0.8;
4852 overridecolor[2] = 0.4;
4854 if (!strcmp(value, "light_flame_large_yellow"))
4859 overridecolor[0] = 1;
4860 overridecolor[1] = 0.5;
4861 overridecolor[2] = 0.1;
4863 if (!strcmp(value, "light_flame_small_yellow"))
4868 overridecolor[0] = 1;
4869 overridecolor[1] = 0.5;
4870 overridecolor[2] = 0.1;
4872 if (!strcmp(value, "light_torch_small_white"))
4877 overridecolor[0] = 1;
4878 overridecolor[1] = 0.5;
4879 overridecolor[2] = 0.1;
4881 if (!strcmp(value, "light_torch_small_walltorch"))
4886 overridecolor[0] = 1;
4887 overridecolor[1] = 0.5;
4888 overridecolor[2] = 0.1;
4892 else if (!strcmp("style", key))
4893 style = atoi(value);
4894 else if (!strcmp("skin", key))
4895 skin = (int)atof(value);
4896 else if (!strcmp("pflags", key))
4897 pflags = (int)atof(value);
4898 else if (!strcmp("effects", key))
4899 effects = (int)atof(value);
4900 else if (cl.worldmodel->type == mod_brushq3)
4902 if (!strcmp("scale", key))
4903 lightscale = atof(value);
4904 if (!strcmp("fade", key))
4905 fadescale = atof(value);
4910 if (lightscale <= 0)
4914 if (color[0] == color[1] && color[0] == color[2])
4916 color[0] *= overridecolor[0];
4917 color[1] *= overridecolor[1];
4918 color[2] *= overridecolor[2];
4920 radius = light[3] * r_editlights_quakelightsizescale.value * lightscale / fadescale;
4921 color[0] = color[0] * light[0];
4922 color[1] = color[1] * light[1];
4923 color[2] = color[2] * light[2];
4926 case LIGHTTYPE_MINUSX:
4928 case LIGHTTYPE_RECIPX:
4930 VectorScale(color, (1.0f / 16.0f), color);
4932 case LIGHTTYPE_RECIPXX:
4934 VectorScale(color, (1.0f / 16.0f), color);
4937 case LIGHTTYPE_NONE:
4941 case LIGHTTYPE_MINUSXX:
4944 VectorAdd(origin, originhack, origin);
4946 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);
4949 Mem_Free(entfiledata);
4953 void R_Shadow_SetCursorLocationForView(void)
4956 vec3_t dest, endpos;
4958 VectorMA(r_refdef.view.origin, r_editlights_cursordistance.value, r_refdef.view.forward, dest);
4959 trace = CL_Move(r_refdef.view.origin, vec3_origin, vec3_origin, dest, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false);
4960 if (trace.fraction < 1)
4962 dist = trace.fraction * r_editlights_cursordistance.value;
4963 push = r_editlights_cursorpushback.value;
4967 VectorMA(trace.endpos, push, r_refdef.view.forward, endpos);
4968 VectorMA(endpos, r_editlights_cursorpushoff.value, trace.plane.normal, endpos);
4972 VectorClear( endpos );
4974 r_editlights_cursorlocation[0] = floor(endpos[0] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
4975 r_editlights_cursorlocation[1] = floor(endpos[1] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
4976 r_editlights_cursorlocation[2] = floor(endpos[2] / r_editlights_cursorgrid.value + 0.5f) * r_editlights_cursorgrid.value;
4979 void R_Shadow_UpdateWorldLightSelection(void)
4981 if (r_editlights.integer)
4983 R_Shadow_SetCursorLocationForView();
4984 R_Shadow_SelectLightInView();
4987 R_Shadow_SelectLight(NULL);
4990 void R_Shadow_EditLights_Clear_f(void)
4992 R_Shadow_ClearWorldLights();
4995 void R_Shadow_EditLights_Reload_f(void)
4999 strlcpy(r_shadow_mapname, cl.worldmodel->name, sizeof(r_shadow_mapname));
5000 R_Shadow_ClearWorldLights();
5001 R_Shadow_LoadWorldLights();
5002 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5004 R_Shadow_LoadLightsFile();
5005 if (!Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray))
5006 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5010 void R_Shadow_EditLights_Save_f(void)
5014 R_Shadow_SaveWorldLights();
5017 void R_Shadow_EditLights_ImportLightEntitiesFromMap_f(void)
5019 R_Shadow_ClearWorldLights();
5020 R_Shadow_LoadWorldLightsFromMap_LightArghliteTyrlite();
5023 void R_Shadow_EditLights_ImportLightsFile_f(void)
5025 R_Shadow_ClearWorldLights();
5026 R_Shadow_LoadLightsFile();
5029 void R_Shadow_EditLights_Spawn_f(void)
5032 if (!r_editlights.integer)
5034 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5037 if (Cmd_Argc() != 1)
5039 Con_Print("r_editlights_spawn does not take parameters\n");
5042 color[0] = color[1] = color[2] = 1;
5043 R_Shadow_UpdateWorldLight(R_Shadow_NewWorldLight(), r_editlights_cursorlocation, vec3_origin, color, 200, 0, 0, true, NULL, 0.25, 0, 1, 1, LIGHTFLAG_REALTIMEMODE);
5046 void R_Shadow_EditLights_Edit_f(void)
5048 vec3_t origin, angles, color;
5049 vec_t radius, corona, coronasizescale, ambientscale, diffusescale, specularscale;
5050 int style, shadows, flags, normalmode, realtimemode;
5051 char cubemapname[MAX_INPUTLINE];
5052 if (!r_editlights.integer)
5054 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5057 if (!r_shadow_selectedlight)
5059 Con_Print("No selected light.\n");
5062 VectorCopy(r_shadow_selectedlight->origin, origin);
5063 VectorCopy(r_shadow_selectedlight->angles, angles);
5064 VectorCopy(r_shadow_selectedlight->color, color);
5065 radius = r_shadow_selectedlight->radius;
5066 style = r_shadow_selectedlight->style;
5067 if (r_shadow_selectedlight->cubemapname)
5068 strlcpy(cubemapname, r_shadow_selectedlight->cubemapname, sizeof(cubemapname));
5071 shadows = r_shadow_selectedlight->shadow;
5072 corona = r_shadow_selectedlight->corona;
5073 coronasizescale = r_shadow_selectedlight->coronasizescale;
5074 ambientscale = r_shadow_selectedlight->ambientscale;
5075 diffusescale = r_shadow_selectedlight->diffusescale;
5076 specularscale = r_shadow_selectedlight->specularscale;
5077 flags = r_shadow_selectedlight->flags;
5078 normalmode = (flags & LIGHTFLAG_NORMALMODE) != 0;
5079 realtimemode = (flags & LIGHTFLAG_REALTIMEMODE) != 0;
5080 if (!strcmp(Cmd_Argv(1), "origin"))
5082 if (Cmd_Argc() != 5)
5084 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5087 origin[0] = atof(Cmd_Argv(2));
5088 origin[1] = atof(Cmd_Argv(3));
5089 origin[2] = atof(Cmd_Argv(4));
5091 else if (!strcmp(Cmd_Argv(1), "originx"))
5093 if (Cmd_Argc() != 3)
5095 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5098 origin[0] = atof(Cmd_Argv(2));
5100 else if (!strcmp(Cmd_Argv(1), "originy"))
5102 if (Cmd_Argc() != 3)
5104 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5107 origin[1] = atof(Cmd_Argv(2));
5109 else if (!strcmp(Cmd_Argv(1), "originz"))
5111 if (Cmd_Argc() != 3)
5113 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5116 origin[2] = atof(Cmd_Argv(2));
5118 else if (!strcmp(Cmd_Argv(1), "move"))
5120 if (Cmd_Argc() != 5)
5122 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5125 origin[0] += atof(Cmd_Argv(2));
5126 origin[1] += atof(Cmd_Argv(3));
5127 origin[2] += atof(Cmd_Argv(4));
5129 else if (!strcmp(Cmd_Argv(1), "movex"))
5131 if (Cmd_Argc() != 3)
5133 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5136 origin[0] += atof(Cmd_Argv(2));
5138 else if (!strcmp(Cmd_Argv(1), "movey"))
5140 if (Cmd_Argc() != 3)
5142 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5145 origin[1] += atof(Cmd_Argv(2));
5147 else if (!strcmp(Cmd_Argv(1), "movez"))
5149 if (Cmd_Argc() != 3)
5151 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5154 origin[2] += atof(Cmd_Argv(2));
5156 else if (!strcmp(Cmd_Argv(1), "angles"))
5158 if (Cmd_Argc() != 5)
5160 Con_Printf("usage: r_editlights_edit %s x y z\n", Cmd_Argv(1));
5163 angles[0] = atof(Cmd_Argv(2));
5164 angles[1] = atof(Cmd_Argv(3));
5165 angles[2] = atof(Cmd_Argv(4));
5167 else if (!strcmp(Cmd_Argv(1), "anglesx"))
5169 if (Cmd_Argc() != 3)
5171 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5174 angles[0] = atof(Cmd_Argv(2));
5176 else if (!strcmp(Cmd_Argv(1), "anglesy"))
5178 if (Cmd_Argc() != 3)
5180 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5183 angles[1] = atof(Cmd_Argv(2));
5185 else if (!strcmp(Cmd_Argv(1), "anglesz"))
5187 if (Cmd_Argc() != 3)
5189 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5192 angles[2] = atof(Cmd_Argv(2));
5194 else if (!strcmp(Cmd_Argv(1), "color"))
5196 if (Cmd_Argc() != 5)
5198 Con_Printf("usage: r_editlights_edit %s red green blue\n", Cmd_Argv(1));
5201 color[0] = atof(Cmd_Argv(2));
5202 color[1] = atof(Cmd_Argv(3));
5203 color[2] = atof(Cmd_Argv(4));
5205 else if (!strcmp(Cmd_Argv(1), "radius"))
5207 if (Cmd_Argc() != 3)
5209 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5212 radius = atof(Cmd_Argv(2));
5214 else if (!strcmp(Cmd_Argv(1), "colorscale"))
5216 if (Cmd_Argc() == 3)
5218 double scale = atof(Cmd_Argv(2));
5225 if (Cmd_Argc() != 5)
5227 Con_Printf("usage: r_editlights_edit %s red green blue (OR grey instead of red green blue)\n", Cmd_Argv(1));
5230 color[0] *= atof(Cmd_Argv(2));
5231 color[1] *= atof(Cmd_Argv(3));
5232 color[2] *= atof(Cmd_Argv(4));
5235 else if (!strcmp(Cmd_Argv(1), "radiusscale") || !strcmp(Cmd_Argv(1), "sizescale"))
5237 if (Cmd_Argc() != 3)
5239 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5242 radius *= atof(Cmd_Argv(2));
5244 else if (!strcmp(Cmd_Argv(1), "style"))
5246 if (Cmd_Argc() != 3)
5248 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5251 style = atoi(Cmd_Argv(2));
5253 else if (!strcmp(Cmd_Argv(1), "cubemap"))
5257 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5260 if (Cmd_Argc() == 3)
5261 strlcpy(cubemapname, Cmd_Argv(2), sizeof(cubemapname));
5265 else if (!strcmp(Cmd_Argv(1), "shadows"))
5267 if (Cmd_Argc() != 3)
5269 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5272 shadows = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5274 else if (!strcmp(Cmd_Argv(1), "corona"))
5276 if (Cmd_Argc() != 3)
5278 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5281 corona = atof(Cmd_Argv(2));
5283 else if (!strcmp(Cmd_Argv(1), "coronasize"))
5285 if (Cmd_Argc() != 3)
5287 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5290 coronasizescale = atof(Cmd_Argv(2));
5292 else if (!strcmp(Cmd_Argv(1), "ambient"))
5294 if (Cmd_Argc() != 3)
5296 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5299 ambientscale = atof(Cmd_Argv(2));
5301 else if (!strcmp(Cmd_Argv(1), "diffuse"))
5303 if (Cmd_Argc() != 3)
5305 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5308 diffusescale = atof(Cmd_Argv(2));
5310 else if (!strcmp(Cmd_Argv(1), "specular"))
5312 if (Cmd_Argc() != 3)
5314 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5317 specularscale = atof(Cmd_Argv(2));
5319 else if (!strcmp(Cmd_Argv(1), "normalmode"))
5321 if (Cmd_Argc() != 3)
5323 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5326 normalmode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5328 else if (!strcmp(Cmd_Argv(1), "realtimemode"))
5330 if (Cmd_Argc() != 3)
5332 Con_Printf("usage: r_editlights_edit %s value\n", Cmd_Argv(1));
5335 realtimemode = Cmd_Argv(2)[0] == 'y' || Cmd_Argv(2)[0] == 'Y' || Cmd_Argv(2)[0] == 't' || atoi(Cmd_Argv(2));
5339 Con_Print("usage: r_editlights_edit [property] [value]\n");
5340 Con_Print("Selected light's properties:\n");
5341 Con_Printf("Origin : %f %f %f\n", r_shadow_selectedlight->origin[0], r_shadow_selectedlight->origin[1], r_shadow_selectedlight->origin[2]);
5342 Con_Printf("Angles : %f %f %f\n", r_shadow_selectedlight->angles[0], r_shadow_selectedlight->angles[1], r_shadow_selectedlight->angles[2]);
5343 Con_Printf("Color : %f %f %f\n", r_shadow_selectedlight->color[0], r_shadow_selectedlight->color[1], r_shadow_selectedlight->color[2]);
5344 Con_Printf("Radius : %f\n", r_shadow_selectedlight->radius);
5345 Con_Printf("Corona : %f\n", r_shadow_selectedlight->corona);
5346 Con_Printf("Style : %i\n", r_shadow_selectedlight->style);
5347 Con_Printf("Shadows : %s\n", r_shadow_selectedlight->shadow ? "yes" : "no");
5348 Con_Printf("Cubemap : %s\n", r_shadow_selectedlight->cubemapname);
5349 Con_Printf("CoronaSize : %f\n", r_shadow_selectedlight->coronasizescale);
5350 Con_Printf("Ambient : %f\n", r_shadow_selectedlight->ambientscale);
5351 Con_Printf("Diffuse : %f\n", r_shadow_selectedlight->diffusescale);
5352 Con_Printf("Specular : %f\n", r_shadow_selectedlight->specularscale);
5353 Con_Printf("NormalMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_NORMALMODE) ? "yes" : "no");
5354 Con_Printf("RealTimeMode : %s\n", (r_shadow_selectedlight->flags & LIGHTFLAG_REALTIMEMODE) ? "yes" : "no");
5357 flags = (normalmode ? LIGHTFLAG_NORMALMODE : 0) | (realtimemode ? LIGHTFLAG_REALTIMEMODE : 0);
5358 R_Shadow_UpdateWorldLight(r_shadow_selectedlight, origin, angles, color, radius, corona, style, shadows, cubemapname, coronasizescale, ambientscale, diffusescale, specularscale, flags);
5361 void R_Shadow_EditLights_EditAll_f(void)
5367 if (!r_editlights.integer)
5369 Con_Print("Cannot edit lights when not in editing mode. Set r_editlights to 1.\n");
5373 // EditLights doesn't seem to have a "remove" command or something so:
5374 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5375 for (lightindex = 0;lightindex < range;lightindex++)
5377 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5380 R_Shadow_SelectLight(light);
5381 R_Shadow_EditLights_Edit_f();
5385 void R_Shadow_EditLights_DrawSelectedLightProperties(void)
5387 int lightnumber, lightcount;
5388 size_t lightindex, range;
5392 if (!r_editlights.integer)
5394 x = vid_conwidth.value - 240;
5396 DrawQ_Pic(x-5, y-5, NULL, 250, 155, 0, 0, 0, 0.75, 0);
5399 range = Mem_ExpandableArray_IndexRange(&r_shadow_worldlightsarray); // checked
5400 for (lightindex = 0;lightindex < range;lightindex++)
5402 light = (dlight_t *) Mem_ExpandableArray_RecordAtIndex(&r_shadow_worldlightsarray, lightindex);
5405 if (light == r_shadow_selectedlight)
5406 lightnumber = lightindex;
5409 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;
5410 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;
5412 if (r_shadow_selectedlight == NULL)
5414 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;
5415 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;
5416 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;
5417 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;
5418 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;
5419 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;
5420 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;
5421 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;
5422 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;
5423 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;
5424 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;
5425 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;
5426 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;
5427 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;
5428 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;
5431 void R_Shadow_EditLights_ToggleShadow_f(void)
5433 if (!r_editlights.integer)
5435 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5438 if (!r_shadow_selectedlight)
5440 Con_Print("No selected light.\n");
5443 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);
5446 void R_Shadow_EditLights_ToggleCorona_f(void)
5448 if (!r_editlights.integer)
5450 Con_Print("Cannot spawn light when not in editing mode. Set r_editlights to 1.\n");
5453 if (!r_shadow_selectedlight)
5455 Con_Print("No selected light.\n");
5458 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);
5461 void R_Shadow_EditLights_Remove_f(void)
5463 if (!r_editlights.integer)
5465 Con_Print("Cannot remove light when not in editing mode. Set r_editlights to 1.\n");
5468 if (!r_shadow_selectedlight)
5470 Con_Print("No selected light.\n");
5473 R_Shadow_FreeWorldLight(r_shadow_selectedlight);
5474 r_shadow_selectedlight = NULL;
5477 void R_Shadow_EditLights_Help_f(void)
5480 "Documentation on r_editlights system:\n"
5482 "r_editlights : enable/disable editing mode\n"
5483 "r_editlights_cursordistance : maximum distance of cursor from eye\n"
5484 "r_editlights_cursorpushback : push back cursor this far from surface\n"
5485 "r_editlights_cursorpushoff : push cursor off surface this far\n"
5486 "r_editlights_cursorgrid : snap cursor to grid of this size\n"
5487 "r_editlights_quakelightsizescale : imported quake light entity size scaling\n"
5489 "r_editlights_help : this help\n"
5490 "r_editlights_clear : remove all lights\n"
5491 "r_editlights_reload : reload .rtlights, .lights file, or entities\n"
5492 "r_editlights_save : save to .rtlights file\n"
5493 "r_editlights_spawn : create a light with default settings\n"
5494 "r_editlights_edit command : edit selected light - more documentation below\n"
5495 "r_editlights_remove : remove selected light\n"
5496 "r_editlights_toggleshadow : toggles on/off selected light's shadow property\n"
5497 "r_editlights_importlightentitiesfrommap : reload light entities\n"
5498 "r_editlights_importlightsfile : reload .light file (produced by hlight)\n"
5500 "origin x y z : set light location\n"
5501 "originx x: set x component of light location\n"
5502 "originy y: set y component of light location\n"
5503 "originz z: set z component of light location\n"
5504 "move x y z : adjust light location\n"
5505 "movex x: adjust x component of light location\n"
5506 "movey y: adjust y component of light location\n"
5507 "movez z: adjust z component of light location\n"
5508 "angles x y z : set light angles\n"
5509 "anglesx x: set x component of light angles\n"
5510 "anglesy y: set y component of light angles\n"
5511 "anglesz z: set z component of light angles\n"
5512 "color r g b : set color of light (can be brighter than 1 1 1)\n"
5513 "radius radius : set radius (size) of light\n"
5514 "colorscale grey : multiply color of light (1 does nothing)\n"
5515 "colorscale r g b : multiply color of light (1 1 1 does nothing)\n"
5516 "radiusscale scale : multiply radius (size) of light (1 does nothing)\n"
5517 "sizescale scale : multiply radius (size) of light (1 does nothing)\n"
5518 "style style : set lightstyle of light (flickering patterns, switches, etc)\n"
5519 "cubemap basename : set filter cubemap of light (not yet supported)\n"
5520 "shadows 1/0 : turn on/off shadows\n"
5521 "corona n : set corona intensity\n"
5522 "coronasize n : set corona size (0-1)\n"
5523 "ambient n : set ambient intensity (0-1)\n"
5524 "diffuse n : set diffuse intensity (0-1)\n"
5525 "specular n : set specular intensity (0-1)\n"
5526 "normalmode 1/0 : turn on/off rendering of this light in rtworld 0 mode\n"
5527 "realtimemode 1/0 : turn on/off rendering of this light in rtworld 1 mode\n"
5528 "<nothing> : print light properties to console\n"
5532 void R_Shadow_EditLights_CopyInfo_f(void)
5534 if (!r_editlights.integer)
5536 Con_Print("Cannot copy light info when not in editing mode. Set r_editlights to 1.\n");
5539 if (!r_shadow_selectedlight)
5541 Con_Print("No selected light.\n");
5544 VectorCopy(r_shadow_selectedlight->angles, r_shadow_bufferlight.angles);
5545 VectorCopy(r_shadow_selectedlight->color, r_shadow_bufferlight.color);
5546 r_shadow_bufferlight.radius = r_shadow_selectedlight->radius;
5547 r_shadow_bufferlight.style = r_shadow_selectedlight->style;
5548 if (r_shadow_selectedlight->cubemapname)
5549 strlcpy(r_shadow_bufferlight.cubemapname, r_shadow_selectedlight->cubemapname, sizeof(r_shadow_bufferlight.cubemapname));
5551 r_shadow_bufferlight.cubemapname[0] = 0;
5552 r_shadow_bufferlight.shadow = r_shadow_selectedlight->shadow;
5553 r_shadow_bufferlight.corona = r_shadow_selectedlight->corona;
5554 r_shadow_bufferlight.coronasizescale = r_shadow_selectedlight->coronasizescale;
5555 r_shadow_bufferlight.ambientscale = r_shadow_selectedlight->ambientscale;
5556 r_shadow_bufferlight.diffusescale = r_shadow_selectedlight->diffusescale;
5557 r_shadow_bufferlight.specularscale = r_shadow_selectedlight->specularscale;
5558 r_shadow_bufferlight.flags = r_shadow_selectedlight->flags;
5561 void R_Shadow_EditLights_PasteInfo_f(void)
5563 if (!r_editlights.integer)
5565 Con_Print("Cannot paste light info when not in editing mode. Set r_editlights to 1.\n");
5568 if (!r_shadow_selectedlight)
5570 Con_Print("No selected light.\n");
5573 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);
5576 void R_Shadow_EditLights_Init(void)
5578 Cvar_RegisterVariable(&r_editlights);
5579 Cvar_RegisterVariable(&r_editlights_cursordistance);
5580 Cvar_RegisterVariable(&r_editlights_cursorpushback);
5581 Cvar_RegisterVariable(&r_editlights_cursorpushoff);
5582 Cvar_RegisterVariable(&r_editlights_cursorgrid);
5583 Cvar_RegisterVariable(&r_editlights_quakelightsizescale);
5584 Cmd_AddCommand("r_editlights_help", R_Shadow_EditLights_Help_f, "prints documentation on console commands and variables in rtlight editing system");
5585 Cmd_AddCommand("r_editlights_clear", R_Shadow_EditLights_Clear_f, "removes all world lights (let there be darkness!)");
5586 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)");
5587 Cmd_AddCommand("r_editlights_save", R_Shadow_EditLights_Save_f, "save .rtlights file for current level");
5588 Cmd_AddCommand("r_editlights_spawn", R_Shadow_EditLights_Spawn_f, "creates a light with default properties (let there be light!)");
5589 Cmd_AddCommand("r_editlights_edit", R_Shadow_EditLights_Edit_f, "changes a property on the selected light");
5590 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)");
5591 Cmd_AddCommand("r_editlights_remove", R_Shadow_EditLights_Remove_f, "remove selected light");
5592 Cmd_AddCommand("r_editlights_toggleshadow", R_Shadow_EditLights_ToggleShadow_f, "toggle on/off the shadow option on the selected light");
5593 Cmd_AddCommand("r_editlights_togglecorona", R_Shadow_EditLights_ToggleCorona_f, "toggle on/off the corona option on the selected light");
5594 Cmd_AddCommand("r_editlights_importlightentitiesfrommap", R_Shadow_EditLights_ImportLightEntitiesFromMap_f, "load lights from .ent file or map entities (ignoring .rtlights or .lights file)");
5595 Cmd_AddCommand("r_editlights_importlightsfile", R_Shadow_EditLights_ImportLightsFile_f, "load lights from .lights file (ignoring .rtlights or .ent files and map entities)");
5596 Cmd_AddCommand("r_editlights_copyinfo", R_Shadow_EditLights_CopyInfo_f, "store a copy of all properties (except origin) of the selected light");
5597 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)");
5603 =============================================================================
5607 =============================================================================
5610 void R_CompleteLightPoint(vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const vec3_t p, int dynamic)
5612 VectorClear(diffusecolor);
5613 VectorClear(diffusenormal);
5615 if (!r_fullbright.integer && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
5617 ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = r_refdef.scene.ambient * (2.0f / 128.0f);
5618 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
5621 VectorSet(ambientcolor, 1, 1, 1);
5628 for (i = 0;i < r_refdef.scene.numlights;i++)
5630 light = r_refdef.scene.lights[i];
5631 Matrix4x4_Transform(&light->matrix_worldtolight, p, v);
5632 f = 1 - VectorLength2(v);
5633 if (f > 0 && CL_Move(p, vec3_origin, vec3_origin, light->shadoworigin, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, true, false, NULL, false).fraction == 1)
5634 VectorMA(ambientcolor, f, light->currentcolor, ambientcolor);